From 998eba2ba88aeaf6f518acf76754e2956dfa9757 Mon Sep 17 00:00:00 2001 From: DrSmoothl <1787882683@qq.com> Date: Thu, 21 May 2026 10:44:08 +0800 Subject: [PATCH] build(ci): wire better-sqlite3 native binding into release artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to 0b6541c. That commit added `better-sqlite3` as a workspace dependency and marked it as a vite external — meaning the bundled `dist/index.mjs` does `require('better-sqlite3')` at runtime instead of inlining its JS wrapper. Without the binding + wrapper present in the production archive, every shipped SnowLuma would crash on first SQLite op. The fix is in three small pieces: 1. `packages/runtime/package.json` — declare `better-sqlite3` as a runtime dep. `vite-plugin-cp` copies this manifest into `dist/package.json` during build (see `runtimeDistFiles` in `packages/core/vite.config.ts`), so the release workflow's existing `npm install --omit=dev` step inside `dist/` picks it up and compiles the native binding for the matrix target via prebuild-install (with node-gyp fallback). This is the same mechanism release.yml has used since v1.x — it was just empty until now because the previous vite config bundled everything. 2. `.github/workflows/dev-build.yml` — mirror the `Bundle runtime dependencies` step from release.yml. Dev-build was packaging `dist/` straight after vite, which would have shipped a broken artifact (no `dist/node_modules/`). Added the `npm install --omit=dev` step before the tar/zip packaging steps so dev-build archives carry the binding too. 3. `package.json` root — add `dist:install` script (just `cd dist && npm install --omit=dev`) so local prod-mimic flows work: `pnpm build && pnpm dist:install && pnpm dev:mode`. Not chained into `pnpm build` itself to keep the watch-cycle fast for users who only need the vite build output; the install step adds ~17s. Note on dev mode: `pnpm dev` continues to work unchanged — it runs via tsx against workspace `node_modules/`, which already has `better-sqlite3` compiled (from the workspace-level pnpm install). Only the dist/-based prod-mimic path needed the explicit install. Verification ------------ - `pnpm build` (with stubbed native binary): clean, dist/ has the updated `dist/package.json` with the dependency declared - `pnpm dist:install`: installs 38 packages, compiles `dist/node_modules/better-sqlite3/build/Release/better_sqlite3.node` - Smoke-test from `dist/`: `node -e "import('better-sqlite3')..."` prints `OK: [ { id: 42 } ]`, confirming the binding loads + a basic INSERT/SELECT roundtrip works. CI matrix coverage: win-x64, linux-x64, linux-arm64 (release.yml + dev-build.yml share the same matrix). Each builds its own native binding during the install step — prebuild-install hits better-sqlite3's prebuilt-binary registry for these three targets (no source compile needed in the common case, falls back to node-gyp if a prebuilt isn't available). --- .github/workflows/dev-build.yml | 11 +++++++++++ package.json | 1 + packages/runtime/package.json | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index a4379937..e09e9a8c 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -110,6 +110,17 @@ jobs: SNOWLUMA_TARGET: ${{ matrix.target }} run: pnpm run build:all + # Materialize `dist/node_modules/` for runtime-only externals + # listed in `packages/runtime/package.json::dependencies` + # (currently: better-sqlite3 — native binding can't be inlined + # by vite). Mirrors the same step in `release.yml`. Runs npm + # (not pnpm) deliberately so the install produces a flat + # `node_modules/` tree with no symlinks, which is what the + # bundled `index.mjs::require('better-sqlite3')` expects. + - name: Bundle runtime dependencies + working-directory: dist + run: npm install --omit=dev + # Naming convention: # SnowLuma-dev-.zip|tar.gz – zero-install (node bundled) # SnowLuma-dev--lite.zip|tar.gz – user provides Node >= 22 diff --git a/package.json b/package.json index 699f5ebb..fbb38960 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "build:webui": "pnpm --filter webui build", "build:all": "pnpm --filter @snowluma/core build:all && pnpm --filter @snowluma/sdk build && pnpm --filter webui build", "dev": "pnpm --filter @snowluma/core dev", + "dist:install": "cd dist && npm install --omit=dev", "dev:mode": "cd dist && cross-env SNOWLUMA_DEV_MODE=1 SNOWLUMA_DEV_WEBUI=1 node index.mjs", "dev:web": "pnpm --filter webui dev", "test": "pnpm --filter @snowluma/core test", diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 3e30cb7a..4b6415e7 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -4,5 +4,8 @@ "private": true, "type": "module", "main": "index.mjs", - "description": "SnowLuma runtime distribution manifest: ships into dist/ (launcher.bat, package.json, native/*.dll, native/*.node). Native libraries are loaded via process.dlopen()." + "description": "SnowLuma runtime distribution manifest: ships into dist/ (launcher.bat, package.json, native/*.dll, native/*.node). vite-plugin-cp copies this package.json into dist/, then the release workflow runs `npm install --omit=dev` inside dist/ to materialize the production node_modules. Dependencies listed here are the runtime-only externals that vite did NOT bundle into index.mjs (currently: better-sqlite3 — native binding, can't be inlined).", + "dependencies": { + "better-sqlite3": "^11.7.0" + } }