Found while integrating `@schnsrw/docx-js-editor@1.0.0` into a downstream Vite consumer (Casual Drive). The published `dist/format-converter-HT2IRSL3.mjs` contains:
```js
new Worker(new URL("./format-converter.worker.ts", import.meta.url), { type: "module" })
```
but the `.ts` source isn't shipped in `dist/` — only the compiled `.mjs`. Vite's `vite:worker-import-meta-url` plugin errors at build time:
```
Could not resolve entry module
"node_modules/.../dist/format-converter.worker.ts"
file: node_modules/.../dist/format-converter-HT2IRSL3.mjs
```
The bug exists for any consumer whose bundler honours the `new Worker(new URL(...), import.meta.url)` pattern at build time (Vite, modern webpack with worker-plugin, esbuild's bundler). The format-converter is used for odt / md / txt import paths; consumers that don't trigger those still can't build.
Drive workaround (shipped as a stop-gap)
Vite `transform` hook that rewrites the worker construction to a no-op object:
```ts
{
name: "casual-drive-sdk-worker-shim",
enforce: "pre",
transform(code, id) {
if (!id.includes("@schnsrw/docx-js-editor")) return null;
if (!code.includes("format-converter.worker.ts")) return null;
return code.replace(
/new Worker(new URL(["']./format-converter.worker.ts["'],import.meta.url)\s*,\s*{[^}]*})/g,
"({postMessage(){},addEventListener(){},removeEventListener(){},terminate(){},onmessage:null,onerror:null,onmessageerror:null})"
);
},
}
```
(see CasualOffice/doc-hub@21206da). Works for Drive because the converter is unreachable from the in-Drive embed flow, but it's a downstream hack, not a fix.
Suggested fix
A few patterns that would work in tsup:
-
Pre-build the worker as a sibling artifact. Add a second `defineConfig` entry that compiles `src/lib/format-converter.worker.ts` into `dist/format-converter.worker.js`, then rewrite the consumer-facing URL to reference the compiled file (e.g. via a custom esbuild plugin that swaps `.ts` for `.js` in worker URLs). Adds an `exports` entry for `./format-converter.worker` so the package.json describes it.
-
Inline as a Blob URL. Read the worker source at build time, embed as a constant in the main bundle, instantiate `Worker(URL.createObjectURL(new Blob([source], { type: "application/javascript" })))`. Most portable but bloats the main bundle.
-
`?worker&inline` Vite-style import. Only works for Vite consumers; doesn't help the package's headless-Node or webpack consumers.
(1) is the cleanest. Happy to send a PR if you'd like.
Reproduce
```bash
mkdir bug-repro && cd bug-repro
npm init -y
npm i vite @vitejs/plugin-react react react-dom @schnsrw/docx-js-editor@1.0.0
minimal src/main.tsx that imports anything from @schnsrw/docx-js-editor
npx vite build
```
Found while integrating `@schnsrw/docx-js-editor@1.0.0` into a downstream Vite consumer (Casual Drive). The published `dist/format-converter-HT2IRSL3.mjs` contains:
```js
new Worker(new URL("./format-converter.worker.ts", import.meta.url), { type: "module" })
```
but the `.ts` source isn't shipped in `dist/` — only the compiled `.mjs`. Vite's `vite:worker-import-meta-url` plugin errors at build time:
```
Could not resolve entry module
"node_modules/.../dist/format-converter.worker.ts"
file: node_modules/.../dist/format-converter-HT2IRSL3.mjs
```
The bug exists for any consumer whose bundler honours the `new Worker(new URL(...), import.meta.url)` pattern at build time (Vite, modern webpack with worker-plugin, esbuild's bundler). The format-converter is used for odt / md / txt import paths; consumers that don't trigger those still can't build.
Drive workaround (shipped as a stop-gap)
Vite `transform` hook that rewrites the worker construction to a no-op object:
```ts
{
name: "casual-drive-sdk-worker-shim",
enforce: "pre",
transform(code, id) {
if (!id.includes("@schnsrw/docx-js-editor")) return null;
if (!code.includes("format-converter.worker.ts")) return null;
return code.replace(
/new Worker(new URL(["']./format-converter.worker.ts["'],import.meta.url)\s*,\s*{[^}]*})/g,
"({postMessage(){},addEventListener(){},removeEventListener(){},terminate(){},onmessage:null,onerror:null,onmessageerror:null})"
);
},
}
```
(see CasualOffice/doc-hub@21206da). Works for Drive because the converter is unreachable from the in-Drive embed flow, but it's a downstream hack, not a fix.
Suggested fix
A few patterns that would work in tsup:
Pre-build the worker as a sibling artifact. Add a second `defineConfig` entry that compiles `src/lib/format-converter.worker.ts` into `dist/format-converter.worker.js`, then rewrite the consumer-facing URL to reference the compiled file (e.g. via a custom esbuild plugin that swaps `.ts` for `.js` in worker URLs). Adds an `exports` entry for `./format-converter.worker` so the package.json describes it.
Inline as a Blob URL. Read the worker source at build time, embed as a constant in the main bundle, instantiate `Worker(URL.createObjectURL(new Blob([source], { type: "application/javascript" })))`. Most portable but bloats the main bundle.
`?worker&inline` Vite-style import. Only works for Vite consumers; doesn't help the package's headless-Node or webpack consumers.
(1) is the cleanest. Happy to send a PR if you'd like.
Reproduce
```bash
mkdir bug-repro && cd bug-repro
npm init -y
npm i vite @vitejs/plugin-react react react-dom @schnsrw/docx-js-editor@1.0.0
minimal src/main.tsx that imports anything from @schnsrw/docx-js-editor
npx vite build
```