I'm wondering if it would be useful/possible to run the compilation in a service worker that would intercept requests for *.ts and compile them in the worker?
I've seen an alternative approach, where the TS code is sent for compilation to a dedicated server - dismissed that idea as over engineered, but then I learned that the swc WASM package clocks in at over 5MB.
I've tried this before, with a service worker[1] that intercepts TS/X-ish requests, and directing them over to sucrase[2] to compile to JS, before being loaded by the browser. Unfortunately sucrase seems to be no longer maintained.
Now, I am all for it except the fact that I've heard that some people have actually recommended the wayland protocol + wasm to be a better alternative really.
And I personally feel like (I may be wrong) that at the end your proposal and the wayland proposal might be the same..
The problem with wayland protocol/your proposal is the fact that such things have already been tried (java applets) and they were insecure, and accessibility was a mess, so reverting back to it does feel like a massive chaos since javascript was created to solve that problem..
I am not a js advocate, honestly I wish that ephemeral running of apps cross platform becomes genuinely easy (in my mind nix-shell comes)
There is htmx which is nice too I guess but I think I still need some js to sprinkle in some more interactivity/animations.
Astro with htmx / islands architecture kinda feels the best, imagine using svelte/vue/react and htmx+golang in the same project..
does esm.sh/tsx send source to their servers? I was under the impression it uses a rust-based wasm compiler in the browser locally https://swc.rs/#features
Synchronous XHR is a really bad way to do this. The performance will be terrible for anything but the smallest module graphs.
But the TypeScript compiler API is synchronous, so there's a problem.
What you want to do is asynchronously walk the import graph, resolving import specifiers along the way with something like es-module-lexer or TypeScript's light parser, then when all the input files are collected, pass them through a compiler host to the compiler.
> But the TypeScript compiler API is synchronous, so there's a problem.
But it doesn't use DOM APIs, so you can run it in a worker without any issue. Monaco (the embeddable distribution of VSCode) does that.
The even bigger issue is that the TypeScript compiler is gigantic — like 10 MB, which is just a nonstarter for something you'd need to embed in every page of your site.
Sychronous XHR also seems a symptom here of compiling Typescript to CommonJS which as a very synchronous module system is also the wrong module system to choose for a browser application. All the modern browsers support ESM great and asynchronously load them just fine.
tsc's code is mostly the type-checker, you want to look for a "transpiler" here, so embedding either swc, esbuild, sucrase or the like to handle the process of converting for you. I've never heard of one written in C++ but that may exist.
If you are interested in TypeScript for the browser, you might also like --erasableSyntaxOnly option of typescript >5.8. The only tool needed for it is the typescript compiler itself, so toolchain is kept to a minimum.
Neat! I've been working on a custom element for running tests in the browser, and was thinking of wiring up swc to prevent having to compile the tests from ts before running them. This library seems like it would serve better than trying to maintain something myself!
If you like this and are interested in a less hacky way, I've also implemented it using a Service Worker[1] that intercepts and transpiles modules on-the-fly.
18 comments
[ 4.0 ms ] story [ 53.9 ms ] threadI've seen an alternative approach, where the TS code is sent for compilation to a dedicated server - dismissed that idea as over engineered, but then I learned that the swc WASM package clocks in at over 5MB.
I love the name BTW.
[1]: https://github.com/altbdoor/sucrase-build-iife
[2]: https://github.com/alangpierce/sucrase
[1] https://github.com/stagas/tssw
It is an accumulation of complexity that, for backwards compatibility, we get stuck with.
The browser should be simple.
If the focus just stayed on making wasm better for web development, folks can use any language they want and the API surface area can stay small.
And I personally feel like (I may be wrong) that at the end your proposal and the wayland proposal might be the same..
The problem with wayland protocol/your proposal is the fact that such things have already been tried (java applets) and they were insecure, and accessibility was a mess, so reverting back to it does feel like a massive chaos since javascript was created to solve that problem..
I am not a js advocate, honestly I wish that ephemeral running of apps cross platform becomes genuinely easy (in my mind nix-shell comes) There is htmx which is nice too I guess but I think I still need some js to sprinkle in some more interactivity/animations.
Astro with htmx / islands architecture kinda feels the best, imagine using svelte/vue/react and htmx+golang in the same project..
But the TypeScript compiler API is synchronous, so there's a problem.
What you want to do is asynchronously walk the import graph, resolving import specifiers along the way with something like es-module-lexer or TypeScript's light parser, then when all the input files are collected, pass them through a compiler host to the compiler.
This is what the Lit team's Playground Elements do, which compile files on a worker for embeddable interactive code samples: https://github.com/google/playground-elements
But it doesn't use DOM APIs, so you can run it in a worker without any issue. Monaco (the embeddable distribution of VSCode) does that.
The even bigger issue is that the TypeScript compiler is gigantic — like 10 MB, which is just a nonstarter for something you'd need to embed in every page of your site.
[1]: https://github.com/stagas/tssw
Seems tsc itself requires node, but surely an api that takes a ts file as a string and returns a ts file as a string should be possible?
[1]: https://github.com/stagas/tssw