@nasti-toolchain/nasti 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -2
- package/dist/build-CENae4VM.js +748 -0
- package/dist/build-CENae4VM.js.map +1 -0
- package/dist/build-vjh6h7PB.cjs +786 -0
- package/dist/build-vjh6h7PB.cjs.map +1 -0
- package/dist/cli.cjs +166 -7608
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +1 -2
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +166 -7606
- package/dist/cli.js.map +1 -1
- package/dist/client/hmr.cjs +0 -19
- package/dist/client/hmr.d.cts +14 -12
- package/dist/client/hmr.d.cts.map +1 -0
- package/dist/client/hmr.d.ts +14 -12
- package/dist/client/hmr.d.ts.map +1 -0
- package/dist/client/hmr.js +1 -1
- package/dist/dev-engine-DJL9sfv5.cjs +473 -0
- package/dist/dev-engine-DJL9sfv5.cjs.map +1 -0
- package/dist/dev-engine-DapuTPIz.js +469 -0
- package/dist/dev-engine-DapuTPIz.js.map +1 -0
- package/dist/electron-Bj8H-BJ6.js +278 -0
- package/dist/electron-Bj8H-BJ6.js.map +1 -0
- package/dist/electron-D0PSXz-a.cjs +316 -0
- package/dist/electron-D0PSXz-a.cjs.map +1 -0
- package/dist/electron-dev-BzI2IFnR.cjs +272 -0
- package/dist/electron-dev-BzI2IFnR.cjs.map +1 -0
- package/dist/electron-dev-CM15gsFp.js +251 -0
- package/dist/electron-dev-CM15gsFp.js.map +1 -0
- package/dist/env-GY7K1zPK.js +833 -0
- package/dist/env-GY7K1zPK.js.map +1 -0
- package/dist/env-lOj3yw8v.cjs +924 -0
- package/dist/env-lOj3yw8v.cjs.map +1 -0
- package/dist/environment-B2jCrhY2.js +1361 -0
- package/dist/environment-B2jCrhY2.js.map +1 -0
- package/dist/environment-CjmvoHIG.cjs +1443 -0
- package/dist/environment-CjmvoHIG.cjs.map +1 -0
- package/dist/index.cjs +453 -7976
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +872 -817
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +872 -817
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +418 -7939
- package/dist/index.js.map +1 -1
- package/dist/logger-BVZwdqqT.js +116 -0
- package/dist/logger-BVZwdqqT.js.map +1 -0
- package/dist/logger-M7AuVVTV.cjs +171 -0
- package/dist/logger-M7AuVVTV.cjs.map +1 -0
- package/dist/runnable-environment-BjoOvdDa.js +1345 -0
- package/dist/runnable-environment-BjoOvdDa.js.map +1 -0
- package/dist/runnable-environment-ByA3DHQ6.cjs +1351 -0
- package/dist/runnable-environment-ByA3DHQ6.cjs.map +1 -0
- package/dist/server-Bqgl25z0.js +1871 -0
- package/dist/server-Bqgl25z0.js.map +1 -0
- package/dist/server-BynlMdFc.cjs +1895 -0
- package/dist/server-BynlMdFc.cjs.map +1 -0
- package/package.json +20 -10
- package/dist/client/hmr.cjs.map +0 -1
- package/dist/client/hmr.js.map +0 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { a as __exportAll } from "./logger-BVZwdqqT.js";
|
|
2
|
+
import { c as transformReactCode, f as resolveConfig, h as resolveMinifyOption, l as resolvePlugin, n as loadEnv, o as shouldTransform, s as transformCode, t as buildEnvDefine } from "./env-GY7K1zPK.js";
|
|
3
|
+
import { builtinModules, createRequire } from "node:module";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
import { rolldown } from "rolldown";
|
|
8
|
+
//#region src/plugins/electron.ts
|
|
9
|
+
const NODE_BUILTINS = /* @__PURE__ */ new Set([...builtinModules, ...builtinModules.map((m) => `node:${m}`)]);
|
|
10
|
+
const ELECTRON_MODULES = /* @__PURE__ */ new Set([
|
|
11
|
+
"electron",
|
|
12
|
+
"electron/main",
|
|
13
|
+
"electron/common",
|
|
14
|
+
"electron/renderer"
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* Create a Vite/Rollup plugin that externalizes Electron and Node built-in imports according to the resolved config.
|
|
18
|
+
*
|
|
19
|
+
* @param config - Resolved build config; any entries in `config.electron.external` are added to the externalized modules set.
|
|
20
|
+
* @returns A plugin that marks `electron` and `electron/*` imports and Node built-in modules (including `node:`-prefixed names) as external.
|
|
21
|
+
*/
|
|
22
|
+
function electronPlugin(config) {
|
|
23
|
+
const external = /* @__PURE__ */ new Set([
|
|
24
|
+
...ELECTRON_MODULES,
|
|
25
|
+
...NODE_BUILTINS,
|
|
26
|
+
...config.electron.external ?? []
|
|
27
|
+
]);
|
|
28
|
+
return {
|
|
29
|
+
name: "nasti:electron",
|
|
30
|
+
enforce: "pre",
|
|
31
|
+
resolveId(source) {
|
|
32
|
+
if (external.has(source)) return {
|
|
33
|
+
id: source,
|
|
34
|
+
external: true
|
|
35
|
+
};
|
|
36
|
+
if (source.startsWith("electron/")) return {
|
|
37
|
+
id: source,
|
|
38
|
+
external: true
|
|
39
|
+
};
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/build/electron.ts
|
|
46
|
+
var electron_exports = /* @__PURE__ */ __exportAll({
|
|
47
|
+
buildElectron: () => buildElectron,
|
|
48
|
+
createElectronRendererConfig: () => createElectronRendererConfig,
|
|
49
|
+
detectInstalledElectron: () => detectInstalledElectron,
|
|
50
|
+
normalizePreload: () => normalizePreload
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Performs a full Electron build pipeline producing renderer, main, and preload artifacts.
|
|
54
|
+
*
|
|
55
|
+
* Resolves an Electron-targeted config, validates the installed Electron version, prepares the output directory, builds the renderer (via the web build), bundles the main process, bundles configured preload scripts, and logs a summary.
|
|
56
|
+
*
|
|
57
|
+
* @param inlineConfig - Optional config overrides merged into the resolved build configuration
|
|
58
|
+
* @returns An object with `rendererOutDir` (renderer output directory), `mainFile` (bundled main process file path), and `preloadFiles` (array of bundled preload file paths)
|
|
59
|
+
* @throws Error if the configured Electron main entry file does not exist
|
|
60
|
+
*/
|
|
61
|
+
async function buildElectron(inlineConfig = {}) {
|
|
62
|
+
const config = await resolveConfig({
|
|
63
|
+
...inlineConfig,
|
|
64
|
+
target: "electron"
|
|
65
|
+
}, "build");
|
|
66
|
+
const startTime = performance.now();
|
|
67
|
+
assertElectronVersion(config);
|
|
68
|
+
console.log(pc.cyan("\n⚡ nasti build (electron)") + pc.dim(` v2.5.2`));
|
|
69
|
+
console.log(pc.dim(` root: ${config.root}`));
|
|
70
|
+
console.log(pc.dim(` mode: ${config.mode}`));
|
|
71
|
+
console.log(pc.dim(` target: electron (≥ ${config.electron.minVersion})`));
|
|
72
|
+
const outDir = path.resolve(config.root, config.build.outDir);
|
|
73
|
+
if (config.build.emptyOutDir && fs.existsSync(outDir)) fs.rmSync(outDir, {
|
|
74
|
+
recursive: true,
|
|
75
|
+
force: true
|
|
76
|
+
});
|
|
77
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
78
|
+
const rendererOutDir = path.join(outDir, "renderer");
|
|
79
|
+
const { build } = await import("./build-CENae4VM.js").then((n) => n.n);
|
|
80
|
+
await build(createElectronRendererConfig(config, inlineConfig, { build: {
|
|
81
|
+
...inlineConfig.build,
|
|
82
|
+
outDir: rendererOutDir,
|
|
83
|
+
emptyOutDir: false
|
|
84
|
+
} }));
|
|
85
|
+
const mainEntry = path.resolve(config.root, config.electron.main);
|
|
86
|
+
if (!fs.existsSync(mainEntry)) throw new Error(`Electron main entry not found: ${config.electron.main}\n在 nasti.config.ts 的 electron.main 指定主进程入口文件。`);
|
|
87
|
+
const mainFile = await bundleNode(config, mainEntry, {
|
|
88
|
+
outFile: outFileName(outDir, "main", config.electron.mainFormat),
|
|
89
|
+
format: config.electron.mainFormat,
|
|
90
|
+
label: "main"
|
|
91
|
+
});
|
|
92
|
+
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
93
|
+
const preloadFiles = [];
|
|
94
|
+
for (const entry of preloadEntries) {
|
|
95
|
+
if (!fs.existsSync(entry)) {
|
|
96
|
+
console.warn(pc.yellow(` ⚠ preload entry not found, skipped: ${entry}`));
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const base = path.basename(entry).replace(/\.[^.]+$/, "");
|
|
100
|
+
const out = outFileName(outDir, base, config.electron.preloadFormat);
|
|
101
|
+
await bundleNode(config, entry, {
|
|
102
|
+
outFile: out,
|
|
103
|
+
format: config.electron.preloadFormat,
|
|
104
|
+
label: `preload (${base})`
|
|
105
|
+
});
|
|
106
|
+
preloadFiles.push(out);
|
|
107
|
+
}
|
|
108
|
+
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
109
|
+
console.log(pc.green(`\n✓ Electron build complete in ${elapsed}s`));
|
|
110
|
+
console.log(pc.dim(` renderer: ${path.relative(config.root, rendererOutDir)}/`));
|
|
111
|
+
console.log(pc.dim(` main: ${path.relative(config.root, mainFile)}`));
|
|
112
|
+
for (const pf of preloadFiles) console.log(pc.dim(` preload: ${path.relative(config.root, pf)}`));
|
|
113
|
+
console.log();
|
|
114
|
+
return {
|
|
115
|
+
rendererOutDir,
|
|
116
|
+
mainFile,
|
|
117
|
+
preloadFiles
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Bundles a Node-targeted entry for Electron into a single output file using Rolldown and the OXC transform.
|
|
122
|
+
*
|
|
123
|
+
* @param config - Fully resolved build configuration used to drive transforms, defines, plugins, and output options
|
|
124
|
+
* @param entry - Absolute path to the entry file to bundle
|
|
125
|
+
* @param opts - Bundle options; expects `outFile` (destination path), `format` (`'cjs'` or `'esm'`), and `label` (human-readable name for logging)
|
|
126
|
+
* @returns The path to the written bundle file (`opts.outFile`)
|
|
127
|
+
*/
|
|
128
|
+
async function bundleNode(config, entry, opts) {
|
|
129
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
130
|
+
const envDefine = {
|
|
131
|
+
...buildEnvDefine(env, config.mode),
|
|
132
|
+
__ELECTRON__: "true",
|
|
133
|
+
__NASTI_TARGET__: JSON.stringify("electron")
|
|
134
|
+
};
|
|
135
|
+
const oxcTransformPlugin = {
|
|
136
|
+
name: "nasti:oxc-transform",
|
|
137
|
+
async transform(code, id) {
|
|
138
|
+
const result = config.framework === "react" ? await transformReactCode(id, code, {
|
|
139
|
+
react: config.react,
|
|
140
|
+
consumer: "server",
|
|
141
|
+
development: config.mode === "development",
|
|
142
|
+
sourcemap: !!config.build.sourcemap,
|
|
143
|
+
target: config.electron.nodeTarget,
|
|
144
|
+
onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
|
|
145
|
+
}) : shouldTransform(id) ? transformCode(id, code, {
|
|
146
|
+
sourcemap: !!config.build.sourcemap,
|
|
147
|
+
jsxRuntime: "automatic",
|
|
148
|
+
jsxImportSource: "vue",
|
|
149
|
+
target: config.electron.nodeTarget
|
|
150
|
+
}) : null;
|
|
151
|
+
if (!result) return null;
|
|
152
|
+
return {
|
|
153
|
+
code: result.code,
|
|
154
|
+
map: result.map ? JSON.parse(result.map) : void 0
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
|
|
159
|
+
const mergedDefine = {
|
|
160
|
+
...userTransform?.define ?? {},
|
|
161
|
+
...envDefine
|
|
162
|
+
};
|
|
163
|
+
const bundle = await rolldown({
|
|
164
|
+
...restInputOptions,
|
|
165
|
+
input: entry,
|
|
166
|
+
platform: "node",
|
|
167
|
+
transform: {
|
|
168
|
+
...userTransform,
|
|
169
|
+
target: config.electron.nodeTarget,
|
|
170
|
+
define: mergedDefine
|
|
171
|
+
},
|
|
172
|
+
plugins: [
|
|
173
|
+
oxcTransformPlugin,
|
|
174
|
+
electronPlugin(config),
|
|
175
|
+
resolvePlugin(config)
|
|
176
|
+
]
|
|
177
|
+
});
|
|
178
|
+
fs.mkdirSync(path.dirname(opts.outFile), { recursive: true });
|
|
179
|
+
await bundle.write({
|
|
180
|
+
sourcemap: !!config.build.sourcemap,
|
|
181
|
+
minify: resolveMinifyOption(config.build.minify),
|
|
182
|
+
...userOutput,
|
|
183
|
+
file: opts.outFile,
|
|
184
|
+
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
185
|
+
codeSplitting: false
|
|
186
|
+
});
|
|
187
|
+
await bundle.close();
|
|
188
|
+
console.log(pc.dim(` ✓ ${opts.label} → ${path.relative(config.root, opts.outFile)}`));
|
|
189
|
+
return opts.outFile;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 从 Electron 配置派生 renderer 的普通 Web 构建配置。
|
|
193
|
+
*
|
|
194
|
+
* renderer 使用指定 HTML 入口;本地文件加载场景默认把 `/` base 收敛为
|
|
195
|
+
* `./`,避免产物中的 `/assets/*` 被解析到文件系统根目录。
|
|
196
|
+
*/
|
|
197
|
+
function createElectronRendererConfig(config, inlineConfig = {}, overrides = {}) {
|
|
198
|
+
const inlineClient = inlineConfig.environments?.client ?? {};
|
|
199
|
+
return {
|
|
200
|
+
...inlineConfig,
|
|
201
|
+
...overrides,
|
|
202
|
+
root: config.root,
|
|
203
|
+
mode: config.mode,
|
|
204
|
+
target: "web",
|
|
205
|
+
framework: config.framework,
|
|
206
|
+
base: config.base === "/" ? "./" : config.base,
|
|
207
|
+
environments: {
|
|
208
|
+
...inlineConfig.environments ?? {},
|
|
209
|
+
client: {
|
|
210
|
+
...inlineClient,
|
|
211
|
+
html: config.electron.renderer
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Compute an output file path for a given base name and module format.
|
|
218
|
+
*
|
|
219
|
+
* @param outDir - Directory where the output file will be placed
|
|
220
|
+
* @param base - Base filename without extension
|
|
221
|
+
* @param format - Module format; `cjs` yields a `.cjs` extension, `esm` yields a `.mjs` extension
|
|
222
|
+
* @returns The resolved file path combining `outDir` and `base` with the appropriate extension
|
|
223
|
+
*/
|
|
224
|
+
function outFileName(outDir, base, format) {
|
|
225
|
+
const ext = format === "cjs" ? ".cjs" : ".mjs";
|
|
226
|
+
return path.join(outDir, base + ext);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Normalize Electron preload entries into absolute file paths.
|
|
230
|
+
*
|
|
231
|
+
* @param preload - A single preload path or an array of preload paths; a falsy value produces an empty list
|
|
232
|
+
* @param root - Root directory used to resolve relative preload entries
|
|
233
|
+
* @returns An array of absolute file paths for each preload entry
|
|
234
|
+
*/
|
|
235
|
+
function normalizePreload(preload, root) {
|
|
236
|
+
return (Array.isArray(preload) ? preload : preload ? [preload] : []).map((p) => path.resolve(root, p));
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Warns when the detected Electron major version is lower than the configured minimum.
|
|
240
|
+
*
|
|
241
|
+
* Checks the project for an installed Electron package and, if its major version
|
|
242
|
+
* is less than `config.electron.minVersion`, logs a yellow warning describing the mismatch.
|
|
243
|
+
*
|
|
244
|
+
* @param config - Resolved build configuration that contains `electron.minVersion` and project `root`
|
|
245
|
+
*/
|
|
246
|
+
function assertElectronVersion(config) {
|
|
247
|
+
const min = config.electron.minVersion;
|
|
248
|
+
const installed = detectInstalledElectron(config.root);
|
|
249
|
+
if (installed && installed < min) console.warn(pc.yellow(` ⚠ 检测到 Electron ${installed},Nasti 要求 ≥ ${min}。旧版本可能缺少 ESM 主进程支持。`));
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Detects the installed Electron major version in the given project root.
|
|
253
|
+
*
|
|
254
|
+
* @param root - Project root directory used to locate electron via Node resolution
|
|
255
|
+
* @returns The major Electron version as a number, or `null` if Electron is not installed or the version cannot be determined
|
|
256
|
+
*/
|
|
257
|
+
function detectInstalledElectron(root) {
|
|
258
|
+
try {
|
|
259
|
+
const pkgPath = createRequire(path.resolve(root, "package.json")).resolve("electron/package.json");
|
|
260
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
261
|
+
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
262
|
+
return Number.isFinite(major) ? major : null;
|
|
263
|
+
} catch {
|
|
264
|
+
try {
|
|
265
|
+
const pkgPath = path.resolve(root, "node_modules/electron/package.json");
|
|
266
|
+
if (!fs.existsSync(pkgPath)) return null;
|
|
267
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
268
|
+
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
269
|
+
return Number.isFinite(major) ? major : null;
|
|
270
|
+
} catch {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
//#endregion
|
|
276
|
+
export { normalizePreload as a, electron_exports as i, createElectronRendererConfig as n, electronPlugin as o, detectInstalledElectron as r, buildElectron as t };
|
|
277
|
+
|
|
278
|
+
//# sourceMappingURL=electron-Bj8H-BJ6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electron-Bj8H-BJ6.js","names":[],"sources":["../src/plugins/electron.ts","../src/build/electron.ts"],"sourcesContent":["// Electron 内置插件\n//\n// 负责:将 Electron 模块(electron、electron/*)与 Node 内建模块(fs、path、...)\n// 标记为 external,避免被打包进主进程/Preload 产物。\n//\n// 仅在 config.target === 'electron' 时启用\nimport { builtinModules } from 'node:module'\nimport type { NastiPlugin, ResolvedConfig } from '../types.js'\n\nconst NODE_BUILTINS = new Set([\n ...builtinModules,\n ...builtinModules.map((m) => `node:${m}`),\n])\n\nconst ELECTRON_MODULES = new Set([\n 'electron',\n 'electron/main',\n 'electron/common',\n 'electron/renderer',\n])\n\n/**\n * Create a Vite/Rollup plugin that externalizes Electron and Node built-in imports according to the resolved config.\n *\n * @param config - Resolved build config; any entries in `config.electron.external` are added to the externalized modules set.\n * @returns A plugin that marks `electron` and `electron/*` imports and Node built-in modules (including `node:`-prefixed names) as external.\n */\nexport function electronPlugin(config: ResolvedConfig): NastiPlugin {\n const external = new Set([\n ...ELECTRON_MODULES,\n ...NODE_BUILTINS,\n ...(config.electron.external ?? []),\n ])\n\n return {\n name: 'nasti:electron',\n enforce: 'pre',\n\n resolveId(source) {\n // 显式外部化 electron 与 Node 内建模块\n if (external.has(source)) {\n return { id: source, external: true }\n }\n // 形如 `electron/xxx` 的子路径一律标记外部\n if (source.startsWith('electron/')) {\n return { id: source, external: true }\n }\n return null\n },\n }\n}\n","// Electron 构建入口\n//\n// 流水线:\n// 1. 渲染进程(Web)构建 —— 复用现有 build() 流水线,输出到 outDir/renderer\n// 2. 主进程构建 —— 独立 Rolldown,target=node22,external=electron+内建模块\n// 3. Preload 构建 —— 独立 Rolldown,默认 cjs,contextIsolation 友好\n//\n// 产物目录结构(默认):\n// dist/\n// ├── renderer/ Web 渲染层,与 nasti build 一致\n// ├── main.{cjs,mjs}\n// └── preload.{cjs,mjs}\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { rolldown } from 'rolldown'\nimport pc from 'picocolors'\nimport type { NastiConfig, ResolvedConfig } from '../types.js'\nimport { resolveConfig } from '../config/index.js'\nimport { resolvePlugin } from '../plugins/resolve.js'\nimport { electronPlugin } from '../plugins/electron.js'\nimport { transformCode, transformReactCode, shouldTransform } from '../core/transformer.js'\nimport { loadEnv, buildEnvDefine } from '../core/env.js'\nimport { resolveMinifyOption } from '../core/minify.js'\n\nexport interface ElectronBuildResult {\n rendererOutDir: string\n mainFile: string\n preloadFiles: string[]\n}\n\n/**\n * Performs a full Electron build pipeline producing renderer, main, and preload artifacts.\n *\n * Resolves an Electron-targeted config, validates the installed Electron version, prepares the output directory, builds the renderer (via the web build), bundles the main process, bundles configured preload scripts, and logs a summary.\n *\n * @param inlineConfig - Optional config overrides merged into the resolved build configuration\n * @returns An object with `rendererOutDir` (renderer output directory), `mainFile` (bundled main process file path), and `preloadFiles` (array of bundled preload file paths)\n * @throws Error if the configured Electron main entry file does not exist\n */\nexport async function buildElectron(inlineConfig: NastiConfig = {}): Promise<ElectronBuildResult> {\n const config = await resolveConfig({ ...inlineConfig, target: 'electron' }, 'build')\n const startTime = performance.now()\n\n assertElectronVersion(config)\n\n console.log(pc.cyan('\\n⚡ nasti build (electron)') + pc.dim(` v${__NASTI_VERSION__}`))\n console.log(pc.dim(` root: ${config.root}`))\n console.log(pc.dim(` mode: ${config.mode}`))\n console.log(pc.dim(` target: electron (≥ ${config.electron.minVersion})`))\n\n const outDir = path.resolve(config.root, config.build.outDir)\n if (config.build.emptyOutDir && fs.existsSync(outDir)) {\n fs.rmSync(outDir, { recursive: true, force: true })\n }\n fs.mkdirSync(outDir, { recursive: true })\n\n // ---- 1. 渲染进程(复用 Web 构建)----\n const rendererOutDir = path.join(outDir, 'renderer')\n const { build } = await import('./index.js')\n await build(createElectronRendererConfig(config, inlineConfig, {\n build: {\n ...inlineConfig.build,\n outDir: rendererOutDir,\n emptyOutDir: false,\n },\n }))\n\n // ---- 2. 主进程 ----\n const mainEntry = path.resolve(config.root, config.electron.main)\n if (!fs.existsSync(mainEntry)) {\n throw new Error(\n `Electron main entry not found: ${config.electron.main}\\n` +\n `在 nasti.config.ts 的 electron.main 指定主进程入口文件。`,\n )\n }\n const mainFile = await bundleNode(config, mainEntry, {\n outFile: outFileName(outDir, 'main', config.electron.mainFormat),\n format: config.electron.mainFormat,\n label: 'main',\n })\n\n // ---- 3. Preload ----\n const preloadEntries = normalizePreload(config.electron.preload, config.root)\n const preloadFiles: string[] = []\n for (const entry of preloadEntries) {\n if (!fs.existsSync(entry)) {\n console.warn(pc.yellow(` ⚠ preload entry not found, skipped: ${entry}`))\n continue\n }\n const base = path.basename(entry).replace(/\\.[^.]+$/, '')\n const out = outFileName(outDir, base, config.electron.preloadFormat)\n await bundleNode(config, entry, {\n outFile: out,\n format: config.electron.preloadFormat,\n label: `preload (${base})`,\n })\n preloadFiles.push(out)\n }\n\n const elapsed = ((performance.now() - startTime) / 1000).toFixed(2)\n console.log(pc.green(`\\n✓ Electron build complete in ${elapsed}s`))\n console.log(pc.dim(` renderer: ${path.relative(config.root, rendererOutDir)}/`))\n console.log(pc.dim(` main: ${path.relative(config.root, mainFile)}`))\n for (const pf of preloadFiles) {\n console.log(pc.dim(` preload: ${path.relative(config.root, pf)}`))\n }\n console.log()\n\n return { rendererOutDir, mainFile, preloadFiles }\n}\n\ninterface BundleNodeOptions {\n outFile: string\n format: 'cjs' | 'esm'\n label: string\n}\n\n/**\n * Bundles a Node-targeted entry for Electron into a single output file using Rolldown and the OXC transform.\n *\n * @param config - Fully resolved build configuration used to drive transforms, defines, plugins, and output options\n * @param entry - Absolute path to the entry file to bundle\n * @param opts - Bundle options; expects `outFile` (destination path), `format` (`'cjs'` or `'esm'`), and `label` (human-readable name for logging)\n * @returns The path to the written bundle file (`opts.outFile`)\n */\nasync function bundleNode(\n config: ResolvedConfig,\n entry: string,\n opts: BundleNodeOptions,\n): Promise<string> {\n const env = loadEnv(config.mode, config.root, config.envPrefix)\n const envDefine = {\n ...buildEnvDefine(env, config.mode),\n __ELECTRON__: 'true',\n __NASTI_TARGET__: JSON.stringify('electron'),\n }\n\n const oxcTransformPlugin = {\n name: 'nasti:oxc-transform',\n async transform(code: string, id: string) {\n const result = config.framework === 'react'\n ? await transformReactCode(id, code, {\n react: config.react,\n consumer: 'server',\n development: config.mode === 'development',\n sourcemap: !!config.build.sourcemap,\n target: config.electron.nodeTarget,\n onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`),\n })\n : shouldTransform(id)\n ? transformCode(id, code, {\n sourcemap: !!config.build.sourcemap,\n jsxRuntime: 'automatic',\n jsxImportSource: 'vue',\n target: config.electron.nodeTarget,\n })\n : null\n if (!result) return null\n return { code: result.code, map: result.map ? JSON.parse(result.map) : undefined }\n },\n }\n\n // 从 build.rolldownOptions 拆出 output(合并进 bundle.write())与 transform\n // (需与 envDefine 合并),其余 input 选项(treeshake 等)随 restInputOptions 透传。\n // Nasti 自管的 input / platform / transform / plugins 放在 spread 之后确保覆盖。\n const { output: userOutput, transform: userTransform, ...restInputOptions } =\n config.build.rolldownOptions\n // 合并用户的 transform.define 和 envDefine,确保 envDefine 优先级更高\n const mergedDefine = { ...(userTransform?.define ?? {}), ...envDefine }\n const bundle = await rolldown({\n ...restInputOptions,\n input: entry,\n platform: 'node',\n transform: {\n ...userTransform,\n target: config.electron.nodeTarget,\n define: mergedDefine,\n },\n plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)] as any,\n })\n\n fs.mkdirSync(path.dirname(opts.outFile), { recursive: true })\n\n await bundle.write({\n sourcemap: !!config.build.sourcemap,\n minify: resolveMinifyOption(config.build.minify),\n // 允许用户微调 output;但主进程 / preload 的单文件约束由下方键强制保证\n ...userOutput,\n file: opts.outFile,\n format: opts.format === 'cjs' ? 'cjs' : 'esm',\n codeSplitting: false,\n })\n\n await bundle.close()\n\n console.log(pc.dim(` ✓ ${opts.label} → ${path.relative(config.root, opts.outFile)}`))\n return opts.outFile\n}\n\n/**\n * 从 Electron 配置派生 renderer 的普通 Web 构建配置。\n *\n * renderer 使用指定 HTML 入口;本地文件加载场景默认把 `/` base 收敛为\n * `./`,避免产物中的 `/assets/*` 被解析到文件系统根目录。\n */\nexport function createElectronRendererConfig(\n config: ResolvedConfig,\n inlineConfig: NastiConfig = {},\n overrides: Pick<NastiConfig, 'build'> = {},\n): NastiConfig {\n const inlineClient = inlineConfig.environments?.client ?? {}\n return {\n ...inlineConfig,\n ...overrides,\n root: config.root,\n mode: config.mode,\n target: 'web',\n framework: config.framework,\n base: config.base === '/' ? './' : config.base,\n environments: {\n ...(inlineConfig.environments ?? {}),\n client: {\n ...inlineClient,\n html: config.electron.renderer,\n },\n },\n }\n}\n\n/**\n * Compute an output file path for a given base name and module format.\n *\n * @param outDir - Directory where the output file will be placed\n * @param base - Base filename without extension\n * @param format - Module format; `cjs` yields a `.cjs` extension, `esm` yields a `.mjs` extension\n * @returns The resolved file path combining `outDir` and `base` with the appropriate extension\n */\nfunction outFileName(outDir: string, base: string, format: 'cjs' | 'esm'): string {\n const ext = format === 'cjs' ? '.cjs' : '.mjs'\n return path.join(outDir, base + ext)\n}\n\n/**\n * Normalize Electron preload entries into absolute file paths.\n *\n * @param preload - A single preload path or an array of preload paths; a falsy value produces an empty list\n * @param root - Root directory used to resolve relative preload entries\n * @returns An array of absolute file paths for each preload entry\n */\nexport function normalizePreload(preload: string | string[] | undefined, root: string): string[] {\n const list = Array.isArray(preload) ? preload : preload ? [preload] : []\n return list.map((p) => path.resolve(root, p))\n}\n\n/**\n * Warns when the detected Electron major version is lower than the configured minimum.\n *\n * Checks the project for an installed Electron package and, if its major version\n * is less than `config.electron.minVersion`, logs a yellow warning describing the mismatch.\n *\n * @param config - Resolved build configuration that contains `electron.minVersion` and project `root`\n */\nfunction assertElectronVersion(config: ResolvedConfig): void {\n const min = config.electron.minVersion\n const installed = detectInstalledElectron(config.root)\n if (installed && installed < min) {\n console.warn(\n pc.yellow(\n ` ⚠ 检测到 Electron ${installed},Nasti 要求 ≥ ${min}。旧版本可能缺少 ESM 主进程支持。`,\n ),\n )\n }\n}\n\n/**\n * Detects the installed Electron major version in the given project root.\n *\n * @param root - Project root directory used to locate electron via Node resolution\n * @returns The major Electron version as a number, or `null` if Electron is not installed or the version cannot be determined\n */\nexport function detectInstalledElectron(root: string): number | null {\n try {\n // Node resolution handles pnpm/yarn symlink layouts; plain path join is a\n // fallback for installers that still flatten electron under node_modules.\n const require = createRequire(path.resolve(root, 'package.json'))\n const pkgPath = require.resolve('electron/package.json')\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n const major = parseInt(String(pkg.version).split('.')[0], 10)\n return Number.isFinite(major) ? major : null\n } catch {\n try {\n const pkgPath = path.resolve(root, 'node_modules/electron/package.json')\n if (!fs.existsSync(pkgPath)) return null\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n const major = parseInt(String(pkg.version).split('.')[0], 10)\n return Number.isFinite(major) ? major : null\n } catch {\n return null\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
const require_logger = require("./logger-M7AuVVTV.cjs");
|
|
2
|
+
const require_env = require("./env-lOj3yw8v.cjs");
|
|
3
|
+
let node_path = require("node:path");
|
|
4
|
+
node_path = require_logger.__toESM(node_path, 1);
|
|
5
|
+
let node_fs = require("node:fs");
|
|
6
|
+
node_fs = require_logger.__toESM(node_fs, 1);
|
|
7
|
+
let picocolors = require("picocolors");
|
|
8
|
+
picocolors = require_logger.__toESM(picocolors, 1);
|
|
9
|
+
let node_module = require("node:module");
|
|
10
|
+
let rolldown = require("rolldown");
|
|
11
|
+
//#region src/plugins/electron.ts
|
|
12
|
+
const NODE_BUILTINS = /* @__PURE__ */ new Set([...node_module.builtinModules, ...node_module.builtinModules.map((m) => `node:${m}`)]);
|
|
13
|
+
const ELECTRON_MODULES = /* @__PURE__ */ new Set([
|
|
14
|
+
"electron",
|
|
15
|
+
"electron/main",
|
|
16
|
+
"electron/common",
|
|
17
|
+
"electron/renderer"
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Create a Vite/Rollup plugin that externalizes Electron and Node built-in imports according to the resolved config.
|
|
21
|
+
*
|
|
22
|
+
* @param config - Resolved build config; any entries in `config.electron.external` are added to the externalized modules set.
|
|
23
|
+
* @returns A plugin that marks `electron` and `electron/*` imports and Node built-in modules (including `node:`-prefixed names) as external.
|
|
24
|
+
*/
|
|
25
|
+
function electronPlugin(config) {
|
|
26
|
+
const external = /* @__PURE__ */ new Set([
|
|
27
|
+
...ELECTRON_MODULES,
|
|
28
|
+
...NODE_BUILTINS,
|
|
29
|
+
...config.electron.external ?? []
|
|
30
|
+
]);
|
|
31
|
+
return {
|
|
32
|
+
name: "nasti:electron",
|
|
33
|
+
enforce: "pre",
|
|
34
|
+
resolveId(source) {
|
|
35
|
+
if (external.has(source)) return {
|
|
36
|
+
id: source,
|
|
37
|
+
external: true
|
|
38
|
+
};
|
|
39
|
+
if (source.startsWith("electron/")) return {
|
|
40
|
+
id: source,
|
|
41
|
+
external: true
|
|
42
|
+
};
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/build/electron.ts
|
|
49
|
+
var electron_exports = /* @__PURE__ */ require_logger.__exportAll({
|
|
50
|
+
buildElectron: () => buildElectron,
|
|
51
|
+
createElectronRendererConfig: () => createElectronRendererConfig,
|
|
52
|
+
detectInstalledElectron: () => detectInstalledElectron,
|
|
53
|
+
normalizePreload: () => normalizePreload
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Performs a full Electron build pipeline producing renderer, main, and preload artifacts.
|
|
57
|
+
*
|
|
58
|
+
* Resolves an Electron-targeted config, validates the installed Electron version, prepares the output directory, builds the renderer (via the web build), bundles the main process, bundles configured preload scripts, and logs a summary.
|
|
59
|
+
*
|
|
60
|
+
* @param inlineConfig - Optional config overrides merged into the resolved build configuration
|
|
61
|
+
* @returns An object with `rendererOutDir` (renderer output directory), `mainFile` (bundled main process file path), and `preloadFiles` (array of bundled preload file paths)
|
|
62
|
+
* @throws Error if the configured Electron main entry file does not exist
|
|
63
|
+
*/
|
|
64
|
+
async function buildElectron(inlineConfig = {}) {
|
|
65
|
+
const config = await require_env.resolveConfig({
|
|
66
|
+
...inlineConfig,
|
|
67
|
+
target: "electron"
|
|
68
|
+
}, "build");
|
|
69
|
+
const startTime = performance.now();
|
|
70
|
+
assertElectronVersion(config);
|
|
71
|
+
console.log(picocolors.default.cyan("\n⚡ nasti build (electron)") + picocolors.default.dim(` v2.5.2`));
|
|
72
|
+
console.log(picocolors.default.dim(` root: ${config.root}`));
|
|
73
|
+
console.log(picocolors.default.dim(` mode: ${config.mode}`));
|
|
74
|
+
console.log(picocolors.default.dim(` target: electron (≥ ${config.electron.minVersion})`));
|
|
75
|
+
const outDir = node_path.default.resolve(config.root, config.build.outDir);
|
|
76
|
+
if (config.build.emptyOutDir && node_fs.default.existsSync(outDir)) node_fs.default.rmSync(outDir, {
|
|
77
|
+
recursive: true,
|
|
78
|
+
force: true
|
|
79
|
+
});
|
|
80
|
+
node_fs.default.mkdirSync(outDir, { recursive: true });
|
|
81
|
+
const rendererOutDir = node_path.default.join(outDir, "renderer");
|
|
82
|
+
const { build } = await Promise.resolve().then(() => require("./build-vjh6h7PB.cjs")).then((n) => n.build_exports);
|
|
83
|
+
await build(createElectronRendererConfig(config, inlineConfig, { build: {
|
|
84
|
+
...inlineConfig.build,
|
|
85
|
+
outDir: rendererOutDir,
|
|
86
|
+
emptyOutDir: false
|
|
87
|
+
} }));
|
|
88
|
+
const mainEntry = node_path.default.resolve(config.root, config.electron.main);
|
|
89
|
+
if (!node_fs.default.existsSync(mainEntry)) throw new Error(`Electron main entry not found: ${config.electron.main}\n在 nasti.config.ts 的 electron.main 指定主进程入口文件。`);
|
|
90
|
+
const mainFile = await bundleNode(config, mainEntry, {
|
|
91
|
+
outFile: outFileName(outDir, "main", config.electron.mainFormat),
|
|
92
|
+
format: config.electron.mainFormat,
|
|
93
|
+
label: "main"
|
|
94
|
+
});
|
|
95
|
+
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
96
|
+
const preloadFiles = [];
|
|
97
|
+
for (const entry of preloadEntries) {
|
|
98
|
+
if (!node_fs.default.existsSync(entry)) {
|
|
99
|
+
console.warn(picocolors.default.yellow(` ⚠ preload entry not found, skipped: ${entry}`));
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const base = node_path.default.basename(entry).replace(/\.[^.]+$/, "");
|
|
103
|
+
const out = outFileName(outDir, base, config.electron.preloadFormat);
|
|
104
|
+
await bundleNode(config, entry, {
|
|
105
|
+
outFile: out,
|
|
106
|
+
format: config.electron.preloadFormat,
|
|
107
|
+
label: `preload (${base})`
|
|
108
|
+
});
|
|
109
|
+
preloadFiles.push(out);
|
|
110
|
+
}
|
|
111
|
+
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
112
|
+
console.log(picocolors.default.green(`\n✓ Electron build complete in ${elapsed}s`));
|
|
113
|
+
console.log(picocolors.default.dim(` renderer: ${node_path.default.relative(config.root, rendererOutDir)}/`));
|
|
114
|
+
console.log(picocolors.default.dim(` main: ${node_path.default.relative(config.root, mainFile)}`));
|
|
115
|
+
for (const pf of preloadFiles) console.log(picocolors.default.dim(` preload: ${node_path.default.relative(config.root, pf)}`));
|
|
116
|
+
console.log();
|
|
117
|
+
return {
|
|
118
|
+
rendererOutDir,
|
|
119
|
+
mainFile,
|
|
120
|
+
preloadFiles
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Bundles a Node-targeted entry for Electron into a single output file using Rolldown and the OXC transform.
|
|
125
|
+
*
|
|
126
|
+
* @param config - Fully resolved build configuration used to drive transforms, defines, plugins, and output options
|
|
127
|
+
* @param entry - Absolute path to the entry file to bundle
|
|
128
|
+
* @param opts - Bundle options; expects `outFile` (destination path), `format` (`'cjs'` or `'esm'`), and `label` (human-readable name for logging)
|
|
129
|
+
* @returns The path to the written bundle file (`opts.outFile`)
|
|
130
|
+
*/
|
|
131
|
+
async function bundleNode(config, entry, opts) {
|
|
132
|
+
const env = require_env.loadEnv(config.mode, config.root, config.envPrefix);
|
|
133
|
+
const envDefine = {
|
|
134
|
+
...require_env.buildEnvDefine(env, config.mode),
|
|
135
|
+
__ELECTRON__: "true",
|
|
136
|
+
__NASTI_TARGET__: JSON.stringify("electron")
|
|
137
|
+
};
|
|
138
|
+
const oxcTransformPlugin = {
|
|
139
|
+
name: "nasti:oxc-transform",
|
|
140
|
+
async transform(code, id) {
|
|
141
|
+
const result = config.framework === "react" ? await require_env.transformReactCode(id, code, {
|
|
142
|
+
react: config.react,
|
|
143
|
+
consumer: "server",
|
|
144
|
+
development: config.mode === "development",
|
|
145
|
+
sourcemap: !!config.build.sourcemap,
|
|
146
|
+
target: config.electron.nodeTarget,
|
|
147
|
+
onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
|
|
148
|
+
}) : require_env.shouldTransform(id) ? require_env.transformCode(id, code, {
|
|
149
|
+
sourcemap: !!config.build.sourcemap,
|
|
150
|
+
jsxRuntime: "automatic",
|
|
151
|
+
jsxImportSource: "vue",
|
|
152
|
+
target: config.electron.nodeTarget
|
|
153
|
+
}) : null;
|
|
154
|
+
if (!result) return null;
|
|
155
|
+
return {
|
|
156
|
+
code: result.code,
|
|
157
|
+
map: result.map ? JSON.parse(result.map) : void 0
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
|
|
162
|
+
const mergedDefine = {
|
|
163
|
+
...userTransform?.define ?? {},
|
|
164
|
+
...envDefine
|
|
165
|
+
};
|
|
166
|
+
const bundle = await (0, rolldown.rolldown)({
|
|
167
|
+
...restInputOptions,
|
|
168
|
+
input: entry,
|
|
169
|
+
platform: "node",
|
|
170
|
+
transform: {
|
|
171
|
+
...userTransform,
|
|
172
|
+
target: config.electron.nodeTarget,
|
|
173
|
+
define: mergedDefine
|
|
174
|
+
},
|
|
175
|
+
plugins: [
|
|
176
|
+
oxcTransformPlugin,
|
|
177
|
+
electronPlugin(config),
|
|
178
|
+
require_env.resolvePlugin(config)
|
|
179
|
+
]
|
|
180
|
+
});
|
|
181
|
+
node_fs.default.mkdirSync(node_path.default.dirname(opts.outFile), { recursive: true });
|
|
182
|
+
await bundle.write({
|
|
183
|
+
sourcemap: !!config.build.sourcemap,
|
|
184
|
+
minify: require_env.resolveMinifyOption(config.build.minify),
|
|
185
|
+
...userOutput,
|
|
186
|
+
file: opts.outFile,
|
|
187
|
+
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
188
|
+
codeSplitting: false
|
|
189
|
+
});
|
|
190
|
+
await bundle.close();
|
|
191
|
+
console.log(picocolors.default.dim(` ✓ ${opts.label} → ${node_path.default.relative(config.root, opts.outFile)}`));
|
|
192
|
+
return opts.outFile;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 从 Electron 配置派生 renderer 的普通 Web 构建配置。
|
|
196
|
+
*
|
|
197
|
+
* renderer 使用指定 HTML 入口;本地文件加载场景默认把 `/` base 收敛为
|
|
198
|
+
* `./`,避免产物中的 `/assets/*` 被解析到文件系统根目录。
|
|
199
|
+
*/
|
|
200
|
+
function createElectronRendererConfig(config, inlineConfig = {}, overrides = {}) {
|
|
201
|
+
const inlineClient = inlineConfig.environments?.client ?? {};
|
|
202
|
+
return {
|
|
203
|
+
...inlineConfig,
|
|
204
|
+
...overrides,
|
|
205
|
+
root: config.root,
|
|
206
|
+
mode: config.mode,
|
|
207
|
+
target: "web",
|
|
208
|
+
framework: config.framework,
|
|
209
|
+
base: config.base === "/" ? "./" : config.base,
|
|
210
|
+
environments: {
|
|
211
|
+
...inlineConfig.environments ?? {},
|
|
212
|
+
client: {
|
|
213
|
+
...inlineClient,
|
|
214
|
+
html: config.electron.renderer
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Compute an output file path for a given base name and module format.
|
|
221
|
+
*
|
|
222
|
+
* @param outDir - Directory where the output file will be placed
|
|
223
|
+
* @param base - Base filename without extension
|
|
224
|
+
* @param format - Module format; `cjs` yields a `.cjs` extension, `esm` yields a `.mjs` extension
|
|
225
|
+
* @returns The resolved file path combining `outDir` and `base` with the appropriate extension
|
|
226
|
+
*/
|
|
227
|
+
function outFileName(outDir, base, format) {
|
|
228
|
+
const ext = format === "cjs" ? ".cjs" : ".mjs";
|
|
229
|
+
return node_path.default.join(outDir, base + ext);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Normalize Electron preload entries into absolute file paths.
|
|
233
|
+
*
|
|
234
|
+
* @param preload - A single preload path or an array of preload paths; a falsy value produces an empty list
|
|
235
|
+
* @param root - Root directory used to resolve relative preload entries
|
|
236
|
+
* @returns An array of absolute file paths for each preload entry
|
|
237
|
+
*/
|
|
238
|
+
function normalizePreload(preload, root) {
|
|
239
|
+
return (Array.isArray(preload) ? preload : preload ? [preload] : []).map((p) => node_path.default.resolve(root, p));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Warns when the detected Electron major version is lower than the configured minimum.
|
|
243
|
+
*
|
|
244
|
+
* Checks the project for an installed Electron package and, if its major version
|
|
245
|
+
* is less than `config.electron.minVersion`, logs a yellow warning describing the mismatch.
|
|
246
|
+
*
|
|
247
|
+
* @param config - Resolved build configuration that contains `electron.minVersion` and project `root`
|
|
248
|
+
*/
|
|
249
|
+
function assertElectronVersion(config) {
|
|
250
|
+
const min = config.electron.minVersion;
|
|
251
|
+
const installed = detectInstalledElectron(config.root);
|
|
252
|
+
if (installed && installed < min) console.warn(picocolors.default.yellow(` ⚠ 检测到 Electron ${installed},Nasti 要求 ≥ ${min}。旧版本可能缺少 ESM 主进程支持。`));
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Detects the installed Electron major version in the given project root.
|
|
256
|
+
*
|
|
257
|
+
* @param root - Project root directory used to locate electron via Node resolution
|
|
258
|
+
* @returns The major Electron version as a number, or `null` if Electron is not installed or the version cannot be determined
|
|
259
|
+
*/
|
|
260
|
+
function detectInstalledElectron(root) {
|
|
261
|
+
try {
|
|
262
|
+
const pkgPath = (0, node_module.createRequire)(node_path.default.resolve(root, "package.json")).resolve("electron/package.json");
|
|
263
|
+
const pkg = JSON.parse(node_fs.default.readFileSync(pkgPath, "utf-8"));
|
|
264
|
+
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
265
|
+
return Number.isFinite(major) ? major : null;
|
|
266
|
+
} catch {
|
|
267
|
+
try {
|
|
268
|
+
const pkgPath = node_path.default.resolve(root, "node_modules/electron/package.json");
|
|
269
|
+
if (!node_fs.default.existsSync(pkgPath)) return null;
|
|
270
|
+
const pkg = JSON.parse(node_fs.default.readFileSync(pkgPath, "utf-8"));
|
|
271
|
+
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
272
|
+
return Number.isFinite(major) ? major : null;
|
|
273
|
+
} catch {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
Object.defineProperty(exports, "buildElectron", {
|
|
280
|
+
enumerable: true,
|
|
281
|
+
get: function() {
|
|
282
|
+
return buildElectron;
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
Object.defineProperty(exports, "createElectronRendererConfig", {
|
|
286
|
+
enumerable: true,
|
|
287
|
+
get: function() {
|
|
288
|
+
return createElectronRendererConfig;
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
Object.defineProperty(exports, "detectInstalledElectron", {
|
|
292
|
+
enumerable: true,
|
|
293
|
+
get: function() {
|
|
294
|
+
return detectInstalledElectron;
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
Object.defineProperty(exports, "electronPlugin", {
|
|
298
|
+
enumerable: true,
|
|
299
|
+
get: function() {
|
|
300
|
+
return electronPlugin;
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
Object.defineProperty(exports, "electron_exports", {
|
|
304
|
+
enumerable: true,
|
|
305
|
+
get: function() {
|
|
306
|
+
return electron_exports;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
Object.defineProperty(exports, "normalizePreload", {
|
|
310
|
+
enumerable: true,
|
|
311
|
+
get: function() {
|
|
312
|
+
return normalizePreload;
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
//# sourceMappingURL=electron-D0PSXz-a.cjs.map
|