Skip to content

Publish an official wasip1 (WASI) build artifact of tsgo #63858

Open

Description

Request

Please consider publishing an official GOOS=wasip1 GOARCH=wasm build artifact of tsgo alongside the native platform binaries (npm @typescript/* platform packages / GitHub release assets).

Context

We embed JavaScript tooling in WebAssembly (WASI) environments and evaluated running the TypeScript 7 compiler there. Building from source works today with no patches:

GOOS=wasip1 GOARCH=wasm go build ./cmd/tsgo   # at tag typescript/v7.0.2, go1.26.4
  • One command, ~40s build, ~48.6 MB core module.
  • Runs under wasmtime (preview1): diagnostics are byte-identical to the native binary on our test projects, exit codes preserved.
  • Single-threaded as expected for this target (~12× native wall-clock in our samples — still practical for small/medium projects).
  • Known limitation we observed: wasm32's 4 GiB memory ceiling prices out very large programs (a type-fest-scale check needed ~6.6 GB natively).

Why an official artifact

The build is trivially reproducible, but an official artifact would give WASI/browser-adjacent consumers a supported, versioned binary instead of each project maintaining its own build pipeline, and would make regressions on this target visible to CI here rather than downstream.

Happy to share our verification receipts (diagnostic byte-comparisons vs the native binary) if useful.

Activity

  1. jakebailey commented on Jul 22, 2026

    @jakebailey
    Member

    What's the expectation? Just that you want a .wasm file to be on npm somewhere that's certainly easy enough, though since that's not a real platform, it'll have to be special cased. Not a big deal, esbuild does it.

    It would be cool if we could fall back to this package + Node's Wasi shim if the package is installed and no native binary exists, but last I checked, we crash Node's shims.

  2. calvinrp commented on Jul 22, 2026

    @calvinrp
    Author

    Concretely, two things would cover it:

    1. A versioned .wasm published per release. The esbuild-wasm shape you mention is exactly right: an npm package in the platform-package family (or a GitHub release asset; npm is more convenient for toolchain integration, but either works). Special-cased is OK. wasip1 consumers commonly expect that.
    2. The artifact built in your CI, even if nothing runs against it at first, so a change that breaks GOOS=wasip1 compilation shows up here instead of downstream.

    On the Node WASI-shim fallback: that would be a nice bonus, but I'd decouple it from this ask. Our hosts are real WASI runtimes (Wasmtime and browser-adjacent hosts), where the current build already runs cleanly: byte-identical diagnostics vs the native binary across our test projects, exit codes preserved. The Node shim crash could be a separate issue.

  3. calvinrp commented on Jul 22, 2026

    @calvinrp
    Author

    Followed up on the shim crash — two separate things were going on:

    The crash was a Node bug, already fixed. Node 20–22 segfault inside V8 when a wasm program grows memory past a few hundred MB (tsgo does that on any real project). Node 23 and 24 are clean — we ran real checks up to 3.5 GiB. So the fallback works today if it's gated on node >= 23: with returnOnExit: false and without passing the host env through (Go's wasip1 runtime derives cwd from $PWD), tsgo -p under node:wasi produces output diff-identical to the native binary. Happy to share the loader proof-of-concept and receipts.

    LSP mode hangs for a different, tsgo-side reason — filed as #63862 with a small fix.

  4. jakebailey commented on Jul 24, 2026

    @jakebailey
    Member

    One gotcha here; should that wasm bundle include all of our embedded artifacts? Or just use the same exe location stuff we currently do? I'm kinda unsure.

  5. calvinrp commented on Jul 24, 2026

    @calvinrp
    Author

    I'd just embed. That's what the default GOOS=wasip1 go build does anyway, and it's the build we tested — output matched native with zero lib-path setup, under both wasmtime and node:wasi. There isn't really a "next to the exe" in wasm anyway (no real executable path), so relative lookup would turn into custom setup for every host. The libs only add a few MB to a ~49 MB module, and you get one self-contained file that runs anywhere.

  6. jakebailey commented on Jul 24, 2026

    @jakebailey
    Member

    Except that it's useless for editor use due to the paths getting exposed over the wire and then pointing nowhere, and error messages lying about their contents.

    I have success in providing argv0 in hosts, but not all hosts let one do that.

  7. calvinrp commented on Jul 24, 2026

    @calvinrp
    Author

    Fair, our LSP testing only got as far as hover, so we never hit the lib-path problem. Could it be both? Embed by default so the CLI is one file that works anywhere, plus a --lib-dir flag/env for editor hosts pointing at the on-disk libs the package ships anyway. A flag or env var is also just more explicit than routing the lib location through argv0, and doesn't depend on the host exposing it.

  8. jakebailey commented on Jul 24, 2026

    @jakebailey
    Member

    Not sure, I think it will also depend on what we do in the playground.

  9. trobertson-graymatterllc commented on Aug 24, 2026

    @trobertson-graymatterllc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

InfrastructureIssue relates to TypeScript team infrastructureNeeds InvestigationThis issue needs a team member to investigate its status.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions