inline-worker-plugin.mjs

scripts/inline-worker-plugin.mjs · raw · all examples · site home

Exports: inlineWorkerPlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import esbuild from "esbuild";
import path from "node:path";

// `import Worker from "./file?worker&inline"` bundles file.ts as its own ESM
// bundle and exports a Worker subclass that runs it from a blob URL, so the
// page needs no separate worker files. `import code from "./file?module&inline"`
// bundles it the same way and exports its code as a string (for a blob URL
// that workers import). `define` is passed through to the bundle
// (RADIX_STATIC); `minify` for the production build.
export function inlineWorkerPlugin({ minify = false, define = {} } = {}) {
  return {
    name: "inline-worker",
    setup(build) {
      build.onResolve({ filter: /\?(worker|module)&inline$/ }, (args) => ({
        path: path.resolve(args.resolveDir, args.path.replace(/\?(worker|module)&inline$/, "")),
        namespace: "inline-worker",
        pluginData: { kind: args.path.match(/\?(worker|module)&inline$/)[1] },
      }));

      build.onLoad({ filter: /.*/, namespace: "inline-worker" }, async (args) => {
        const result = await esbuild.build({
          entryPoints: [args.path],
          bundle: true,
          format: "esm",
          platform: "browser",
          minify,
          define,
          write: false,
          metafile: true,
        });
        const code = result.outputFiles[0].text;
        const watchFiles = Object.keys(result.metafile.inputs);
        if (args.pluginData.kind === "module") {
          return { contents: `export default ${JSON.stringify(code)};`, loader: "js", watchFiles };
        }

        return {
          contents: [
            `const workerCode = ${JSON.stringify(code)};`,
            `const workerUrl = URL.createObjectURL(new Blob([workerCode], { type: "text/javascript" }));`,
            "export default class InlineWorker extends Worker {",
            "  constructor(options = {}) {",
            '    super(workerUrl, { ...options, type: "module" });',
            "  }",
            "}",
          ].join("\n"),
          loader: "js",
          watchFiles,
        };
      });
    },
  };
}