Open History to see the last commit
1import * as NodeChildProcess from "node:child_process";
2import * as NodeFSP from "node:fs/promises";
3import * as NodeOS from "node:os";
4import * as NodePath from "node:path";
5import * as NodeVM from "node:vm";
6import * as NodeURL from "node:url";
7import { build } from "vite-plus/pack";
8import { assert, it } from "vite-plus/test";
9
10import desktopConfig from "../vite.config.ts";
11
12it("keeps lazy Linux imports and worker bundles from executing desktop startup twice", async () => {
13 const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-desktop-bundle-"));
14 try {
15 const workerEntries = [
16 "src/electron/WindowsForegroundFocusWorker.ts",
17 "src/snapShot/GlobalShiftShortcutWorker.ts",
18 "src/snapShot/RegionSnapShotWorker.ts",
19 "src/snapShot/SnapShotAccessibilityWorker.ts",
20 ];
21 await Promise.all([
22 NodeFSP.mkdir(NodePath.join(directory, "src/electron"), { recursive: true }),
23 NodeFSP.mkdir(NodePath.join(directory, "src/snapShot"), { recursive: true }),
24 ]);
25 await Promise.all([
26 NodeFSP.writeFile(
27 NodePath.join(directory, "src/main.ts"),
28 `import { shared } from "./shared.ts";
29process.emit("startup", shared.value);
30void import("./linux.ts").then(({ result }) => process.emit("ready", result));`,
31 ),
32 NodeFSP.writeFile(
33 NodePath.join(directory, "src/shared.ts"),
34 "export const shared = { value: 42 };",
35 ),
36 NodeFSP.writeFile(
37 NodePath.join(directory, "src/linux.ts"),
38 'import { shared } from "./shared.ts"; export const result = shared.value + 1;',
39 ),
40 ...workerEntries.map((entry) =>
41 NodeFSP.writeFile(
42 NodePath.join(directory, entry),
43 'import { shared } from "../shared.ts"; process.emit("worker", shared.value);',
44 ),
45 ),
46 ]);
47 assert.ok(Array.isArray(desktopConfig.pack));
48 const fixtureEntries = new Set(["src/main.ts", ...workerEntries]);
49 for (const packConfig of desktopConfig.pack) {
50 if (!Array.isArray(packConfig.entry)) continue;
51 if (!packConfig.entry.some((entry) => fixtureEntries.has(entry))) continue;
52 await build({
53 ...packConfig,
54 config: false,
55 cwd: directory,
56 tsconfig: false,
57 sourcemap: false,
58 onSuccess: undefined,
59 logLevel: "silent",
60 });
61 }
62
63 const outputDirectory = NodePath.join(directory, "dist-electron");
64 const filenames = (await NodeFSP.readdir(outputDirectory, { recursive: true })).filter(
65 (filename) => filename.endsWith(".cjs"),
66 );
67 const sources = new Map(
68 await Promise.all(
69 filenames.map(async (filename) => {
70 const path = NodePath.join(outputDirectory, filename);
71 return [path, await NodeFSP.readFile(path, "utf8")];
72 }),
73 ),
74 );
75 const modules = new Map();
76 const startups = [];
77 const workers = [];
78 const ready = Promise.withResolvers();
79 const load = (filename, cacheModule = true) => {
80 const cached = modules.get(filename);
81 if (cached) return cached.exports;
82 const module = { exports: {} };
83 if (cacheModule) modules.set(filename, module);
84 const source = sources.get(filename);
85 assert.ok(source, `Missing bundle: ${filename}`);
86 NodeVM.runInNewContext(source, {
87 exports: module.exports,
88 module,
89 require: (specifier) => load(NodePath.resolve(NodePath.dirname(filename), specifier)),
90 process: {
91 emit: (event, value) => {
92 if (event === "startup") startups.push(value);
93 if (event === "worker") workers.push(value);
94 if (event === "ready") ready.resolve(value);
95 },
96 },
97 });
98 return module.exports;
99 };
100
101 load(NodePath.join(outputDirectory, "main.cjs"), false);
102 assert.equal(await ready.promise, 43);
103 assert.deepEqual(startups, [42]);
104 for (const entry of workerEntries) {
105 load(NodePath.join(outputDirectory, entry.replace(/^src\//, "").replace(/\.ts$/, ".cjs")));
106 }
107 assert.deepEqual(workers, [42, 42, 42, 42]);
108 assert.deepEqual(startups, [42]);
109 } finally {
110 await NodeFSP.rm(directory, { recursive: true, force: true });
111 }
112});
113
114it("loads the emitted packaged boot entry and backend cache preload", async () => {
115 const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-desktop-boot-"));
116 try {
117 const entries = ["src/boot.ts", "src/compileCache.ts"];
118 assert.ok(Array.isArray(desktopConfig.pack));
119 for (const packConfig of desktopConfig.pack) {
120 if (!Array.isArray(packConfig.entry)) continue;
121 if (!packConfig.entry.some((entry) => entries.includes(entry))) continue;
122 await build({
123 ...packConfig,
124 entry: packConfig.entry.map((entry) =>
125 NodeURL.fileURLToPath(new URL(`../${entry}`, import.meta.url)),
126 ),
127 outDir: NodePath.join(directory, "dist-electron"),
128 config: false,
129 cwd: directory,
130 tsconfig: false,
131 sourcemap: false,
132 onSuccess: undefined,
133 logLevel: "silent",
134 });
135 }
136 const outputDirectory = NodePath.join(directory, "dist-electron");
137 const fixture = `console.log(require('node:module').getCompileCacheDir() ? 'cached' : 'uncached');`;
138 await NodeFSP.writeFile(NodePath.join(outputDirectory, "main.cjs"), fixture);
139 await NodeFSP.writeFile(
140 NodePath.join(outputDirectory, "backend.mjs"),
141 `import { getCompileCacheDir } from 'node:module'; console.log(getCompileCacheDir() ? 'cached' : 'uncached');`,
142 );
143 for (const disabled of [false, true]) {
144 for (const args of [
145 [NodePath.join(outputDirectory, "boot.cjs")],
146 [
147 "--require",
148 NodePath.join(outputDirectory, "compileCache.cjs"),
149 NodePath.join(outputDirectory, "backend.mjs"),
150 ],
151 ]) {
152 const child = NodeChildProcess.spawnSync(process.execPath, args, {
153 encoding: "utf8",
154 env: {
155 ...process.env,
156 APPIMAGE: "",
157 NODE_COMPILE_CACHE: undefined,
158 NODE_DISABLE_COMPILE_CACHE: disabled ? "1" : undefined,
159 XDG_CACHE_HOME: directory,
160 TMPDIR: directory,
161 TEMP: directory,
162 TMP: directory,
163 },
164 });
165 assert.equal(child.status, 0, child.stderr);
166 assert.equal(child.stdout.trim(), disabled ? "uncached" : "cached");
167 }
168 }
169 } finally {
170 await NodeFSP.rm(directory, { recursive: true, force: true });
171 }
172});