feat: pre-transpile .ts on export and resolve to it at runtime (no-transpiler targets)#228
Open
benpalevsky wants to merge 3 commits into
Open
feat: pre-transpile .ts on export and resolve to it at runtime (no-transpiler targets)#228benpalevsky wants to merge 3 commits into
benpalevsky wants to merge 3 commits into
Conversation
Compiles a Rust staticlib (transpiler-ffi/) built around SWC and exposed through a minimal two-function/one-struct C FFI, wired into the engine via SCsub. jsb_module_resolver loads .ts sources directly by transpiling them in-process into the CommonJS module wrapper, so TypeScript no longer needs a separate tsc emit step to run. Opt-in via a new use_typescript_transpiler build flag, off by default. With the flag off (the default) no Rust toolchain enters the build graph and every .ts code path is compiled out behind JSB_WITH_TYPESCRIPT_TRANSPILER: script loading keeps using the tsc-emitted .js (convert_typescript_path), the resolver does not probe .ts, and the build behaves as before this change. The FFI is panic-safe (catch_unwind at the boundary) and hands buffers to C through Box<[u8]> so the C-side free is sound. Build flags in SCsub allow the staticlib's libstd symbols to coexist with Godot's prebuilt accesskit staticlib on Linux/Windows.
The FFI now returns an inline data:application/json;base64 sourcemap URL, which the resolver appends to the wrapped module source as a //# sourceMappingURL comment and also decodes into a per-environment source-map cache. A V8 PrepareStackTraceCallback rewrites runtime Error.stack frames to .ts line/col through that cache, since V8 12.4 only applies source maps in DevTools and not to Error.stack.
…anspiler targets) Export targets without the embedded SWC transpiler (web/mobile) can't compile .ts at runtime. Pre-transpile .ts -> .js via SWC at export time so exported builds need no `tsc`, drop the hard tsc-install gate on the editor Start button, and resolve a .ts module to its pre-transpiled .js sibling at runtime. The export plugin writes the .js to convert_typescript_path() (res://.godot/ GodotJS/<path>.js). Godot still packs the raw .ts (it is the referenced Script resource), so DefaultModuleResolver would otherwise match the un-loadable .ts first; on !JSB_WITH_TYPESCRIPT_TRANSPILER builds it now prefers the .js sibling in check_absolute_file_path (autoloads / direct .ts attaches) and check_implicit_source_path (extension-less imports). Transpiler builds (editor + desktop) are byte-identical; falls through to the .ts (and the guard error) when no .js is packed. An editor built without the transpiler (use_typescript_transpiler off, the default) compiles the SWC export path out entirely and packs the tsc-emitted .js exactly as before this stack.
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.
Part 3 of 3 — the SWC stack. Builds on PR 6 (
6-swc-sourcemaps).Problem
Two friction points around
tsc:tscto turn.tsinto.jsfirst.tscwas installed.What this adds
.tsthrough SWC when you export, so exported builds contain ready-to-run JavaScript and don't needtsc. Pre-transpile is the default export behavior; it's governed by the.../editor/packaging/include_typescript_sourcesetting, which defaults to off — with it off, each.tsis pre-transpiled to.jsat export; turning it on instead packs the raw.tsso the runtime SWC transpiler runs it on load. In an editor built without the transpiler (use_typescript_transpiler=no, the default), the SWC export path compiles out entirely and exports pack thetsc-emitted.jsexactly as today.tscgate. The editor's Start button no longer refuses to run just becausetscisn't installed..js. Godot still packs the raw.ts(it's the referenced Script resource), so the resolver now prefers the pre-transpiled.jssibling for a.tsreference on those builds — autoloads and direct.tsreferences load instead of erroring with "cannot load .ts at runtime". Builds with the embedded transpiler are unchanged.Caveat — checked
Every reference style had to hit that rewrite inside a real exported build (autoloads, direct
.tsattaches, extension-less imports). This is handled in the resolver across three sites:check_absolute_file_pathand theget_source_infoabsolute-path fallback each prefer the converted.jsunder#if !JSB_WITH_TYPESCRIPT_TRANSPILER;check_implicit_source_pathkeeps probing.tson both flag states, with only the.js-preference in the!JSB_WITH_TYPESCRIPT_TRANSPILERbranch (so a transpiler build still loads.tsdirectly). Verified end-to-end on a web export: a freshly exported web build whose autoload is a.tsboots and runs with no "cannot load .ts" error.How to verify
Export a small project that uses a
.tsautoload, run the exported web build (no transpiler present), and confirm it loads and the autoload runs. Separately, withtscuninstalled, confirm the editor Start button still runs.A changeset is included. (Opened on its own, this PR's base is
6-swc-sourcemaps; see the README for how the stack is delivered.)