Skip to content

Commit 8091c06

Browse files
committed
fix: copy Vite output for production builds
1 parent e027862 commit 8091c06

2 files changed

Lines changed: 111 additions & 18 deletions

File tree

lib/services/bundler/bundler-compiler-service.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,9 @@ export class BundlerCompilerService
126126
}
127127

128128
// Copy Vite output files directly to platform destination
129-
const distOutput = path.join(
130-
projectData.projectDir,
131-
".ns-vite-build",
132-
);
133-
const destDir = path.join(
134-
platformData.appDestinationDirectoryPath,
135-
this.$options.hostProjectModuleName,
129+
const { distOutput, destDir } = this.getViteBuildPaths(
130+
platformData,
131+
projectData,
136132
);
137133

138134
if (debugLog) {
@@ -380,7 +376,18 @@ export class BundlerCompilerService
380376
delete this.bundlerProcesses[platformData.platformNameLowerCase];
381377
const exitCode = typeof arg === "number" ? arg : arg && arg.code;
382378
if (exitCode === 0) {
383-
resolve();
379+
try {
380+
if (this.getBundler() === "vite") {
381+
const { distOutput, destDir } = this.getViteBuildPaths(
382+
platformData,
383+
projectData,
384+
);
385+
this.copyViteBundleToNative(distOutput, destDir, null, true);
386+
}
387+
resolve();
388+
} catch (error) {
389+
reject(error);
390+
}
384391
} else {
385392
const error: any = new Error(
386393
`Executing ${projectData.bundler} failed with exit code ${exitCode}.`,
@@ -845,10 +852,24 @@ export class BundlerCompilerService
845852
return this.$projectConfigService.getValue(`bundler`, "webpack");
846853
}
847854

855+
private getViteBuildPaths(
856+
platformData: IPlatformData,
857+
projectData: IProjectData,
858+
) {
859+
return {
860+
distOutput: path.join(projectData.projectDir, ".ns-vite-build"),
861+
destDir: path.join(
862+
platformData.appDestinationDirectoryPath,
863+
this.$options.hostProjectModuleName,
864+
),
865+
};
866+
}
867+
848868
private copyViteBundleToNative(
849869
distOutput: string,
850870
destDir: string,
851871
specificFiles: string[] = null,
872+
failOnError = false,
852873
) {
853874
// Clean and copy Vite output to native platform folder
854875
if (debugLog) {
@@ -890,23 +911,28 @@ export class BundlerCompilerService
890911
console.log("Full build: Copying all files.");
891912
}
892913

914+
if (!this.$fs.exists(distOutput)) {
915+
throw new Error(
916+
`Vite output directory does not exist: ${distOutput}`,
917+
);
918+
}
919+
893920
// Clean destination directory
894921
if (this.$fs.exists(destDir)) {
895922
this.$fs.deleteDirectory(destDir);
896923
}
897924
this.$fs.createDirectory(destDir);
898925

899926
// Copy all files from dist to platform destination
900-
if (this.$fs.exists(distOutput)) {
901-
this.copyRecursiveSync(distOutput, destDir);
902-
} else {
903-
this.$logger.warn(
904-
`Vite output directory does not exist: ${distOutput}`,
905-
);
906-
}
927+
this.copyRecursiveSync(distOutput, destDir);
907928
}
908929
} catch (error) {
909-
this.$logger.warn(`Failed to copy Vite bundle: ${error.message}`);
930+
const copyError =
931+
error instanceof Error ? error : new Error(String(error));
932+
if (failOnError) {
933+
throw copyError;
934+
}
935+
this.$logger.warn(`Failed to copy Vite bundle: ${copyError.message}`);
910936
}
911937
}
912938

test/services/bundler/bundler-compiler-service.ts

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { assert } from "chai";
44
import { ErrorsStub } from "../../stubs";
55
import { IInjector } from "../../../lib/common/definitions/yok";
66
import { CONFIG_FILE_NAME_DISPLAY } from "../../../lib/constants";
7+
import { EventEmitter } from "events";
8+
import * as path from "path";
79

810
const iOSPlatformName = "ios";
911
const androidPlatformName = "android";
@@ -27,12 +29,14 @@ function createTestInjector(): IInjector {
2729
testInjector.register("childProcess", {});
2830
testInjector.register("hooksService", {});
2931
testInjector.register("hostInfo", {});
30-
testInjector.register("options", {});
32+
testInjector.register("options", { hostProjectModuleName: "app" });
3133
testInjector.register("logger", {});
3234
testInjector.register("errors", ErrorsStub);
3335
testInjector.register("packageInstallationManager", {});
3436
testInjector.register("mobileHelper", {});
35-
testInjector.register("cleanupService", {});
37+
testInjector.register("cleanupService", {
38+
removeKillProcess: async (): Promise<void> => undefined,
39+
});
3640
testInjector.register("projectConfigService", {
3741
getValue: (key: string, defaultValue?: string) => defaultValue,
3842
});
@@ -221,6 +225,69 @@ describe("BundlerCompilerService", () => {
221225
});
222226

223227
describe("compileWithoutWatch", () => {
228+
it("copies a successful Vite build to the native app", async () => {
229+
const childProcess = Object.assign(new EventEmitter(), { pid: 1234 });
230+
const copies: Array<{
231+
distOutput: string;
232+
destDir: string;
233+
failOnError: boolean;
234+
}> = [];
235+
(<any>bundlerCompilerService).startBundleProcess = async () =>
236+
childProcess;
237+
(<any>bundlerCompilerService).copyViteBundleToNative = (
238+
distOutput: string,
239+
destDir: string,
240+
_specificFiles: string[],
241+
failOnError: boolean,
242+
) => {
243+
copies.push({ distOutput, destDir, failOnError });
244+
};
245+
(<any>testInjector.resolve("projectConfigService")).getValue = () =>
246+
"vite";
247+
248+
const compilation = bundlerCompilerService.compileWithoutWatch(
249+
<any>{
250+
platformNameLowerCase: "android",
251+
appDestinationDirectoryPath: "/project/platforms/android",
252+
},
253+
<any>{ projectDir: "/project" },
254+
<any>{},
255+
);
256+
setImmediate(() => childProcess.emit("close", 0));
257+
await compilation;
258+
259+
assert.deepEqual(copies, [
260+
{
261+
distOutput: path.join("/project", ".ns-vite-build"),
262+
destDir: path.join("/project/platforms/android", "app"),
263+
failOnError: true,
264+
},
265+
]);
266+
});
267+
268+
it("fails when a successful Vite build cannot be copied", async () => {
269+
const childProcess = Object.assign(new EventEmitter(), { pid: 1234 });
270+
(<any>bundlerCompilerService).startBundleProcess = async () =>
271+
childProcess;
272+
(<any>bundlerCompilerService).copyViteBundleToNative = () => {
273+
throw new Error("copy failed");
274+
};
275+
(<any>testInjector.resolve("projectConfigService")).getValue = () =>
276+
"vite";
277+
278+
const compilation = bundlerCompilerService.compileWithoutWatch(
279+
<any>{
280+
platformNameLowerCase: "ios",
281+
appDestinationDirectoryPath: "/project/platforms/ios",
282+
},
283+
<any>{ projectDir: "/project" },
284+
<any>{},
285+
);
286+
setImmediate(() => childProcess.emit("close", 0));
287+
288+
await assert.isRejected(compilation, "copy failed");
289+
});
290+
224291
it("fails when the value set for bundlerConfigPath is not existant file", async () => {
225292
const bundlerConfigPath = "some path.js";
226293
testInjector.resolve("fs").exists = (filePath: string) =>

0 commit comments

Comments
 (0)