A tsdown plugin for handling Web Workers and SharedWorkers. Supports both ?worker query imports and the standard ES modules new URL() pattern.
npm install tsdown-plugin-worker
# or
yarn add tsdown-plugin-worker
# or
bun add tsdown-plugin-workertsdown.config.ts
import { defineConfig } from "tsdown";
import workerPlugins from "tsdown-plugin-worker";
export default defineConfig({
plugins: [workerPlugins({ format: "es" })],
});tsconfig.json
{
"compilerOptions": {
"types": ["tsdown-plugin-worker/types"]
}
}Import a worker file using the ?worker query suffix:
import MyWorker from "./worker.ts?worker";
const worker = new MyWorker();
worker.postMessage("Hello");For SharedWorkers, use the ?sharedworker query:
import MySharedWorker from "./worker.ts?sharedworker";
const sharedWorker = new MySharedWorker();
sharedWorker.port.postMessage("Hello");Bundle worker code inline as a Blob (no separate file):
import InlineWorker from "./worker.ts?worker&inline";
const worker = new InlineWorker();
worker.postMessage("Hello");Use the standard browser pattern with automatic bundling:
const worker = new Worker(new URL("./worker.ts", import.meta.url));const sharedWorker = new SharedWorker(new URL("./worker.ts", import.meta.url));Pass worker options when using new URL():
const worker = new Worker(new URL("./worker.ts", import.meta.url), {
type: "module",
});Workers can import other modules - they'll be bundled automatically:
// worker.ts
import { processData } from "./utils";
self.onmessage = (event) => {
const result = processData(event.data);
self.postMessage(result);
};// main.ts
import MyWorker from "./worker.ts?worker";
const worker = new MyWorker();You can import workers from packages (including ?worker&inline):
import EditorWorker from "monaco-editor/esm/vs/editor/editor.worker.js?worker";
// or
import InlineEditorWorker from "monaco-editor/esm/vs/editor/editor.worker.js?worker&inline";
const worker = new EditorWorker();Warning
Package worker imports can cause dependencies to be internalized into your build output. If you expected those dependencies to stay external for downstream bundlers, review your output carefully before publishing libraries.
Default format. Workers are loaded as ES modules:
workerPlugins({ format: "es" });For IIFE output with classic script workers:
workerPlugins({ format: "iife" });For fine-grained control, use individual plugins:
import {
workerQueryPlugin, // Handles ?worker and ?sharedworker imports
workerNewUrlPlugin, // Handles new URL() patterns
workerPostPlugin, // Post-processing for IIFE format
} from "tsdown-plugin-worker";
export default defineConfig({
plugins: [
workerQueryPlugin({ format: "iife" }),
workerNewUrlPlugin({ format: "iife" }),
workerPostPlugin({ format: "iife" }),
],
});interface WorkerPluginOptions {
format: "es" | "iife"; // Output format
rolldownOptions?: RolldownOptions; // Custom rolldown options for worker bundling
}