From 78d6dcbc25222bdcb16ae770036d99f010a111f5 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Thu, 4 Jun 2026 21:11:07 +0200 Subject: [PATCH 1/2] fix(bundler): copy the vite bundle to native in non-watch builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Vite bundler integration copies its output (`.ns-vite-build/`) into the native project's `assets/app` only from the watch-mode IPC handler in `compileWithWatch` (the `emittedFiles` message). A non-watch build — `ns build`, or `ns run --justlaunch` — runs `compileWithoutWatch`, which has no IPC channel (`startBundleProcess` sets `stdio: "inherit"` when `prepareData.watch` is false) and never calls `copyViteBundleToNative`. The Vite output is therefore left in `.ns-vite-build/`, `assets/app` stays empty, and the Static Binding Generator fails with "Couldn't find sbg-bindings.txt" (no JS input). Webpack/rspack are unaffected — they write directly into the platform folder. Copy the full Vite bundle in `compileWithoutWatch`'s `close` handler on a successful (exit code 0) build, mirroring the full-build branch of the watch-mode copy. --- .../bundler/bundler-compiler-service.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/services/bundler/bundler-compiler-service.ts b/lib/services/bundler/bundler-compiler-service.ts index 3eb880b2ba..38f55f8dfe 100644 --- a/lib/services/bundler/bundler-compiler-service.ts +++ b/lib/services/bundler/bundler-compiler-service.ts @@ -380,6 +380,25 @@ export class BundlerCompilerService delete this.bundlerProcesses[platformData.platformNameLowerCase]; const exitCode = typeof arg === "number" ? arg : arg && arg.code; if (exitCode === 0) { + // In watch mode the Vite output is copied into the native + // project from the `emittedFiles` IPC message. A non-watch + // build (`ns build`, `ns run --justlaunch`) has no IPC + // channel — `startBundleProcess` sets `stdio: "inherit"` + // when `prepareData.watch` is false — so that copy never + // runs and `/.../assets/app` stays empty, leaving + // the Static Binding Generator with no input. Copy the full + // Vite bundle here instead. + if (this.getBundler() === "vite") { + const distOutput = path.join( + projectData.projectDir, + ".ns-vite-build", + ); + const destDir = path.join( + platformData.appDestinationDirectoryPath, + this.$options.hostProjectModuleName, + ); + this.copyViteBundleToNative(distOutput, destDir); + } resolve(); } else { const error: any = new Error( From 76778c7a663573cb7aa5d1a651b429f78f91a4b3 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Thu, 4 Jun 2026 21:47:21 +0200 Subject: [PATCH 2/2] refactor(bundler): extract getVitePaths helper Share the .ns-vite-build / assets-app path computation between the watch-mode emittedFiles copy and the non-watch copy (CodeRabbit review). --- .../bundler/bundler-compiler-service.ts | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/services/bundler/bundler-compiler-service.ts b/lib/services/bundler/bundler-compiler-service.ts index 38f55f8dfe..d870bdc43f 100644 --- a/lib/services/bundler/bundler-compiler-service.ts +++ b/lib/services/bundler/bundler-compiler-service.ts @@ -126,13 +126,9 @@ export class BundlerCompilerService } // Copy Vite output files directly to platform destination - const distOutput = path.join( - projectData.projectDir, - ".ns-vite-build", - ); - const destDir = path.join( - platformData.appDestinationDirectoryPath, - this.$options.hostProjectModuleName, + const { distOutput, destDir } = this.getVitePaths( + platformData, + projectData, ); if (debugLog) { @@ -389,13 +385,9 @@ export class BundlerCompilerService // the Static Binding Generator with no input. Copy the full // Vite bundle here instead. if (this.getBundler() === "vite") { - const distOutput = path.join( - projectData.projectDir, - ".ns-vite-build", - ); - const destDir = path.join( - platformData.appDestinationDirectoryPath, - this.$options.hostProjectModuleName, + const { distOutput, destDir } = this.getVitePaths( + platformData, + projectData, ); this.copyViteBundleToNative(distOutput, destDir); } @@ -864,6 +856,21 @@ export class BundlerCompilerService return this.$projectConfigService.getValue(`bundler`, "webpack"); } + // The Vite output directory and its destination in the native project — + // shared by the watch-mode `emittedFiles` copy and the non-watch copy. + private getVitePaths( + platformData: IPlatformData, + projectData: IProjectData, + ): { distOutput: string; destDir: string } { + return { + distOutput: path.join(projectData.projectDir, ".ns-vite-build"), + destDir: path.join( + platformData.appDestinationDirectoryPath, + this.$options.hostProjectModuleName, + ), + }; + } + private copyViteBundleToNative( distOutput: string, destDir: string,