A code, bundle, pack workflow for webextension projects

Till now we have been working with a bare-minimum setup for building webextensions. A lot of the tasks we have been doing can be automated. In this post, we will learn how to use bash scripts in our workflow to automate several repetitive tasks and chores.


Grab this repo and figure out how the project has been set up.

The tools

git, node, npm and a code editor#

Ensure that you have all these available on your system.


standard is a zero-config linter and style checker for javascript. It integrates with your code editor and shows red squiggly lines in the editor that distract, irritate, and burn your eyes when you make a mistake. This linter will:

  • run straight out of the box
  • enforce consistent coding style across the project
  • slap you for oversights such as reassigning to a const variable

Install the standard plugin for your editor.
Or run the linter using npx standard and fix the errors manually.


A bundler allows the use of modern language features and tools for web application development. A bundler will:

  • compile our sass
  • inline our imports
  • use babel to transpile javascript to support older browsers

… and a lot more


web-ext is another tool that helps to test and pack webextensions. This will:

  • find errors in the project (like an invalid manifest)
  • load extensions into a browser for testing in a single command
  • pack the extension for publishing

The setup

new project structure#

├── artifacts           # archives for publishing
├── dist                # bundled project
├── node_modules
├── package.json
├── package-lock.json
├── README.md
├── scripts             # build scripts
├── src
└── test


The dev process will require two processes running in parallel. We need parcel to watch the src/ directory and build the project on change, and web-ext to watch dist/ and reload the extension on changes.

The dev process explained using unicons The dev process explained using Unicons

This can be done very easily by a bash script. Running npm run dev executes this script.

#!/usr/bin/env bash

rm -rf dist/
mkdir dist

cp -r src/manifest.json src/icons dist

parcel watch src/popup/index.html src/background/index.html --out-dir dist/ &

web-ext run -s dist/ &

wait $parcelProcess $webextProcess

The extension we are building contains just two entrypoints (a browser_action and a background script). The same is reflected in the script above. Two entrypoints are provided to the parcel command in the script. If your project uses different entrypoints or has different static assets, the script will require some modifications.


Running npm run build outputs a webextension ready for publishing. The packed webextension and zipped source code are put in artifacts/.

#!/usr/bin/env bash

rm -rf dist/ artifacts/
mkdir dist artifacts

cp -r src/manifest.json src/icons dist

parcel build src/popup/index.html src/background/index.html --out-dir dist/  --no-source-maps 

web-ext lint -s dist/

if [ $linterReturnCode -ne 0 ]; then
  exit $retVal

web-ext build -s dist/ -a artifacts/

git archive -o artifacts/$npm_package_name-$npm_package_version-source.zip HEAD

Hopefully, you can take some ideas from my setup and incorporate them into your own. Happy coding!