diff --git a/.changeset/fix-desktop-local-runtime-missing-engine-dist.md b/.changeset/fix-desktop-local-runtime-missing-engine-dist.md new file mode 100644 index 0000000000..6c03775be5 --- /dev/null +++ b/.changeset/fix-desktop-local-runtime-missing-engine-dist.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Fix desktop app crashing on "Local" mode startup with a missing-module error. +category: fix +dev: The desktop build now compiles @fusion/core and @fusion/engine tsc dist (both gitignored) so the packaged embedded Local runtime's `import("@fusion/engine")` resolves. Previously only release.yml's root `pnpm build` produced these; desktop-windows.yml packaged an empty engine/dist and crashed with ERR_MODULE_NOT_FOUND for app.asar/node_modules/@fusion/engine. `@fusion/desktop build` is now self-contained (build.ts → ensureEmbeddedRuntimeBuild), and desktop-windows.yml gained the `pnpm build` parity step. diff --git a/.github/workflows/desktop-windows.yml b/.github/workflows/desktop-windows.yml index be50354685..759497c6b3 100644 --- a/.github/workflows/desktop-windows.yml +++ b/.github/workflows/desktop-windows.yml @@ -22,6 +22,16 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + # FNXC:WindowsDesktopPackaging 2026-07-01-19:45: + # Mirror release.yml: build every workspace package's tsc dist (incl. + # @fusion/core and @fusion/engine, which are gitignored) before packaging. + # Without this the embedded Local runtime's `import("@fusion/engine")` + # resolves to an empty dist and the app crashes with ERR_MODULE_NOT_FOUND. + # `@fusion/desktop build` now also self-builds these, so this is belt-and- + # suspenders parity that additionally covers any other workspace runtime dep. + - name: Build workspace + run: pnpm build + - name: Build desktop package run: pnpm --filter @fusion/desktop build diff --git a/packages/desktop/scripts/build.ts b/packages/desktop/scripts/build.ts index 8dc7ca3e5c..fc68c903f0 100644 --- a/packages/desktop/scripts/build.ts +++ b/packages/desktop/scripts/build.ts @@ -1,7 +1,7 @@ import { build } from "esbuild"; import { cp, mkdir, rm, stat } from "node:fs/promises"; import { join } from "node:path"; -import { buildDashboard, buildDashboardClient, packageRoot, workspaceRoot } from "./workspace-tools"; +import { buildCore, buildDashboard, buildDashboardClient, buildEngine, packageRoot, workspaceRoot } from "./workspace-tools"; const dashboardRoot = join(workspaceRoot, "packages", "dashboard"); const dashboardClientDir = join(dashboardRoot, "dist", "client"); const dashboardRegistryManifestSource = join(dashboardRoot, "src", "registry-manifest.json"); @@ -97,10 +97,27 @@ async function copyDashboardClient(): Promise { await cp(dashboardClientDir, desktopClientDistDir, { recursive: true }); } +// FNXC:DesktopBuild 2026-07-01-19:45: +// Compile the workspace @fusion/* packages the embedded "Local" runtime imports +// at runtime (@fusion/core, @fusion/engine) so `@fusion/desktop build` alone +// produces a complete, packageable tree — no separate root `pnpm build` required. +// engine/dist and core/dist are tsc-emitted + gitignored; without this the +// desktop-windows.yml workflow_dispatch build shipped an empty engine/dist and +// the packaged app crashed on Local mode with ERR_MODULE_NOT_FOUND for +// ...app.asar/node_modules/@fusion/engine. Core must build before engine +// (engine depends on @fusion/core). Dashboard + its runtime plugins + plugin-sdk +// are already built by ensureDashboardBuild(). +async function ensureEmbeddedRuntimeBuild(): Promise { + console.log("[desktop:build] Building @fusion/core and @fusion/engine runtime dist..."); + await buildCore(); + await buildEngine(); +} + async function main(): Promise { await rm(desktopDistDir, { recursive: true, force: true }); await mkdir(desktopDistDir, { recursive: true }); + await ensureEmbeddedRuntimeBuild(); await ensureDashboardBuild(); await buildElectronEntrypoints(); await copyDashboardClient(); diff --git a/packages/desktop/scripts/workspace-tools.ts b/packages/desktop/scripts/workspace-tools.ts index 573675f74f..1b39145c42 100644 --- a/packages/desktop/scripts/workspace-tools.ts +++ b/packages/desktop/scripts/workspace-tools.ts @@ -46,6 +46,18 @@ export async function buildCore(): Promise { await runWorkspaceBin("tsc", [], resolve(workspaceRoot, "packages", "core")); } +// FNXC:DesktopBuild 2026-07-01-19:45: +// The packaged desktop "Local" runtime dynamically imports @fusion/engine +// (local-runtime.ts createDashboardServerDefault). Engine's runtime code is +// tsc-emitted into packages/engine/dist and gitignored, so a workflow that runs +// only `@fusion/desktop build` (e.g. desktop-windows.yml, which lacked the root +// `pnpm build`) shipped an empty engine/dist. The packaged app then crashed on +// Local mode with `ERR_MODULE_NOT_FOUND ...app.asar/node_modules/@fusion/engine`. +// Engine depends on @fusion/core, so callers must build core first. +export async function buildEngine(): Promise { + await runWorkspaceBin("tsc", [], resolve(workspaceRoot, "packages", "engine")); +} + async function buildPackage(relativePath: string): Promise { await runWorkspaceBin("tsc", [], resolve(workspaceRoot, relativePath)); }