xbintsc 0.5.52 → 0.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/README.zh-CN.md +9 -3
- package/dist/scripts/fetch-tarball.d.ts +28 -0
- package/dist/scripts/fetch-tarball.js +57 -0
- package/dist/scripts/fetch-tarball.js.map +1 -0
- package/dist/scripts/gui-build-options.d.ts +77 -0
- package/dist/scripts/gui-build-options.js +134 -0
- package/dist/scripts/gui-build-options.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/hints.d.ts +6 -2
- package/dist/src/cli/hints.js +16 -2
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +9 -0
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/driver/app-artifacts.d.ts +2 -0
- package/dist/src/driver/app-artifacts.js +3 -3
- package/dist/src/driver/app-artifacts.js.map +1 -1
- package/dist/src/driver/compiler.js +147 -52
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/icon.d.ts +1 -1
- package/dist/src/driver/icon.js +3 -3
- package/dist/src/driver/icon.js.map +1 -1
- package/dist/src/driver/macos-sdk.d.ts +32 -0
- package/dist/src/driver/macos-sdk.js +50 -0
- package/dist/src/driver/macos-sdk.js.map +1 -0
- package/dist/src/driver/options.d.ts +6 -0
- package/dist/src/driver/platform-support.d.ts +45 -0
- package/dist/src/driver/platform-support.js +66 -0
- package/dist/src/driver/platform-support.js.map +1 -0
- package/dist/src/driver/prebuilt.d.ts +26 -0
- package/dist/src/driver/prebuilt.js +58 -0
- package/dist/src/driver/prebuilt.js.map +1 -0
- package/dist/src/driver/runtime-objects.d.ts +11 -0
- package/dist/src/driver/runtime-objects.js +14 -5
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/toolchain-provider.d.ts +8 -0
- package/dist/src/driver/toolchain-provider.js +8 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +20 -1
- package/dist/src/driver/toolchain.js +19 -0
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/driver/version.js.map +1 -1
- package/dist/src/driver/win-entry.d.ts +1 -1
- package/dist/src/driver/win-entry.js +4 -4
- package/dist/src/driver/win-entry.js.map +1 -1
- package/dist/src/extensions/gui/html.d.ts +10 -7
- package/dist/src/extensions/gui/html.js +53 -29
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/node/child_process/index.d.ts +4 -3
- package/dist/src/extensions/node/child_process/index.js +4 -3
- package/dist/src/extensions/node/child_process/index.js.map +1 -1
- package/dist/tests/cli/hints.test.js +9 -1
- package/dist/tests/cli/hints.test.js.map +1 -1
- package/dist/tests/cli/main.test.js +9 -0
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +107 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/cxx-compile-flags.test.d.ts +1 -0
- package/dist/tests/driver/cxx-compile-flags.test.js +24 -0
- package/dist/tests/driver/cxx-compile-flags.test.js.map +1 -0
- package/dist/tests/driver/macos-sdk.test.d.ts +1 -0
- package/dist/tests/driver/macos-sdk.test.js +83 -0
- package/dist/tests/driver/macos-sdk.test.js.map +1 -0
- package/dist/tests/driver/platform-support.test.d.ts +1 -0
- package/dist/tests/driver/platform-support.test.js +41 -0
- package/dist/tests/driver/platform-support.test.js.map +1 -0
- package/dist/tests/driver/prebuilt.test.d.ts +1 -0
- package/dist/tests/driver/prebuilt.test.js +44 -0
- package/dist/tests/driver/prebuilt.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +24 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +23 -0
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/async-await.test.js +4 -2
- package/dist/tests/e2e/async-await.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +21 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.js +34 -6
- package/dist/tests/e2e/fetch.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-pelican3d.test.d.ts +10 -0
- package/dist/tests/e2e/gui-example-pelican3d.test.js +94 -0
- package/dist/tests/e2e/gui-example-pelican3d.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.js +48 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -1
- package/dist/tests/e2e/unhandled-rejection.test.d.ts +14 -0
- package/dist/tests/e2e/unhandled-rejection.test.js +107 -0
- package/dist/tests/e2e/unhandled-rejection.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +44 -0
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/dist/tests/scripts/fetch-tarball.test.d.ts +1 -0
- package/dist/tests/scripts/fetch-tarball.test.js +70 -0
- package/dist/tests/scripts/fetch-tarball.test.js.map +1 -0
- package/doc/ai/cli.md +6 -0
- package/doc/ai/language-support.md +1 -0
- package/doc/ai/troubleshooting.md +32 -2
- package/doc/ai/zh-CN/cli.md +5 -0
- package/doc/ai/zh-CN/language-support.md +1 -0
- package/doc/ai/zh-CN/troubleshooting.md +27 -2
- package/doc/gui/build.md +7 -3
- package/doc/gui/dom.md +3 -1
- package/doc/gui/webgl.md +4 -0
- package/doc/gui-scripts.md +33 -17
- package/doc/gui.md +17 -1
- package/doc/implemented/async.md +1 -0
- package/doc/implemented/modules.md +9 -6
- package/doc/implemented/node/child-process.md +12 -4
- package/doc/implemented/runtime-core.md +1 -1
- package/doc/npm-package.md +23 -2
- package/doc/post/make-js-great-again.md +30 -0
- package/doc/requirements.md +31 -0
- package/doc/unimplemented/deviations.md +1 -0
- package/doc/zh-CN/gui/build.md +4 -2
- package/doc/zh-CN/gui/dom.md +3 -1
- package/doc/zh-CN/gui/webgl.md +1 -0
- package/doc/zh-CN/gui-scripts.md +23 -11
- package/doc/zh-CN/gui.md +11 -1
- package/doc/zh-CN/implemented/async.md +1 -0
- package/doc/zh-CN/implemented/modules.md +8 -4
- package/doc/zh-CN/implemented/node/child-process.md +10 -3
- package/doc/zh-CN/implemented/runtime-core.md +1 -1
- package/doc/zh-CN/npm-package.md +18 -1
- package/doc/zh-CN/post/make-js-great-again.md +32 -0
- package/doc/zh-CN/requirements.md +25 -0
- package/doc/zh-CN/unimplemented/deviations.md +1 -0
- package/package.json +7 -7
- package/runtime/ext_node/child_process/child_process.c +149 -7
- package/runtime/rt.h +4 -0
- package/runtime/xt_async.c +4 -0
- package/runtime/xt_generator.c +2 -0
- package/runtime/xt_loop.c +8 -4
- package/runtime/xt_promise.c +103 -0
- package/scripts/build-gui.ts +17 -5
- package/scripts/build-media.ts +89 -10
- package/scripts/build-runtime.ts +7 -2
- package/scripts/fetch-tarball.ts +71 -0
- package/scripts/gui-build-cache.ts +28 -0
- package/scripts/gui-build-options.ts +26 -2
- package/scripts/package-release.ts +8 -0
- package/src/cli/hints.ts +19 -2
- package/src/cli/main.ts +11 -0
- package/src/driver/app-artifacts.ts +5 -3
- package/src/driver/compiler.ts +167 -56
- package/src/driver/icon.ts +3 -2
- package/src/driver/macos-sdk.ts +52 -0
- package/src/driver/options.ts +6 -0
- package/src/driver/platform-support.ts +69 -0
- package/src/driver/prebuilt.ts +61 -0
- package/src/driver/runtime-objects.ts +26 -5
- package/src/driver/toolchain-provider.ts +11 -0
- package/src/driver/toolchain.ts +26 -1
- package/src/driver/version.ts +1 -1
- package/src/driver/win-entry.ts +4 -3
- package/src/extensions/gui/html.ts +61 -31
- package/src/extensions/node/child_process/index.ts +4 -3
package/doc/gui-scripts.md
CHANGED
|
@@ -141,9 +141,10 @@ __registerScript("a1b2…", __xt_script_a1b2);
|
|
|
141
141
|
export default __html;
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
- id is a content hash of the wrapped body (sha256, first 32 hex chars; a
|
|
145
|
+
deferred import's prelude is included, so two scripts with identical
|
|
146
|
+
statements but different imports stay distinct); the body is replaced by an
|
|
147
|
+
empty marker element so the engine can find it in document order.
|
|
147
148
|
- `window` and `document` are **function parameters**, so script globals resolve
|
|
148
149
|
as ordinary locals — **no compiler changes**, no global object.
|
|
149
150
|
- `__registerScript(id, fn)` is a new runtime builtin that stores the closure in
|
|
@@ -151,6 +152,13 @@ export default __html;
|
|
|
151
152
|
- Deferred scripts (`<script defer>`, or all inline scripts, as decided in M9c)
|
|
152
153
|
run after the full document is parsed and the first layout is computed, in
|
|
153
154
|
document order. `DOMContentLoaded` then `load` are fired on `window`.
|
|
155
|
+
- An inline body is split into imports and statements by the **same** routine as
|
|
156
|
+
a `<script src>` file (below): top-level `import`/`export … from` statements
|
|
157
|
+
are hoisted into the generated module, relative specifiers resolve from the
|
|
158
|
+
HTML file, and `export` modifiers are stripped. `import { readFileSync } from
|
|
159
|
+
"node:fs"` inside an inline `<script>` therefore links exactly like the same
|
|
160
|
+
import in an external script — one has to enable the `node` extension, but not
|
|
161
|
+
rewrite the page.
|
|
154
162
|
|
|
155
163
|
### 2b. External `<script src>`
|
|
156
164
|
|
|
@@ -162,21 +170,21 @@ are **deferred**, like a browser module script: the loader emits a synthetic
|
|
|
162
170
|
at `loadHTML` time. The bundler wraps the whole local import graph in functions
|
|
163
171
|
that return their exports (memoised by `__xt_defer`), so top-level module code
|
|
164
172
|
runs after the document exists and two scripts importing the same module share
|
|
165
|
-
one instance. Bare specifiers (`gui`, a package) stay eager.
|
|
173
|
+
one instance. Bare specifiers (`gui`, a package, `node:fs`) stay eager. An
|
|
174
|
+
inline `<script>` body goes through the identical split, so an import behaves
|
|
175
|
+
the same in both forms; the only difference is where the body comes from.
|
|
166
176
|
|
|
167
177
|
A missing `src` file is still a clear error (turned into a bundler diagnostic),
|
|
168
178
|
and `src` URLs (`https://…`, `data:…`, `//host`) are left untouched — they are
|
|
169
179
|
not compile-time assets and never run.
|
|
170
180
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
directly: `state.update = …` on an object literal is not a `TS4003`. A page can
|
|
179
|
-
therefore ship its existing scripts unchanged.
|
|
181
|
+
A wrapped `<script src>` body keeps its own file as the origin of every
|
|
182
|
+
statement in it (the loader reports the body's span in the generated module as a
|
|
183
|
+
*source range*), so a diagnostic points at `app.js:12` rather than at a column
|
|
184
|
+
of `index.html`, and a **plain-JavaScript** script stays untyped exactly like a
|
|
185
|
+
`.js` module imported directly: `state.update = …` on an object literal is not a
|
|
186
|
+
`TS4003`. A page can therefore ship its existing scripts unchanged. An inline
|
|
187
|
+
body's origin is the HTML page itself.
|
|
180
188
|
|
|
181
189
|
```html
|
|
182
190
|
<button id="b">0</button>
|
|
@@ -308,6 +316,10 @@ legacy `target` field over the handle.
|
|
|
308
316
|
module wrapper at `loadHTML` time, so the import graph sees a parsed
|
|
309
317
|
document and shares one instance per module. Missing files surface as
|
|
310
318
|
diagnostics. All scripts run in document order. e2e coverage.
|
|
319
|
+
- **M9c′** ✅ — an inline `<script>` body is split by the same routine, so an
|
|
320
|
+
`import` (a `node:`/bare specifier included) links exactly as it does in a
|
|
321
|
+
`<script src>` file. It used to be wrapped verbatim, leaving an inline
|
|
322
|
+
`import` inside the script function where codegen reported TS5001.
|
|
311
323
|
- **M9d** *(optional)* — detect inline HTML in template literals passed to
|
|
312
324
|
`win.loadHTML(...)` and transform them too (fragile; deferred).
|
|
313
325
|
- **M10 — polish** ✅ — `requestAnimationFrame`/`cancelAnimationFrame` on the
|
|
@@ -331,11 +343,12 @@ legacy `target` field over the handle.
|
|
|
331
343
|
network fetches) do not run. Documented.
|
|
332
344
|
- **Template-literal HTML** passed to `win.loadHTML(…)` is not transformed in
|
|
333
345
|
M9b (only imported assets are). M9d addresses this if needed.
|
|
334
|
-
- **Top-level `await`** inside a deferred `<script src>`
|
|
346
|
+
- **Top-level `await`** inside a deferred `<script src>` or inline script is not
|
|
335
347
|
supported: the module body is wrapped in a synchronous init function.
|
|
336
|
-
- **Assets.** `<script src>` is resolved relative to the HTML asset;
|
|
337
|
-
|
|
338
|
-
global `fetch` is a separate
|
|
348
|
+
- **Assets.** `<script src>` is resolved relative to the HTML asset; an inline
|
|
349
|
+
body's imports resolve from the same place. URL `src` values are ignored. The
|
|
350
|
+
loader does not fetch network URLs; the runtime's global `fetch` is a separate
|
|
351
|
+
API.
|
|
339
352
|
|
|
340
353
|
## Testing
|
|
341
354
|
|
|
@@ -347,6 +360,9 @@ legacy `target` field over the handle.
|
|
|
347
360
|
rewrites `*.foo` and records dependencies.
|
|
348
361
|
- **M9b**: an e2e case with an inline `<script>` incrementing a counter on
|
|
349
362
|
click, asserted through `console.log` from the handler.
|
|
363
|
+
- **M9c′**: unit cases asserting an inline body's imports are hoisted (and its
|
|
364
|
+
relative ones deferred), plus an e2e case where an inline script reads a file
|
|
365
|
+
through `node:fs` and calls a deferred helper module.
|
|
350
366
|
- **M10**: e2e cases for `requestAnimationFrame` (runs each frame, re-queues,
|
|
351
367
|
receives a timestamp, honours `cancelAnimationFrame`) and for
|
|
352
368
|
`offsetWidth`/`offsetHeight`/`contains`.
|
package/doc/gui.md
CHANGED
|
@@ -217,7 +217,16 @@ engine were Rust.
|
|
|
217
217
|
- `vendor/` (SDL3/FreeType/HarfBuzz/glslang for the GUI archive, FFmpeg for `media`)
|
|
218
218
|
is cached per OS/arch, keyed by `scripts/build-gui.ts` /
|
|
219
219
|
`scripts/build-media.ts`. Windows x64 gets its own source cache plus the
|
|
220
|
-
installed `vendor/ffmpeg-build-msvc/dist` prefix.
|
|
220
|
+
installed `vendor/ffmpeg-build-msvc/dist` prefix. On Linux/macOS the
|
|
221
|
+
installed `vendor/ffmpeg-build/dist` prefix has its own cache, keyed by
|
|
222
|
+
`FFMPEG_VERSION` and `scripts/build-media.ts` (which owns the configure
|
|
223
|
+
flags), so a hit skips FFmpeg's configure/make instead of rebuilding it on
|
|
224
|
+
every run: `scripts/build-media.ts` stamps the prefix with the release it
|
|
225
|
+
built and discards it when either the release or the macOS deployment
|
|
226
|
+
target changes. The FFmpeg
|
|
227
|
+
release tarball additionally has a cache keyed only by `FFMPEG_VERSION` and
|
|
228
|
+
shared by every job, so ffmpeg.org's intermittent TLS handshake cannot fail
|
|
229
|
+
a run that already downloaded it once.
|
|
221
230
|
- Windows x64 builds both archives in CI and links a `gui` program that
|
|
222
231
|
exercises the `media` link feature (plus an explicit `--feature media`
|
|
223
232
|
build), using the same Visual Studio `vcvarsall` + bundled LLVM toolchain
|
|
@@ -245,6 +254,10 @@ engine were Rust.
|
|
|
245
254
|
through a memoised module wrapper, so imported modules see the parsed
|
|
246
255
|
document and share state. Missing files become diagnostics. Everything
|
|
247
256
|
runs in document order.
|
|
257
|
+
- **M9c′** ✅ — an inline `<script>` body is split by the same routine, so its
|
|
258
|
+
imports are hoisted (a `node:`/bare specifier links like any module import)
|
|
259
|
+
instead of staying inside the wrapped function, where codegen reported
|
|
260
|
+
TS5001. Inline and `<script src>` now behave identically.
|
|
248
261
|
10. **M10 — polish** ✅
|
|
249
262
|
- `win.requestAnimationFrame(fn)` / `win.cancelAnimationFrame(id)`; callbacks
|
|
250
263
|
run at the top of each frame with the frame timestamp and may mutate the
|
|
@@ -454,6 +467,9 @@ engine were Rust.
|
|
|
454
467
|
memoised module wrapper (so module-level DOM work sees the parsed document),
|
|
455
468
|
while missing files are diagnostics. Loader errors are caught by `loadGraph`
|
|
456
469
|
and reported as build errors.
|
|
470
|
+
- **M9c′** ✅ inline `<script>` bodies are split by the same routine as external
|
|
471
|
+
ones, so an inline `import` is hoisted and links identically (including
|
|
472
|
+
`node:fs` with the `node` extension); only the body's origin differs.
|
|
457
473
|
- **M10** ✅ `requestAnimationFrame`/`cancelAnimationFrame` on window handles
|
|
458
474
|
(callbacks run with the frame timestamp before layout each frame) plus
|
|
459
475
|
`offsetWidth`/`offsetHeight`/`contains` on element handles; e2e coverage in
|
package/doc/implemented/async.md
CHANGED
|
@@ -30,6 +30,7 @@ Location: `runtime/xt_async.c`, `runtime/xt_coroutine.c`, `runtime/xt_promise.c`
|
|
|
30
30
|
- Microtask queue (`xt_microtasks`); `xt_promise_ctor/resolve/reject/static` (including `withResolvers`), instance `then` / `catch` / `finally`.
|
|
31
31
|
- `xt_drain_microtasks` empties the queue at program exit, and the event loop drains it between callbacks.
|
|
32
32
|
- `xt_await` queues a microtask for a non-promise or settled value, and suspends the running async coroutine on a pending promise until it settles.
|
|
33
|
+
- Unhandled rejections are fatal, like Node's default `--unhandled-rejections=throw`. A promise that rejects and is never observed — no `.then` / `.catch`, no `await`, not adopted by another promise — is reported as `Unhandled promise rejection` on stderr once the event loop drains, and the process exits with status 1. The case this protects is the entry point: a program's `main()` is usually `async`, so an exception escaping it would otherwise reject an unobserved promise and the process would print nothing and exit 0. Attaching a handler later, even from a timer, still counts as observed.
|
|
33
34
|
|
|
34
35
|
## Timers and the event loop
|
|
35
36
|
|
|
@@ -21,12 +21,15 @@ Location: `src/parser/parser.ts` (syntax), `src/driver/modules.ts` (bundling),
|
|
|
21
21
|
|
|
22
22
|
## Deferred evaluation
|
|
23
23
|
|
|
24
|
-
- The `gui` `.html` asset loader marks relative
|
|
25
|
-
synthetic `__xt_deferred_module` binding.
|
|
26
|
-
and its local import graph in functions that
|
|
27
|
-
generated script calls them after `loadHTML`
|
|
28
|
-
module). This matches a browser module script,
|
|
29
|
-
once the document exists.
|
|
24
|
+
- The `gui` `.html` asset loader marks relative imports of an inline `<script>`
|
|
25
|
+
body or a `<script src>` file with a synthetic `__xt_deferred_module` binding.
|
|
26
|
+
The bundler then wraps that module and its local import graph in functions that
|
|
27
|
+
return their exports, and the generated script calls them after `loadHTML`
|
|
28
|
+
(`__xt_defer` memoises each module). This matches a browser module script,
|
|
29
|
+
where the graph is evaluated once the document exists.
|
|
30
|
+
- Both script forms are split the same way: top-level `import`/`export … from`
|
|
31
|
+
statements are hoisted into the generated module and `export` modifiers are
|
|
32
|
+
stripped, so a bare or `node:` specifier links like any ordinary module import.
|
|
30
33
|
- Modules also reachable through a normal (non-marker) import stay eager and get
|
|
31
34
|
a thin wrapper over their already-initialised exports.
|
|
32
35
|
- The wrapper body is synchronous: top-level `await` inside a deferred script
|
|
@@ -5,17 +5,25 @@
|
|
|
5
5
|
Location: `src/extensions/node/child_process/index.ts`, `runtime/ext_node/child_process/child_process.c`
|
|
6
6
|
|
|
7
7
|
`spawnSync(command, args[, options])` runs a program to completion and returns
|
|
8
|
-
`{ status, stdout, stderr }`. `options.cwd` sets the working directory
|
|
9
|
-
`options.
|
|
10
|
-
|
|
11
|
-
stdout/stderr are captured
|
|
8
|
+
`{ status, stdout, stderr }`. `options.cwd` sets the working directory,
|
|
9
|
+
`options.env` replaces the child's environment, and `options.stdio: "inherit"`
|
|
10
|
+
hands the child the parent's stdout/stderr (used by `xbintsc run`, so a
|
|
11
|
+
compiled program's output streams live); otherwise stdout/stderr are captured
|
|
12
|
+
as UTF-8 strings.
|
|
12
13
|
|
|
13
14
|
| Option | Notes |
|
|
14
15
|
| --- | --- |
|
|
15
16
|
| `cwd` | working directory for the child |
|
|
17
|
+
| `env` | the child's complete environment; omit it to inherit, spread `process.env` into it to extend |
|
|
16
18
|
| `stdio: "inherit"` | share the parent's stdout/stderr instead of capturing |
|
|
17
19
|
| `encoding` | accepted and ignored (output is always decoded as UTF-8) |
|
|
18
20
|
|
|
21
|
+
`env` follows Node's replace semantics: a present object *is* the environment,
|
|
22
|
+
so a variable the caller does not list is absent in the child. That is what lets
|
|
23
|
+
a caller hand a toolchain a specific `SDKROOT`, `INCLUDE` or `LIB` without
|
|
24
|
+
leaking its own shell setup — and what the macOS SDK fix relies on, because a
|
|
25
|
+
self-hosted compiler runs this same code.
|
|
26
|
+
|
|
19
27
|
On Windows the child is launched with `CreateProcess` and its stdout/stderr are
|
|
20
28
|
drained through anonymous pipes by reader threads. No temporary files are used,
|
|
21
29
|
so a locked-down `%TEMP%` cannot break `spawnSync`, and output larger than a pipe
|
|
@@ -28,5 +28,5 @@ standard-library surface have their own pages:
|
|
|
28
28
|
- Operator helpers: `xt_in` (`in`), `xt_delete` (`delete`), `xt_rest_args` (rest parameters / `arguments`).
|
|
29
29
|
- Box: `box_new/get/set` (for closure-captured variables).
|
|
30
30
|
- Functions and closures: `arg`, `closure_new/call/env/arity`.
|
|
31
|
-
- Exceptions: `xt_try_enter` / `xt_try_exception` / `xt_try_leave` maintain the `_setjmp` frame stack; `xt_throw` long-jumps to the nearest `try` when a frame exists, otherwise prints `Uncaught ...` and exits. Codegen also maintains a shadow call stack (function name, source file and line) that `Error.stack` captures (see [Standard library](./stdlib.md)), and a fatal-signal handler dumps the same frames on a native crash. `--debug` additionally emits `!DICompileUnit` / `!DISubprogram` / `!DILocation` metadata and compiles with `-g -fno-omit-frame-pointer`, so gdb/lldb/WinDbg map instructions back to source lines.
|
|
31
|
+
- Exceptions: `xt_try_enter` / `xt_try_exception` / `xt_try_leave` maintain the `_setjmp` frame stack; `xt_throw` long-jumps to the nearest `try` when a frame exists, otherwise prints `Uncaught ...` and exits. A promise rejection nobody observes is fatal too: `xt_promise_report_unhandled` runs once the event loop drains, prints `Unhandled promise rejection` plus the reason and exits with status 1 (see [Async](./async.md)). Codegen also maintains a shadow call stack (function name, source file and line) that `Error.stack` captures (see [Standard library](./stdlib.md)), and a fatal-signal handler dumps the same frames on a native crash. `--debug` additionally emits `!DICompileUnit` / `!DISubprogram` / `!DILocation` metadata and compiles with `-g -fno-omit-frame-pointer`, so gdb/lldb/WinDbg map instructions back to source lines.
|
|
32
32
|
- Objects / functions: `xt_object` with a prototype chain, `xt_function` with a property bag (static members and `prototype`); `xt_new` (instantiation), `xt_instance_of` (prototype chain), `xt_object_freeze/is_frozen/from_entries`; `xt_constructors.c` holds the first-class constructor cache, constructor prototypes and static-value dispatch.
|
package/doc/npm-package.md
CHANGED
|
@@ -216,9 +216,29 @@ necessarily next to the config file); set `xbintsc_CACHE_DIR` to put it
|
|
|
216
216
|
elsewhere. Expect that fallback build to take noticeably longer than the ones
|
|
217
217
|
after it.
|
|
218
218
|
|
|
219
|
+
The prebuilt archives are produced by the release runner's toolchain and target
|
|
220
|
+
the floors in
|
|
221
|
+
[requirements](./requirements.md#supported-platforms) (macOS 11.0, Windows 11,
|
|
222
|
+
glibc 2.39). When that toolchain is newer than the one on this machine — a newer
|
|
223
|
+
Xcode Command Line Tools/SDK or Visual Studio C++ toolset — the linker can
|
|
224
|
+
reject the archive with unresolved symbols (`LNK2038`, `LNK2019`, `Undefined
|
|
225
|
+
symbols`, `undefined reference`) or a `was built for newer macOS version`
|
|
226
|
+
warning. The driver then retries the link **automatically** with
|
|
227
|
+
`core`/`ext_node` compiled from the sources shipped in the package, so a
|
|
228
|
+
mismatched archive costs time, not a failed build:
|
|
229
|
+
|
|
230
|
+
```text
|
|
231
|
+
xbintsc: the prebuilt runtime archive does not match this toolchain (…); compiling the C runtime from source
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The retry is not remembered: after a toolchain upgrade a later build links the
|
|
235
|
+
archive again. The bundled `gui.a`/`media.a` are the exception — they contain
|
|
236
|
+
SDL3/FFmpeg, whose sources are not part of the npm package, so they cannot be
|
|
237
|
+
rebuilt this way. If they are the incompatible archive, use a release built for
|
|
238
|
+
this toolchain or a source checkout.
|
|
239
|
+
|
|
219
240
|
To ignore the platform archive on purpose and compile the runtime from the
|
|
220
|
-
sources shipped in the package — for example after patching `runtime
|
|
221
|
-
the prebuilt archive does not match the environment — set:
|
|
241
|
+
sources shipped in the package — for example after patching `runtime/` — set:
|
|
222
242
|
|
|
223
243
|
```bash
|
|
224
244
|
xbintsc_PREFER_PREBUILT=0 npx xbintsc build src/main.ts --out build
|
|
@@ -439,6 +459,7 @@ the same file under `node_modules/xbintsc/doc/ai/`.
|
|
|
439
459
|
| The first build takes a long time | The optional `@xbintsc/<os>-<arch>` package was skipped (or this host has no prebuilt package), so the runtime C sources are compiled and cached. Check `npm ls @xbintsc/<os>-<arch>` and reinstall without `--omit=optional`; `--time` confirms. |
|
|
440
460
|
| Permission errors writing `.xbintsc/` | Set `xbintsc_CACHE_DIR` to a writable directory, or run from a writable working directory. |
|
|
441
461
|
| `module 'fs' is provided by the 'node' extension` | Add `--ext node`, or `"extensions": ["node"]` in the config. |
|
|
462
|
+
| Link fails with `LNK2038`, `LNK2019`, `Undefined symbols` or `was built for newer macOS version` | The prebuilt archive was built by a newer Xcode/Visual Studio toolchain. The driver retries automatically with the runtime's C sources; if the error persists it is `gui.a`/`media.a`, which cannot be rebuilt from the npm package — use a matching release or a source checkout. |
|
|
442
463
|
| `GUI native library not found` / `media native library not found` | The optional platform package that ships `gui.a`/`gui.lib` or `media.a`/`media.lib` was skipped, or this host has no prebuilt GUI/media archive (Windows arm64). Reinstall without `--omit=optional`, use a Linux/macOS/Windows x64 release archive, or build the archive from a source checkout. An auto-detected `media` feature with a missing archive only warns; `--feature media` makes it an error. |
|
|
443
464
|
| `require("xbintsc")` fails | The package is ESM-only; use `import` (or dynamic `import()`). |
|
|
444
465
|
| Windows link errors about missing MSVC libraries | Run from a Native Tools prompt, install the VS C++ build tools, and check `npx xbintsc doctor`. |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# This Might Be the Most Exciting Thing for JS Developers This Year
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
The image above is a 3D pelican riding a bicycle that I built with JS + HTML + WebGL2, and the framerate is excellent too.
|
|
6
|
+
|
|
7
|
+
You might say, "Isn't that just a matter of having hands and an AI these days?"
|
|
8
|
+
|
|
9
|
+
But what if I told you that I compiled that very thing into a native binary with xbintsc — under 10 MB, able to run with no WebView environment at all, and able to mix Node.js and HTML in a single file, like this:
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<html>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="out">loading...</div>
|
|
15
|
+
<script lang="ts">
|
|
16
|
+
import { readFileSync } from "fs";
|
|
17
|
+
|
|
18
|
+
const out = document.getElementById("out");
|
|
19
|
+
const world = readFileSync("data.txt", "utf8");
|
|
20
|
+
out.textContent = "hello " + world;
|
|
21
|
+
</script>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Keep in mind that Chrome alone used to take at least 100 MB. The xbintsc build is 10 MB and doesn't need a WebView environment — and that means far more than just a massive reduction in the footprint of desktop development, or a more correct implementation path.
|
|
27
|
+
|
|
28
|
+
What is truly epoch-making is this: it is now possible for JS developers to run the applications they want to build on embedded devices.
|
|
29
|
+
|
|
30
|
+
[xbintsc on GitHub](https://github.com/zy445566/xbintsc)
|
package/doc/requirements.md
CHANGED
|
@@ -15,6 +15,32 @@ no requirements on any platform.
|
|
|
15
15
|
Installing the compiler from npm instead of using a release archive? Node.js 22+
|
|
16
16
|
then runs the compiler itself; see [Using xbintsc from npm](./npm-package.md).
|
|
17
17
|
|
|
18
|
+
## Supported platforms
|
|
19
|
+
|
|
20
|
+
Release binaries and the prebuilt runtime archives target the oldest platform
|
|
21
|
+
versions xbintsc supports. CI builds them with the **oldest toolchain that can
|
|
22
|
+
still assemble a release for each host**, so a newer Xcode or Visual Studio on
|
|
23
|
+
your machine can link them — the reverse direction is what fails with `LNK2038`,
|
|
24
|
+
`Undefined symbols` or `was built for newer macOS version`.
|
|
25
|
+
|
|
26
|
+
| Platform | Produced binaries run on | Build baseline (CI) |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| macOS x64 / arm64 | **macOS 11.0** (Big Sur) and newer | the oldest installed Xcode with clang 16+, `MACOSX_DEPLOYMENT_TARGET=11.0` |
|
|
29
|
+
| Windows x64 | **Windows 11** and newer | the `windows-2025` image's toolset (VS 2026) |
|
|
30
|
+
| Windows arm64 | **Windows 11** | the `windows-11-arm` image's toolset (currently VS 2026; no older arm64 image exists) |
|
|
31
|
+
| Linux x64 / arm64 | **glibc 2.39** (Ubuntu 24.04) and newer | clang 16 + lld 16 on `ubuntu-24.04` |
|
|
32
|
+
|
|
33
|
+
The compiler toolchain floors are Xcode 16 (Apple clang 16) on macOS, the
|
|
34
|
+
`windows-2025` image's Visual Studio (currently VS 2026) on Windows and clang 16
|
|
35
|
+
on Linux. Building therefore needs a newer host than the produced binary does:
|
|
36
|
+
Xcode 16 itself requires macOS 14.5+, so a macOS 11–14 build machine needs a
|
|
37
|
+
standalone LLVM 16+ (for example Homebrew's `llvm`). `xbintsc doctor` prints the
|
|
38
|
+
floor for the host it runs on. If the archives were built with a
|
|
39
|
+
newer toolchain than yours, `build` retries with the C runtime's shipped
|
|
40
|
+
sources (see [the npm package guide](./npm-package.md#the-first-build-and-the-cache));
|
|
41
|
+
the bundled `gui.a`/`media.a` cannot be rebuilt that way, because SDL3/FFmpeg
|
|
42
|
+
sources are not part of the package.
|
|
43
|
+
|
|
18
44
|
clang 15 and older fail on the first string literal in any program, with:
|
|
19
45
|
|
|
20
46
|
```
|
|
@@ -112,6 +138,11 @@ xcode-select -p # prints the active developer directory
|
|
|
112
138
|
xcrun --show-sdk-path # prints the SDK path
|
|
113
139
|
```
|
|
114
140
|
|
|
141
|
+
xbintsc runs the command in the second line itself and passes the result to
|
|
142
|
+
clang as `-isysroot`, so a clang selected by absolute path (the CI baseline, or
|
|
143
|
+
`xbintsc_CLANG`) still finds the SDK's C headers and link stubs. Setting
|
|
144
|
+
`SDKROOT` yourself takes precedence and pins a specific SDK.
|
|
145
|
+
|
|
115
146
|
## Linux — install clang and lld
|
|
116
147
|
|
|
117
148
|
A normal glibc-based distribution plus `clang` and `lld` is enough:
|
|
@@ -16,6 +16,7 @@ These features **compile and run**, but the result does not fully match ECMAScri
|
|
|
16
16
|
| Memory management | Non-moving mark-sweep collector behind `xt_alloc`: explicit roots, subsystem root providers and a conservative C-stack scan. Single-threaded and stop-the-world; no moving/compaction or generational mode |
|
|
17
17
|
| Function `arity` / argument count | Direct calls to a locally visible function are checked by the default [semantic checker](../implemented/checker.md) (`TS4004`); calls through properties, imports, spread arguments or a reassigned binding are not. `fn.length` reports the declared arity |
|
|
18
18
|
| `async` / `await` | Real suspension on a stackful coroutine; `await` always queues a microtask (non-promises and already-settled promises included), so interleaving with pending `.then` callbacks matches the specification. Top-level `await` blocks on the event loop rather than yielding the module body. `fs/promises` and `fetch` offload their blocking work to a four-worker pool and settle on the reactor. Async generators suspend at both `await` and `yield`; `for await...of` awaits one step per iteration |
|
|
19
|
+
| Unhandled rejections | Reported when the program ends rather than at the end of the tick: a rejection no handler observed is printed and makes the process exit 1 once the event loop drains, so a long-running process (a server) keeps running until it exits, and a handler attached later still suppresses the report. Node raises the fatal error right after the microtask queue drains |
|
|
19
20
|
| Async generator cleanup | `for await...of` does not call the iterator's `return()` when the loop exits early. `yield*` inside an async generator delegates to synchronous iterables only. `.return()` at a suspended `yield` completes without running `finally` (the same limitation as synchronous generators) |
|
|
20
21
|
| `super` | `super.x` / `super[x]` read from the parent holder of the class whose body is running (in an instance method: the parent prototype; in a `static` method or static block: the parent constructor), so any inheritance depth is correct |
|
|
21
22
|
| `Error.stack` | Function-level frames only: each frame is `at name (file:line)` with the function's declaration line (updated to the construction line for the innermost frame); no column numbers and no frames for generator / `async` bodies (they switch stacks) |
|
package/doc/zh-CN/gui/build.md
CHANGED
|
@@ -39,8 +39,10 @@
|
|
|
39
39
|
demuxer/parser/decoder 的最小静态构建,用它编译
|
|
40
40
|
`runtime/ext_media/media.cpp`,并把所有内容合并到
|
|
41
41
|
`runtime/lib/<os>-<arch>/media.a`(Windows 上 MSVC ABI 则为 `media.lib`)。
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
下载会重试发布主机常见的瞬时 TLS 故障;解压后 tarball 保留为
|
|
43
|
+
`vendor/ffmpeg-<version>.tar.xz`,因此重建(或按 `FFMPEG_VERSION` 缓存它的
|
|
44
|
+
CI)会解压本地副本而不再下载。`gui.a` **不会**链接 FFmpeg:编译器为可能播放
|
|
45
|
+
媒体的程序选中 `media` 链接特性后才链接 `media.a`(见[链接特性](#链接特性))。
|
|
44
46
|
- `src/extensions/gui/index.ts` 通过 `nativeObjects()` 暴露引擎归档(经由
|
|
45
47
|
`findRuntimeLibrary`,因此 `.a`/`.lib` 都可用),并通过 `linkerFlags()`
|
|
46
48
|
暴露操作系统框架。它的 `linkFeatures()`(位于
|
package/doc/zh-CN/gui/dom.md
CHANGED
|
@@ -182,7 +182,9 @@ run();
|
|
|
182
182
|
这两个参数(`window`、`document`)只是普通的函数参数,因此脚本的局部变量
|
|
183
183
|
无需任何全局对象机制。外部脚本同样可用:`<script src="./counter.ts">` 会在
|
|
184
184
|
编译期读取,其 import 会被提升(重写为从 HTML 文件解析),其主体以同样方式
|
|
185
|
-
包装——因此脚本模块可以 `import` 辅助函数,同时仍能看到 `document
|
|
185
|
+
包装——因此脚本模块可以 `import` 辅助函数,同时仍能看到 `document`。内联主体
|
|
186
|
+
走同一套拆分,因此 `import` 在两种写法中行为一致;开启 `node` 扩展后,
|
|
187
|
+
`node:fs` 等其他 `node:` 内置模块同样可用。脚本是
|
|
186
188
|
**编译期资产**:运行时创建的 HTML(`innerHTML`、网络获取)永不执行,`src`
|
|
187
189
|
URL(`https://…`、`data:…`)会被忽略。一切都按文档顺序在解析后运行(实际上
|
|
188
190
|
是 deferred)。完整设计参见 `gui-scripts.md`。
|
package/doc/zh-CN/gui/webgl.md
CHANGED
|
@@ -133,6 +133,7 @@ transform feedback(入口为空操作:SDL_GPU 没有 transform feedback 阶
|
|
|
133
133
|
- `tests/e2e/gui-media.test.ts` 还会把 `<video>` 的最新解码帧上传为纹理并读回像素。
|
|
134
134
|
- `examples/gui/webgl-cube` 是一个旋转、受光、带纹理的立方体;它在浏览器中原样运行,并由 `tests/e2e/gui-example-webgl.test.ts` 覆盖。
|
|
135
135
|
- `examples/gui/webgl2-cubes` 用一次绘制调用画出 64 个实例化立方体,使用 `#version 300 es` 与 VAO;由 `tests/e2e/gui-example-webgl2.test.ts` 覆盖。
|
|
136
|
+
- `examples/gui/pelican-3d` 是一个完整的光照场景(程序化天空、雾、实例化树木/云、带关节动画的鹈鹕和自行车),拆成九个 ES module,并用 `AudioContext` 合成音效;由 `tests/e2e/gui-example-pelican3d.test.ts` 覆盖。
|
|
136
137
|
|
|
137
138
|
这些用例会在宿主选择的后端上运行:Linux(与 Windows)上是 Vulkan,macOS 上是 Metal,因此 SPIRV-Cross → MSL 路径与 SPIR-V 路径受同一组断言保护。
|
|
138
139
|
|
package/doc/zh-CN/gui-scripts.md
CHANGED
|
@@ -133,8 +133,9 @@ __registerScript("a1b2…", __xt_script_a1b2);
|
|
|
133
133
|
export default __html;
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
- id
|
|
137
|
-
|
|
136
|
+
- id 是包装后主体内容的哈希(sha256,前 32 个十六进制字符;包含延迟 import 的
|
|
137
|
+
prelude,因此语句相同但 import 不同的两个脚本不会合并为同一条注册表记录);
|
|
138
|
+
主体被替换为一个空的标记元素,以便引擎能按文档顺序找到它。
|
|
138
139
|
- `window` 与 `document` 是**函数参数**,因此脚本的全局变量会作为普通局部
|
|
139
140
|
变量解析 —— **无需编译器改动**,也没有全局对象。
|
|
140
141
|
- `__registerScript(id, fn)` 是一个新的运行时内置函数,它把闭包存进全局的
|
|
@@ -142,6 +143,11 @@ export default __html;
|
|
|
142
143
|
- 延迟脚本(`<script defer>`,或 M9c 中决定的所有内联脚本)在完整文档解析
|
|
143
144
|
并计算首次布局之后按文档顺序运行。然后在 `window` 上依次触发
|
|
144
145
|
`DOMContentLoaded` 再 `load`。
|
|
146
|
+
- 内联主体与 `<script src>` 文件走**同一套**拆分逻辑(见下):顶层
|
|
147
|
+
`import`/`export … from` 语句被提升进生成模块,相对说明符相对 HTML 文件
|
|
148
|
+
解析,`export` 修饰符被去掉。因此内联 `<script>` 里的
|
|
149
|
+
`import { readFileSync } from "node:fs"` 与外链脚本里的同一条 import 链接
|
|
150
|
+
方式完全一致 —— 需要开启 `node` 扩展,但不需要改写页面。
|
|
145
151
|
|
|
146
152
|
### 2b. 外部 `<script src>`
|
|
147
153
|
|
|
@@ -151,19 +157,19 @@ import 会像浏览器的模块脚本一样**延迟**:loader 生成一个合
|
|
|
151
157
|
`__xt_deferred_module` 标记,生成的脚本在 `loadHTML` 时调用模块包装函数。
|
|
152
158
|
bundler 把整个本地 import 图包装成返回各自导出的函数(由 `__xt_defer`
|
|
153
159
|
记忆化),因此模块顶层代码在文档就绪后才运行,且两个脚本导入同一模块时共享
|
|
154
|
-
同一个实例。裸说明符(`gui`、npm
|
|
160
|
+
同一个实例。裸说明符(`gui`、npm 包、`node:fs`)仍然立即加载。内联
|
|
161
|
+
`<script>` 主体走完全相同的拆分,因此两种写法里的 import 行为一致;唯一区别
|
|
162
|
+
是主体的来源。
|
|
155
163
|
|
|
156
164
|
缺失的 `src` 文件仍会抛出清晰的错误(被转换为 bundler 诊断);
|
|
157
165
|
`src` URL(`https://…`、`data:…`、`//host`)保持原样 —— 它们不是编译期资产,
|
|
158
166
|
永不运行。
|
|
159
167
|
|
|
160
|
-
|
|
161
|
-
永不运行。
|
|
162
|
-
|
|
163
|
-
被包装的脚本体以**它自己的文件**作为其中每条语句的来源(loader 会把该脚本体在生成模块中的
|
|
168
|
+
被包装的 `<script src>` 主体以**它自己的文件**作为其中每条语句的来源(loader 会把该脚本体在生成模块中的
|
|
164
169
|
区间作为 source range 上报),因此诊断会指向 `app.js:12`,而不是 `index.html` 的某一列;
|
|
165
170
|
同时**纯 JavaScript** 脚本与直接 import 的 `.js` 模块一样不做类型检查:在对象字面量上写
|
|
166
|
-
`state.update = …` 不会再报 `TS4003
|
|
171
|
+
`state.update = …` 不会再报 `TS4003`。页面因此可以原样携带已有的脚本。内联主体的
|
|
172
|
+
来源就是 HTML 页面本身。
|
|
167
173
|
|
|
168
174
|
```html
|
|
169
175
|
<button id="b">0</button>
|
|
@@ -288,6 +294,9 @@ Event 的 `target` 是句柄,其描述符(`toString`)与同一 `div#id.cla
|
|
|
288
294
|
通过带记忆化的模块包装函数延迟到 `loadHTML` 求值,因此 import 图能看到
|
|
289
295
|
已解析的文档,且同一模块只实例化一次。缺失文件作为诊断浮现。所有脚本按
|
|
290
296
|
文档顺序运行。e2e 覆盖。
|
|
297
|
+
- **M9c′** ✅ —— 内联 `<script>` 主体走同一套拆分逻辑,因此 `import`(包括
|
|
298
|
+
`node:`/裸说明符)与外链脚本里的链接方式完全一致。此前内联主体被原样包装,
|
|
299
|
+
其 `import` 留在脚本函数体内,codegen 会报 TS5001。
|
|
291
300
|
- **M9d** *(可选)* —— 检测传给 `win.loadHTML(...)` 的模板字面量中的内联
|
|
292
301
|
HTML 并同样转换它们(脆弱;推迟)。
|
|
293
302
|
- **M10 — 打磨** ✅ —— 窗口上的
|
|
@@ -312,10 +321,11 @@ Event 的 `target` 是句柄,其描述符(`toString`)与同一 `div#id.cla
|
|
|
312
321
|
不会运行。已记录。
|
|
313
322
|
- **模板字面量 HTML** 传给 `win.loadHTML(…)` 时在 M9b 中不会被转换(只有
|
|
314
323
|
导入的资产会)。如有需要,M9d 会处理。
|
|
315
|
-
- **外部 `<script src>`
|
|
324
|
+
- **外部 `<script src>` 与内联脚本之间的 import 绑定冲突。** 会被检测并报告
|
|
316
325
|
(给 import 起别名);之后可以做到带引用重写的按脚本重命名。
|
|
317
|
-
- **资产。** `<script src>` 相对 HTML
|
|
318
|
-
|
|
326
|
+
- **资产。** `<script src>` 相对 HTML 资产解析;内联主体的 import 也从同一位置
|
|
327
|
+
解析。URL `src` 值被忽略。加载器不会请求网络 URL;运行时全局 `fetch` 是
|
|
328
|
+
另一套 API。
|
|
319
329
|
|
|
320
330
|
## 测试
|
|
321
331
|
|
|
@@ -326,6 +336,8 @@ Event 的 `target` 是句柄,其描述符(`toString`)与同一 `div#id.cla
|
|
|
326
336
|
- **M9a**:一个假扩展加载器的单元测试,断言 bundler 重写 `*.foo` 并记录依赖。
|
|
327
337
|
- **M9b**:一个带内联 `<script>`、点击时递增计数器的 e2e 用例,通过处理器的
|
|
328
338
|
`console.log` 断言。
|
|
339
|
+
- **M9c′**:单元用例断言内联主体的 import 被提升(相对 import 被延迟),外加
|
|
340
|
+
一个 e2e 用例:内联脚本通过 `node:fs` 读取文件并调用被延迟的辅助模块。
|
|
329
341
|
- **M10**:`requestAnimationFrame`(每帧运行、重新排队、接收时间戳、遵守
|
|
330
342
|
`cancelAnimationFrame`)与 `offsetWidth`/`offsetHeight`/`contains` 的 e2e
|
|
331
343
|
用例。
|
package/doc/zh-CN/gui.md
CHANGED
|
@@ -157,7 +157,12 @@
|
|
|
157
157
|
- `vendor/`(GUI 归档的 SDL3/FreeType/HarfBuzz/glslang,以及 `media` 的 FFmpeg,
|
|
158
158
|
缓慢的部分)按 OS/arch 缓存,以 `scripts/build-gui.ts` /
|
|
159
159
|
`scripts/build-media.ts` 为键。Windows x64 有独立的源码 + FFmpeg 安装前缀
|
|
160
|
-
|
|
160
|
+
缓存;Linux/macOS 上安装前缀 `vendor/ffmpeg-build/dist` 另有以
|
|
161
|
+
`FFMPEG_VERSION` 和 `scripts/build-media.ts`(决定 configure 参数)为键的
|
|
162
|
+
缓存,命中后跳过 FFmpeg 的 configure/make,不必每次重编:脚本会在前缀里
|
|
163
|
+
记录构建它的发布版本,版本或 macOS 部署目标变化时丢弃重建。FFmpeg 发布
|
|
164
|
+
tarball 另有只以 `FFMPEG_VERSION` 为键、所有 job 共享的缓存:即使
|
|
165
|
+
ffmpeg.org 的 TLS 握手不稳定,也不会让已经下载过它的运行失败。
|
|
161
166
|
- Windows x64 在 CI 中构建两个归档并链接一个会触发 `media` 链接特性的 `gui`
|
|
162
167
|
程序(另有一条显式 `--feature media` 的构建);托管 runner
|
|
163
168
|
没有 GPU/Vulkan 驱动,因此 GUI/媒体示例的*运行*仍为试验性(失败只记录
|
|
@@ -182,6 +187,9 @@
|
|
|
182
187
|
相对 import 通过带记忆化的模块包装函数延迟到 `loadHTML` 求值,因此被导入
|
|
183
188
|
模块能看到已解析的文档并共享状态。缺失文件会成为诊断。一切都按文档顺序
|
|
184
189
|
运行。
|
|
190
|
+
- **M9c′** ✅ —— 内联 `<script>` 主体走同一套拆分逻辑,其 import 被提升
|
|
191
|
+
(`node:`/裸说明符像普通模块 import 一样链接),而不是留在被包装的函数
|
|
192
|
+
体内、由 codegen 报 TS5001。内联与外链现在行为一致。
|
|
185
193
|
10. **M10 — 打磨** ✅
|
|
186
194
|
- `win.requestAnimationFrame(fn)` / `win.cancelAnimationFrame(id)`;回调
|
|
187
195
|
在每帧顶部以帧时间戳运行,并可修改 DOM
|
|
@@ -366,6 +374,8 @@
|
|
|
366
374
|
- **M9c** ✅ 外部 `<script src>` 文件被读取,其主体被包装/注册;相对 import
|
|
367
375
|
通过带记忆化的模块包装函数延迟到 `loadHTML`(模块级 DOM 工作因此能看到已解析
|
|
368
376
|
文档);缺失文件会成为诊断。加载器错误被 `loadGraph` 捕获并报告为构建错误。
|
|
377
|
+
- **M9c′** ✅ 内联 `<script>` 主体与外链主体走同一套拆分逻辑,因此内联 `import`
|
|
378
|
+
被提升并同样链接(开启 `node` 扩展后包括 `node:fs`);只有主体来源不同。
|
|
369
379
|
- **M10** ✅ 窗口句柄上的 `requestAnimationFrame`/`cancelAnimationFrame`
|
|
370
380
|
(回调在每帧布局之前以帧时间戳运行),以及元素句柄上的
|
|
371
381
|
`offsetWidth`/`offsetHeight`/`contains`;e2e 覆盖在
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
- 微任务队列(`xt_microtasks`);`xt_promise_ctor/resolve/reject/static`(含 `withResolvers`)、实例 `then` / `catch` / `finally`。
|
|
31
31
|
- `xt_drain_microtasks` 在程序结束时清空队列,事件循环也会在回调之间清空它。
|
|
32
32
|
- `xt_await` 对非 Promise / 已 settle 值排入一次微任务,对 pending promise 则挂起当前 async 协程直到 settle。
|
|
33
|
+
- 未处理的 rejection 是致命错误,与 Node 默认的 `--unhandled-rejections=throw` 一致。一个 reject 后始终无人观察的 promise——没有 `.then` / `.catch`、没有被 `await`、也没有被另一个 promise 采纳——会在事件循环排空后向 stderr 打印 `Unhandled promise rejection`,并以状态码 1 退出。它主要保护入口函数:程序的 `main()` 通常是 `async`,从其中逃出的异常原本只是 reject 一个无人观察的 promise,进程会静默退出 0。即使在定时器里稍后才挂上处理函数,也算已观察。
|
|
33
34
|
|
|
34
35
|
## 定时器与事件循环
|
|
35
36
|
|
|
@@ -21,10 +21,14 @@
|
|
|
21
21
|
|
|
22
22
|
## 延迟求值
|
|
23
23
|
|
|
24
|
-
- `gui` 的 `.html` 资产加载器用合成的 `__xt_deferred_module`
|
|
25
|
-
`<script src>` import。bundler
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
- `gui` 的 `.html` 资产加载器用合成的 `__xt_deferred_module` 绑定标记内联
|
|
25
|
+
`<script>` 主体与 `<script src>` 文件的相对 import。bundler 会把该模块及其
|
|
26
|
+
本地 import 图包装成返回各自导出的函数,生成的脚本在 `loadHTML` 之后调用它们
|
|
27
|
+
(`__xt_defer` 对每个模块做记忆化)。这与浏览器的模块脚本一致:文档就绪后才
|
|
28
|
+
求值 import 图。
|
|
29
|
+
- 两种脚本写法使用同一套拆分逻辑:顶层 `import`/`export … from` 语句被提升进
|
|
30
|
+
生成模块,`export` 修饰符被去掉,因此裸说明符或 `node:` 说明符与普通模块
|
|
31
|
+
import 一样链接。
|
|
28
32
|
- 同时被普通(非标记)import 引用的模块保持立即求值,并获得一个返回已初始化
|
|
29
33
|
导出的薄包装。
|
|
30
34
|
- 包装体是同步的:延迟脚本模块中的顶层 `await` 不受支持。
|
|
@@ -5,16 +5,23 @@
|
|
|
5
5
|
位置:`src/extensions/node/child_process/index.ts`、`runtime/ext_node/child_process/child_process.c`
|
|
6
6
|
|
|
7
7
|
`spawnSync(command, args[, options])` 运行一个程序直到结束,返回
|
|
8
|
-
`{ status, stdout, stderr }`。`options.cwd`
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
`{ status, stdout, stderr }`。`options.cwd` 设置子进程工作目录,`options.env`
|
|
9
|
+
替换子进程的环境变量,`options.stdio: "inherit"` 让子进程共用父进程的
|
|
10
|
+
stdout/stderr(`xbintsc run` 用它把被编译程序的输出实时透传),否则
|
|
11
|
+
stdout/stderr 会作为 UTF-8 字符串捕获。
|
|
11
12
|
|
|
12
13
|
| 选项 | 说明 |
|
|
13
14
|
| --- | --- |
|
|
14
15
|
| `cwd` | 子进程的工作目录 |
|
|
16
|
+
| `env` | 子进程的完整环境变量;不传则继承父进程,想扩展就展开 `process.env` |
|
|
15
17
|
| `stdio: "inherit"` | 共用父进程的 stdout/stderr,而不是捕获 |
|
|
16
18
|
| `encoding` | 接受但忽略(输出始终按 UTF-8 解码) |
|
|
17
19
|
|
|
20
|
+
`env` 遵循 Node 的替换语义:传了对象,它就是子进程的完整环境,调用方没列出的
|
|
21
|
+
变量在子进程里不存在。这正是调用方能把特定的 `SDKROOT`、`INCLUDE`、`LIB` 交给
|
|
22
|
+
工具链、又不泄漏自身 shell 环境的原因;自举出来的编译器跑的就是这段代码,macOS
|
|
23
|
+
的 SDK 修复也依赖它。
|
|
24
|
+
|
|
18
25
|
Windows 上子进程通过 `CreateProcess` 启动,stdout/stderr 由读线程经匿名管道持续排空。
|
|
19
26
|
不使用临时文件,因此受限的 `%TEMP%` 不会让 `spawnSync` 失败,输出超过管道缓冲区时
|
|
20
27
|
也不会死锁。
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
- 运算符辅助:`xt_in`(`in`)、`xt_delete`(`delete`)、`xt_rest_args`(剩余参数 / `arguments`)。
|
|
28
28
|
- Box:`box_new/get/set`(用于闭包捕获变量)。
|
|
29
29
|
- 函数与闭包:`arg`、`closure_new/call/env/arity`。
|
|
30
|
-
- 异常:`xt_try_enter` / `xt_try_exception` / `xt_try_leave` 维护 `_setjmp` 帧栈;`xt_throw` 在存在帧时长跳到最近 `try`,否则打印 `Uncaught ...`
|
|
30
|
+
- 异常:`xt_try_enter` / `xt_try_exception` / `xt_try_leave` 维护 `_setjmp` 帧栈;`xt_throw` 在存在帧时长跳到最近 `try`,否则打印 `Uncaught ...` 后退出。无人观察的 promise rejection 同样是致命的:事件循环排空后 `xt_promise_report_unhandled` 会打印 `Unhandled promise rejection` 与原因,并以状态码 1 退出(见[异步](./async.md))。codegen 还会维护一条影子调用栈(函数名、源文件、行号):`Error.stack` 用它生成堆栈(见[标准库](./stdlib.md)),原生崩溃时致命信号处理器也会打印同一组帧。`--debug` 还会生成 `!DICompileUnit` / `!DISubprogram` / `!DILocation` 元数据,并用 `-g -fno-omit-frame-pointer` 编译,因此 gdb/lldb/WinDbg 可以把指令映射回源码行。
|
|
31
31
|
- 对象 / 函数:`xt_object` 带原型链,`xt_function` 带属性包(静态成员与 `prototype`);`xt_new`(实例化)、`xt_instance_of`(原型链)、`xt_object_freeze/is_frozen/from_entries`;`xt_constructors.c` 保存一等公民构造器缓存、构造器原型与静态值分派。
|
package/doc/zh-CN/npm-package.md
CHANGED
|
@@ -201,8 +201,24 @@ Hello from xbintsc
|
|
|
201
201
|
(不一定是配置文件所在目录);可以用 `xbintsc_CACHE_DIR` 改到别处。这种回退构建
|
|
202
202
|
会明显比后续构建慢。
|
|
203
203
|
|
|
204
|
+
预编译归档由发布机的工具链生成,面向
|
|
205
|
+
[使用前置要求](./requirements.md#支持的平台)中的下限(macOS 11.0、Windows 11、
|
|
206
|
+
glibc 2.39)。如果它比本机的工具链新——例如更新的 Xcode Command Line
|
|
207
|
+
Tools/SDK 或 Visual Studio C++ 生成工具——链接器可能拒绝该归档,报未定义符号
|
|
208
|
+
(`LNK2038`、`LNK2019`、`Undefined symbols`、`undefined reference`)或
|
|
209
|
+
`was built for newer macOS version` 警告。此时驱动会**自动**用包内自带的源码重新
|
|
210
|
+
编译 `core`/`ext_node` 并重试链接,所以归档版本不匹配只会多花时间,不会让构建失败:
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
xbintsc: the prebuilt runtime archive does not match this toolchain (…); compiling the C runtime from source
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
这个回退不会被记住:升级工具链之后,后续构建仍会重新尝试预编译归档。随包的
|
|
217
|
+
`gui.a`/`media.a` 是例外——它们内含 SDL3/FFmpeg,npm 包里没有这些源码,无法这样
|
|
218
|
+
重编。如果冲突的是它们,请使用与本机工具链匹配的发布包,或在源码检出中构建。
|
|
219
|
+
|
|
204
220
|
如果确实想忽略平台包归档、改从主包自带的源码编译 C 运行时(例如修改了
|
|
205
|
-
`runtime
|
|
221
|
+
`runtime/`),可以设置:
|
|
206
222
|
|
|
207
223
|
```bash
|
|
208
224
|
xbintsc_PREFER_PREBUILT=0 npx xbintsc build src/main.ts --out build
|
|
@@ -408,6 +424,7 @@ npm 包通过可选平台包获得同一套预编译运行时,只有在跳过
|
|
|
408
424
|
| 第一次构建很慢 | 可选包 `@xbintsc/<os>-<arch>` 被跳过(或该宿主没有预编译包),正在编译并缓存运行时 C 源码。用 `npm ls @xbintsc/<os>-<arch>` 检查,并去掉 `--omit=optional` 重新安装;`--time` 可确认。 |
|
|
409
425
|
| 写 `.xbintsc/` 权限错误 | 用 `xbintsc_CACHE_DIR` 指向可写目录,或在可写目录中运行。 |
|
|
410
426
|
| `module 'fs' is provided by the 'node' extension` | 加 `--ext node`,或在配置里写 `"extensions": ["node"]`。 |
|
|
427
|
+
| 链接报 `LNK2038`、`LNK2019`、`Undefined symbols` 或 `was built for newer macOS version` | 预编译归档由更新的 Xcode/Visual Studio 工具链构建。驱动会自动改用运行时的 C 源码重试链接;若仍然失败,冲突的是 `gui.a`/`media.a`,无法从 npm 包重编——请使用匹配的发布包或源码检出。 |
|
|
411
428
|
| `GUI native library not found` / `media native library not found` | 携带 `gui.a`/`gui.lib` 或 `media.a`/`media.lib` 的可选平台包被跳过,或该宿主没有预编译的 GUI/media 归档(Windows arm64)。去掉 `--omit=optional` 重新安装,或使用 Linux/macOS/Windows x64 发布压缩包,或从源码检出构建。自动检测到的 `media` 特性缺归档只会 warning;`--feature media` 才会报错。 |
|
|
412
429
|
| `require("xbintsc")` 失败 | 包只提供 ESM;使用 `import`(或动态 `import()`)。 |
|
|
413
430
|
| Windows 链接时报缺少 MSVC 库 | 在 Native Tools 命令提示符中运行,安装 VS C++ 生成工具,并检查 `npx xbintsc doctor`。 |
|