Something went wrong. Try again.
Something went wrong. Try again.
README.md
Service worker #
A module service worker that strips .ts/.mts module requests on the way to the page, so the page imports TypeScript with no build step.
pnpm build # if build/*.wasm is missing
node examples/service-worker/serve.mjs # then open http://localhost:8000/examples/service-worker/
The page shows a greeting and a table with the cache status of each module.
How it works #
- Matching. The worker handles same-origin
GETrequests whose path ends in.tsor.mts. It matches on the extension, not the response'sContent-Type, because servers label TypeScript inconsistently (video/mp2tis common). It always responds withtext/javascript, because module scripts need a JavaScript MIME type. - Mode. Every module goes through
downlevelmode, so enums, namespaces, parameter properties,import =andexport =all convert without a scan or a retry. Lines match the source everywhere, and columns match outside converted constructs, so DevTools positions under the.tsURL need no source map. The cost is that the worker loads the larger engine: 17,844 B gzip, compared with 12,610 B for erase mode. - Streaming. Each upstream body streams through
transform, and the page receives pieces as they're produced. - Errors. Downlevel mode leaves every construct it reports in place: a
<T>cast before an ASI-sensitivereturn/throw/yield, orimport x =/export =in a file with ESM syntax. None of them is valid JavaScript, so the browser throws its ownSyntaxErrorat that line, for exampleUnexpected token '<'. The worker passesonErrorso that the generator doesn't throw mid-stream, which would make the import fail as a network error. It also logs the offset to the worker console. A result with errors is not cached. - Concurrency. The browser requests a module's imports all at once, and each miss streams on its own engine instance from typestrip's pool. The worker drains each upstream body as fast as it arrives, not as fast as the page reads it, so the instance goes back to the pool and the cache write happens even if the page stops reading.
- Caching. Stripped output goes into Cache Storage together with the upstream
ETag. On the next request, the worker sendsIf-None-Matchwithcache: "no-store". A304serves the cached copy without stripping again. If the network fails, the worker falls back to the cached copy. Responses without anETagare stripped every time. To clear the cache after rebuilding the engine, bumpCACHEinsw.js.
Limits #
- Import specifiers need the extension:
import "./greet.ts"works, but extensionless./greetdoes not resolve. Bare specifiers need an import map. - The worker controls the page only after it activates.
index.htmlwaits forcontrollerchangebefore it importsapp/main.ts. - This example was tested in Chromium. Firefox and Safari support for module service workers (
register(url, { type: "module" })) is untested here. For a host without module service workers, bundlesw.jsinto a classic script.