Skip to content

Add wasip1 support, enabling CLI, API, browser, sync/async - #64174

Draft
Jake Bailey (jakebailey) wants to merge 7 commits into
microsoft:mainfrom
jakebailey:wasip1
Draft

Add wasip1 support, enabling CLI, API, browser, sync/async#64174
Jake Bailey (jakebailey) wants to merge 7 commits into
microsoft:mainfrom
jakebailey:wasip1

Conversation

@jakebailey

@jakebailey Jake Bailey (jakebailey) commented Sep 4, 2026

Copy link
Copy Markdown
Member

Fixes #63858
Fixes #63862
For #63813

This is still a bit experimental, but this creates a wasip1 tsc.wasm build. This build works as a CLI, so one can run it anywhere and get the CLI, LSP server, etc. But, one can also instantiate the module and give it to the new TypeScript IPC-based API (including in the browser!) and get sync/async API access. This works similarly (though not the same) to David Sherret's ts-ast-viewer tsgo prototype. The dual-nature of this is enabled by some Wasm export + binaryen trickery to make one blob that can do both things.

In a perfect world, we'd be able to do wasip3 or something, component model, yadda yadda, but the main Go compiler cannot do that yet.

I think for now, this works alright. I think I'd also want to slap a "no warranty" label on this for now until we can get Wasm a bit more settled.

Some interesting tidbits:

  • This all is validated in playwright. Since we use node:test, I had copilot write some shims for those APIs to make it work. Smarter would be to use vitest in browser mode, I suspect. But this works and runs all but 20 tests succesfully.
  • Since this is wasip1, the host needs to provide that. For the browser, someone has to provide it; I used copilot to put together the absolute minimum wasi shim to make Go happy and that's included.
  • If the wasip1 package is installed and the native host OS does not have a build, the tsc CLI will fall back to using Node's wasi support, allowing "unsupported" platforms to work. Perhaps this is overkill.

TODO:

  • Figure out what to do about bundled files (lib.d.ts, localizations)
  • ???

Add an injectable synchronous transport and a browser-conditioned client for
the TypeScript API. Provide a Go WebAssembly reactor backed by an in-memory
filesystem and exercise it through the compiler and checker APIs.

Publish the reactor and its transport separately as @typescript/api-wasm,
with release-versioned builds and ordered npm publishing. Keep the main
TypeScript package free of the WebAssembly binary and verify its browser
module graph with an esbuild regression test.
Reuse the existing async and sync API suites in Playwright with narrow browser shims and explicit host-only exclusions.

Add WASI scheduler polling and callback-backed output writes so WasmTransport preserves native filesystem behavior.
Do not clear filesystem callbacks configured directly on a transport when the API is constructed without its own filesystem.

Assert that the browser harness accounts for all 669 API tests and cover WASM emit callbacks through the public transport setup.
Keep an active transport's filesystem callback intact when a second transport fails to create a session on the same reactor instance.
Close a newly created reactor session when filesystem callback attachment fails so the instance remains reusable.
Build the compiler, language server, and in-process API from one WASI module. Add the Node fallback, platform-specific runtime behavior, and release packaging for the unified artifact.
Return io.EOF when WASI stdin closes instead of triggering repeated
empty reads. Cover the command lifecycle in the unified module test.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

WASI LSP stdin busy-spins while idle, and process-backed API shutdown can hang during manually batched initialization.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds experimental WASI support for the TypeScript CLI and synchronous/asynchronous APIs across Node.js and browsers.

Changes:

  • Adds a dual CLI/reactor tsc.wasm build and minimal WASI host.
  • Introduces injectable API transports and browser-compatible clients.
  • Adds packaging, publishing, CI, and integration-test coverage.
