Search code examples
firefox-addon-webextensionsweb-ext

Different development and build configuration with web-ext


I am working with a browser extension project and want to have a different URL used in background.js during development time and build time. I want to do this without having to remember to change the code between development and build. With a server project I'd simply use dotenv/environment variables but that's not available to extensions which effectively run client side.

In background.js I have a fetch using this api_base_url (we develop the API too);

...
const api_base_url = 'http://127.0.0.1:8000/v1/'
...

Before I build (web-ext build) I have to manually that to something like;

...
const api_base_url = 'http://a.domain.com/v1/'
...

Ideally it would be something like;

...
const api_base_url = ENV['API_BASE_URL']
...

and I'd have a .env in local dev of;

API_BASE_URL='http://127.0.0.1:8000/v1/'

and .env.production (or .env.build) of;

API_BASE_URL='http://a.domain.com/v1/'

This is also a problem in manifest.json where I need to whitelist the different URLs in permissions e.g.

"permissions": [
    "storage",
    "tabs",
    "https://a.domain.com/v1/*",
    "http://127.0.0.1:8000/v1/*"
  ]

This isn't a run-time per-user option so browser.storage and options.js isn't what we're looking for.


Solution

  • I have figured this out but the basic answer is to add webpack and use dotenv-webpack for entry files like background.js and copy-webpack-plugin for non-entry files like manifest.json. These plugins will replace string occurrences of process.env.YOUR_VARIABLE_NAME with the value from process.env.YOUR_VARIABLE_NAME.

    This literally happens and it took me a few tries to understand it.

    // .env
    API_BASE_URL='http://127.0.0.1:8000/v1/'
    
    // ./background.js
    const api_base_url = process.env.API_BASE_URL
    
    // manifest.json
    "permissions": [
      "tabs",
      "process.env.API_BASE_URL*"
    ],
    
    // webpack => ./dist/main.js
    const api_base_url = 'http://127.0.0.1:8000/v1/'
    
    // webpack => ./dist/manifest.json
    "permissions": [
      "tabs",
      "http://127.0.0.1:8000/v1/*"
    ],
    

    Here is the webpack config;

    // ./webpack.config.js
    const CopyPlugin = require('copy-webpack-plugin')
    const DotenvPlugin = require('dotenv-webpack')
    module.exports = (env) => {
      const dotenvPath = __dirname + '/.env.' + env
    
      const replaceWithProcessEnv = (content) => {
        for (var key in require('dotenv').config({ path: dotenvPath }).parsed) {
          content = content.replace(new RegExp('process.env.' + key, 'g'), process.env[key])
        }
        return content
      }
    
      return {
        plugins: [
          new DotenvPlugin(
            {
              path: dotenvPath,
              safe: true
            }
          ),
          new CopyPlugin(
            [
              {
                from: 'src/manifest.json',
                transform(content) {
                  return replaceWithProcessEnv(content.toString())
                }
              }
            ]
          )
        ]
      }
    }
    

    I have made a complete working example here; https://github.com/paulmwatson/web-ext-environments