feat(examples): build flappy-bird as a self-contained single file (#223)
flappy-bird's end goal is a distributable binary; as a stepping stone it
builds a single dist/game.mjs that `node` runs on its own, with no
node_modules present. It's the example that demonstrates that ideal.
Bundle everything that CAN be bundled — vue, chalk, @vue-tui/runtime, yoga's
base64-inlined wasm, the SFC — and externalize ONLY Node builtins:
- The external predicate is `(id) => isBuiltin(id)`, inline in vite.config.ts
(no separate file for a one-liner). It has no relative/absolute path
heuristics, so the Windows path footgun behind vue-tui#209 can't exist here.
- rollupOptions.platform = "node" so rolldown emits a real
createRequire(import.meta.url) for a CJS dep's require() instead of a stub
that throws at startup (stack-utils does `require("module").builtinModules`
at module load — the #212 fault class).
Guard the property that actually matters in examples-smoke: build flappy-bird,
copy ONLY game.mjs into a fresh temp dir with no node_modules, and launch it
there — it must paint. Verified red->green: dropping platform:"node" brings
back the throwing require shim (build-shim check fails) and re-externalizing a
dep is ERR_MODULE_NOT_FOUND in the empty sandbox.
Closes #209. Supersedes #210 (which targeted the now-removed @vue-tui/cli).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { isBuiltin } from "node:module";
|
||||
|
||||
const here = fileURLToPath(new URL(".", import.meta.url));
|
||||
|
||||
// Build the example as a Node ESM bundle. SFCs are compiled by
|
||||
// @vitejs/plugin-vue; runtime deps (vue, @vue-tui/runtime, chalk, …) stay
|
||||
// external so Node resolves them from node_modules at startup.
|
||||
// Build the example as a SELF-CONTAINED Node ESM bundle: a single dist/game.mjs that `node` runs
|
||||
// with no node_modules present (the stepping stone toward a distributable binary). Bundle EVERYTHING
|
||||
// that can be bundled (vue, chalk, @vue-tui/runtime, yoga's base64-inlined wasm, the SFC) and
|
||||
// externalize ONLY Node's own builtins — isBuiltin() matches both "node:fs" and bare "fs". A
|
||||
// builtins-only rule has no relative/absolute path heuristics, so the Windows path footgun behind
|
||||
// vue-tui#209 can't exist here. `platform: "node"` makes rolldown emit a real
|
||||
// createRequire(import.meta.url) for a CJS dep's require() instead of a stub that throws at startup
|
||||
// (stack-utils does `require("module").builtinModules` at module load — the #212 fault class).
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
build: {
|
||||
@@ -19,10 +25,10 @@ export default defineConfig({
|
||||
formats: ["es"],
|
||||
fileName: () => "game.mjs",
|
||||
},
|
||||
rollupOptions: {
|
||||
// Bundle anything resolved as a relative / absolute path (the .vue
|
||||
// file + its `?vue` virtual modules); externalize bare specifiers.
|
||||
external: (id) => !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\0"),
|
||||
// Vite 8 is Rolldown-powered: rolldownOptions is the field (rollupOptions is the deprecated alias).
|
||||
rolldownOptions: {
|
||||
platform: "node",
|
||||
external: (id) => isBuiltin(id),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user