Repository navigation
feat(browser): download toolchains before the build boundary and expose prefetch - #91
Merged
JacobLinCool merged 2 commits intoOct 5, 2026
Conversation
A first browser build downloads its toolchain inside the compiler request, so on a slow or filtered network the whole C/C++ build boundary (60 s) can go to the 27 MB Clang download; the timeout then recycles the Worker and the next build starts the download over. `browserToolchainAssetPaths` (core) lists the assets one compile and run fetches per language, and `prefetchBrowserToolchain` (browser) downloads them through the same digest-addressed URLs the Workers request, with progress, abort and byte-length checks. A host can start it as soon as it knows the language; later builds then read the bytes from the HTTP or toolchain cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BrowserCompiler.build now acquires the pinned toolchain assets for the project's language, target, optimization and admitted libc++ PCH through prefetchBrowserToolchain before posting the build request, so the download no longer counts against the compiler request timeout. Completed downloads live in the HTTP (or toolchain) cache, so a Worker recycled by a timeout or cancel reuses them instead of starting over. Each profile is acquired once per compiler; cancel, restart and dispose abort an in-flight download, and progress is reported as `loading-toolchain`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TakalaWang
added a commit
to NOJV-TW/NOJV
that referenced
this pull request
Oct 5, 2026
wasm-oj/forge#91 shipped in @wasm-oj/browser 0.2.3: prefetchBrowserToolchain fetches exactly the assets a build needs at the Workers' URLs, and the compiler now downloads a build's toolchain before its build boundary. Drop NOJV's own asset selection and download loop and keep only the per-language dedup, retries and progress fan-out around the upstream helper (C++ asks for the admitted libc++ PCH). The lockfile change is limited to @wasm-oj/browser, core and contracts; toolchain packages stay on 0.2.0 and keep contracts 0.2.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TakalaWang
added a commit
to NOJV-TW/NOJV
that referenced
this pull request
Oct 5, 2026
* feat(web): preload the browser compiler when the editor opens A first in-browser Test downloaded its toolchain inside WASM-OJ's 60 s build boundary, so on a slow exam network it failed with "Failed to fetch" or a boundary timeout, and every retry started the download over. - Opening the editor or switching language preloads that language's pinned toolchain assets at the Workers' digest-addressed URLs, with progress on the Test button; Test waits for the preload and reports a failed download (after two retries) without building or pointing to Submit. - C++ sources that include <bits/stdc++.h> (and ship no copy of it) get WASM-OJ's admitted libc++ PCH header, cutting warm compiles by ~40%; other sources never get forced standard headers. - Build-boundary timeouts, toolchain download failures and missing cross-origin isolation add a localized hint above the engine message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(decisions): link JDG-15's preload and PCH rules to #639 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(web): preload through WASM-OJ 0.2.3's prefetchBrowserToolchain wasm-oj/forge#91 shipped in @wasm-oj/browser 0.2.3: prefetchBrowserToolchain fetches exactly the assets a build needs at the Workers' URLs, and the compiler now downloads a build's toolchain before its build boundary. Drop NOJV's own asset selection and download loop and keep only the per-language dedup, retries and progress fan-out around the upstream helper (C++ asks for the admitted libc++ PCH). The lockfile change is limited to @wasm-oj/browser, core and contracts; toolchain packages stay on 0.2.0 and keep contracts 0.2.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A first browser build downloads its toolchain inside the compiler request, so the download counts against the build boundary (
CLANG_BUILD_CONTROL_TIMEOUT_MS= 60 s for C/C++). On a slow or filtered network the 27 MB Clang WebC alone can use the whole boundary. The timeout then recycles the compiler Worker, and nothing is persisted until a download completes, so the next build starts the download over and fails the same way.We hit this in production during an exam in a computer lab (filtered network, ~50 students starting at once). Students saw
Compiler request exceeded the 60000 ms browser boundary.orFailed to fetchfor trivially small programs, while server judging of the same code was fine.createBrowserEnginewarm-up does not help today: it only starts the Workers and fetches no toolchain bytes.Change
1.
browserToolchainAssetPaths(selection)in@wasm-oj/core(src/core/toolchains.ts). It lists the pinned assets one compile and run fetches per language:libcxxPrecompiledHeader: true. This matchesfindPrecompiledHeader.2.
prefetchBrowserToolchain(sources, { language, target?, optimization?, libcxxPrecompiledHeader?, signal?, onProgress? })in@wasm-oj/browser(src/runtime/toolchain-prefetch.ts).browserToolchainAssetUrl. These are the same digest-addressed URLs the compiler, runner and stage Workers request, so the bytes land in the HTTP cache, or in the toolchain cache whenregisterToolchainCache()controls the page.signal.3.
BrowserCompiler.build()acquires the toolchain before posting the build request (src/runtime/compiler-client.ts):cancel()reuses completed downloads from the cache instead of starting over.clearToolchainCache()resets this.cancel(),restart()anddispose()abort an in-flight download. A failed download rejects the build without crossing the Worker boundary, and the next build retries.onProgressasloading-toolchain.Docs:
docs/integration-guide.mdhas a "Prefetching a toolchain" section. Hosts should serve toolchain assets with a cacheableCache-Control, since they are immutable per digest; otherwise Workers download them a second time.Verification
src/core/toolchains.test.ts: per-language selection, the PCH only for C++ at the requested optimization, unknown languages rejected.src/runtime/toolchain-prefetch.test.ts: exact Worker URLs with?sha256=, progress reaching the total,signalforwarded, truncated and 403 responses rejected, undeclared profiles rejected before any fetch.src/runtime/client-lifecycle.test.ts: no build request and no timeout while a download stalls past the 190 s Rust boundary, then the boundary starts after it; one download per profile; a failed download fails the build without a Worker request and the next build retries;cancel()aborts an in-flight download; the PCH is requested only for C++ projects shipping the exact admitted header.await Promise.resolve()becameawait vi.advanceTimersByTimeAsync(0), because the build now awaits the acquisition first.pnpm run typecheck,pnpm run lint(0 warnings),pnpm test(194 files / 956 tests),pnpm run docs:verify,pnpm run library:build,node scripts/verify-library.mjsandnode scripts/verify-library-nodenext.mjsall pass.🤖 Generated with Claude Code