File summaries
File Description
tsc/internal/ipc/timing.go Exposes server timing collection.
tsc/internal/api/wasmreactor/reactor.go Implements the in-process API reactor.
tsc/internal/api/wasmreactor/reactor_test.go Tests reactor requests and files.
tsc/cmd/tsc/wasmapi_wasip1.go Defines the WebAssembly reactor ABI.
tsc/cmd/tsc/sys.go Uses platform-aware working-directory lookup.
tsc/cmd/tsc/notifycontext.go Provides native signal handling.
tsc/cmd/tsc/notifycontext_wasip1.go Disables unsupported WASI signals.
tsc/cmd/tsc/main.go Uses platform-specific notification contexts.
tsc/cmd/tsc/lsp.go Makes LSP dependencies WASI-compatible.
tsc/cmd/tsc/lsp_stdin.go Defines native LSP stdin.
tsc/cmd/tsc/lsp_stdin_wasip1.go Adds WASI stdin handling.
tsc/cmd/tsc/lsp_process.go Defines native process integrations.
tsc/cmd/tsc/lsp_process_wasip1.go Disables unavailable WASI process features.
tsc/cmd/tsc/currentdirectory.go Defines native cwd lookup.
tsc/cmd/tsc/currentdirectory_wasip1.go Derives WASI cwd from PWD.
tsc/cmd/tsc/api.go Uses portable cwd and signal helpers.
tools/pipelines/typescript-publish.yml Publishes the WASI npm artifact.
packages/typescript/test/version.test.ts Tests CLI WASI fallback.
packages/typescript/test/sync/wasm.test.ts Tests CLI and API WebAssembly execution.
packages/typescript/test/sync/transport.test.ts Tests synchronous injected transports.
packages/typescript/test/encoder.test.ts Tests portable base64 encoding.
packages/typescript/test/browser/wasm.test.ts Tests WebAssembly APIs in Chromium.
packages/typescript/test/browser/syncAPI.ts Adapts sync API browser tests.
packages/typescript/test/browser/suite.test.ts Runs API suites in Chromium.
packages/typescript/test/browser/processShim.ts Provides browser process/timer shims.
packages/typescript/test/browser/harness.ts Implements the browser test harness.
packages/typescript/test/browser/bundle.test.ts Verifies browser-safe bundles.
packages/typescript/test/browser/asyncAPI.ts Adapts async API browser tests.
packages/typescript/test/browser/apiWrapper.ts Manages browser reactors and filesystem mirroring.
packages/typescript/test/async/transport.test.ts Tests asynchronous transport behavior.
packages/typescript/src/api/sync/transportClient.ts Implements sync protocol-over-transport.
packages/typescript/src/api/sync/transport.ts Defines the sync transport contract.
packages/typescript/src/api/sync/client.ts Supports injected sync transports.
packages/typescript/src/api/sync/browserClient.ts Adds the browser sync client.
packages/typescript/src/api/sync/api.ts Routes generated sync API through browser-aware clients.
packages/typescript/src/api/options.ts Adds transport-based API options.
packages/typescript/src/api/node/wtf8.ts Removes the Node buffer dependency.
packages/typescript/src/api/node/encoder.ts Adds portable base64 encoding.
packages/typescript/src/api/async/transportClient.ts Implements async protocol batching and lifecycle.
packages/typescript/src/api/async/transport.ts Defines the async transport contract.
packages/typescript/src/api/async/client.ts Supports injected async transports.
packages/typescript/src/api/async/browserClient.ts Adds the browser async client.
packages/typescript/src/api/async/api.ts Selects browser-aware clients and adjusts closing.
packages/typescript/package.json Exports transports and browser clients.
packages/typescript/lib/tsc.js Falls back to WASI when native binaries are unavailable.
packages/typescript/lib/getExePath.js Resolves the WASI package artifact.
packages/typescript/lib/getExePath.d.ts Declares WASI path resolution.
packages/typescript-wasip1-wasm/tsconfig.json Configures the WASI helper package.
packages/typescript-wasip1-wasm/src/wasmURL.ts Exposes the packaged module URL.
packages/typescript-wasip1-wasm/src/wasmURL.source.ts Exposes the source-build module URL.
packages/typescript-wasip1-wasm/src/wasi.ts Implements the browser WASI host.
packages/typescript-wasip1-wasm/src/index.ts Implements and exports WasmTransport.
packages/typescript-wasip1-wasm/README.md Documents CLI and API usage.
packages/typescript-wasip1-wasm/package.json Defines the WASI npm package.
package.json Adds Binaryen tooling.
package-lock.json Locks new packages and workspace metadata.
Herebyfile.mjs Builds, patches, tests, and packages WebAssembly.
.github/workflows/ci.yml Runs Chromium API tests in CI.
Review details
  • Files reviewed: 56/58 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +19 to +22
if err != syscall.EAGAIN {
return n, err
}
runtime.Gosched()
Comment on lines +395 to +399
if (this.initializing && !this.initialized) {
const initializing = this.initializing;
await this.client.close();
await initializing.catch(() => {});
this.sourceFileCache.clear();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Milestone Bug PRs that fix a bug with a specific milestone

Projects

None yet

2 participants