Chrome Extensions with rollup

14 Sep 2024

Yesterday I posted about using esbuild to bundle a Chrome extension. I hit some roadblocks with that approached, and figured I had gone far enough to warrant a different approach. I decided to try rollup instead.

This is how I did it.

Part 1: Rollup

If you are starting from the previous post:

npm uninstall esbuild minimist tsx ws

Then install the necessary packages and scripts:

npm install rollup \
    rollup-plugin-chrome-extension \
    @rollup/plugin-typescript \
    @rollup/plugin-node-resolve \
    @rollup/plugin-commonjs --save-dev

npx npm-add-script -f -k "build" -v "rollup -c"
npx npm-add-script -f -k "watch" -v "rollup -c -w"

Then, the magic:

  • import commonjs from "@rollup/plugin-commonjs";
    import resolve from "@rollup/plugin-node-resolve";
    import typescript from "@rollup/plugin-typescript";
    import fs from "node:fs/promises";
    import {
      chromeExtension,
      simpleReloader,
    } from "rollup-plugin-chrome-extension";
    
    export default {
      input: "src/manifest.json",
      output: {
        dir: "dist",
        format: "esm",
      },
      plugins: [
        {
          // from https://github.com/jacksteamdev/rollup-plugin-empty-dir - it doesn't like Rollup 4
          name: "empty-dir",
          async generateBundle({ dir }) {
            if (dir) {
              try {
                await fs.rm(dir, { recursive: true });
              } catch {
                /* empty */
              }
            }
          },
        },
        chromeExtension(),
        simpleReloader(),
        typescript(),
        resolve(),
        commonjs(),
      ],
    };
    
  • {
      "manifest_version": 3,
      "background": {
        "service_worker": "background.ts",
        "type": "module"
      },
      "content_scripts": [
        {
          "js": ["content.ts"],
          "matches": ["https://www.dndbeyond.com/*"]
        }
      ],
      "permissions": ["storage"]
    }
    

Pretty wild. With a single Rollup plugin, we can do everything we were doing manually in esbuild and more. (Not to say that there isn’t a plugin for esbuild, but I didn’t find it. I may not have looked hard enough.)

Better yet, everything is then driven off of our manifest.json file. Typescript files in the Manifest! Amazing.

This isn’t a great education about working with Rollup directly, but it’s certainly fun to see the breadth of the community around the tool. And, this brief comparison shows why tools like Vite use both - they each have their strengths.