An orange cat sitting inside a box, as cats do. This cat is now bundled for production.

In 2024, I wrote about learning the basics of Webpack when I realized it was a tool that I used almost daily without thinking about it.

Now, I’m working on a Firefox extension that is going to depend on a third-party library. How on earth do you get third-party packages into a Firefox extension?

The answer is, again, Webpack. But unlike with React-based projects, where Webpack is often invisibly part of the build and deploy process, we are going to have to manually configure Webpack ourselves for this extension.

The problem

I want to include third-party Javascript in my extension. As we learned from my previous post, it makes developers’ lives easier to be able to require or import external scripts, but the browser doesn’t know how to find those scripts on a filesystem. Or even how to access a filesystem. So we need to use Webpack to turn those external dependencies into internal code that the browser knows how to use.

Yes, this is overly simplified.

As a concrete example, my extension’s structure looks like this:

.
├── db.js
├── node_modules
├── package.json
├── package-lock.json
├── readme.md
├── index.js
└── webpack.config.js

Note that there are multiple .js files in the root of the extension, plus a node_modules folder. Any time I write import {thing} from 'thing' in my code, whether I’m talking about code I created or a module I installed, my local dev environment knows how to resolve those imports, but a browser environment wouldn’t – hence the need for a build tool like Webpack. (Note: this is overly simplified and I read Lea Verou’s writing on this topic and, much like the post below, it broke my brain.)

The footnote

There are a zillion other ways to get Javascript libraries working without a build system. I read about a number of them on Julia Evans’s blog, but the outcome of reading that blog post is I realized I just don’t know enough about Javascript to understand all these options. I’ve set up time with a senior engineer at work to learn more, which is exciting in a very nerdy way.

I can say for sure that one of the alternatives is, depending on how the module is written, “just stick it in a <script src> tag, which would be very simple except that Firefox extensions don’t use HTML.1

There are other options (including importing modules directly from CDNs??) but let’s assume for this project we just want to use webpack.

The solution: roll your own (simple) webpack config

First, we need a package.json file to define our dependencies and build tooling. Actually, as I write this, I don’t know for sure if this step is 100% necessary, but it makes things easier. I ran npm init from my extension’s base folder and a wizard walked me through creating a package.json. Super easy!

I then modified my package.json to look like this:

{
  "name": "linkedin-extension",
  "version": "1.0.0",
...
 "scripts": {
    "build": "webpack"
  },
  "author": "rachel kaufman",
  "devDependencies": {
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0"
  }
}

Now when we run npm i we should install two Webpack tools as dev dependencies, and when we run npm run build webpack will run.

We then define a webpack.config.js file:


const path = require("path");

module.exports = {
    entry: {
        whatever: "./whatever.js"
    },
    output: {
        path: path.resolve(__dirname, "addon"),
        filename: "[name]/index.js"
    },
    mode: 'none',
};

This defines an entrypoint of whatever.js, meaning when we run npm run build, Webpack will look at that code, resolve any imports in it recursively, and output new, bundled files to the addon directory. Specifically, to addon/whatever/index.js. We then refer to those built files instead of the source files when running or testing our extension.

This was surprisingly easy, thanks to MDN’s great docs.

What does the extension do? Can’t wait to tell you about it next time.

Further reading

Footnotes

  1. Okay, they do, but I’m talking about content scripts which allow us to load .js or .css