@nasti-toolchain/nasti 1.3.9 → 1.4.0
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 +83 -2
- package/dist/cli.cjs +486 -24
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +484 -24
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1752 -1288
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -1
- package/dist/index.d.ts +82 -1
- package/dist/index.js +1738 -1281
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,1427 +30,1479 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
-
// src/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
33
|
+
// src/config/defaults.ts
|
|
34
|
+
var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaults;
|
|
35
|
+
var init_defaults = __esm({
|
|
36
|
+
"src/config/defaults.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
defaultResolve = {
|
|
39
|
+
alias: {},
|
|
40
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".json", ".vue"],
|
|
41
|
+
conditions: ["import", "module", "browser", "default"],
|
|
42
|
+
mainFields: ["module", "jsnext:main", "jsnext", "main"]
|
|
43
|
+
};
|
|
44
|
+
defaultServer = {
|
|
45
|
+
port: 3e3,
|
|
46
|
+
host: "localhost",
|
|
47
|
+
https: false,
|
|
48
|
+
open: false,
|
|
49
|
+
proxy: {},
|
|
50
|
+
cors: true,
|
|
51
|
+
hmr: true
|
|
52
|
+
};
|
|
53
|
+
defaultBuild = {
|
|
54
|
+
outDir: "dist",
|
|
55
|
+
assetsDir: "assets",
|
|
56
|
+
minify: true,
|
|
57
|
+
sourcemap: false,
|
|
58
|
+
target: "es2022",
|
|
59
|
+
rolldownOptions: {},
|
|
60
|
+
emptyOutDir: true
|
|
61
|
+
};
|
|
62
|
+
defaultElectron = {
|
|
63
|
+
main: "src/electron/main.ts",
|
|
64
|
+
preload: "src/electron/preload.ts",
|
|
65
|
+
renderer: "index.html",
|
|
66
|
+
nodeTarget: "node22",
|
|
67
|
+
mainFormat: "cjs",
|
|
68
|
+
preloadFormat: "cjs",
|
|
69
|
+
electronPath: "",
|
|
70
|
+
electronArgs: [],
|
|
71
|
+
autoRestart: true,
|
|
72
|
+
minVersion: 41,
|
|
73
|
+
external: ["electron"]
|
|
74
|
+
};
|
|
75
|
+
defaults = {
|
|
76
|
+
root: ".",
|
|
77
|
+
base: "/",
|
|
78
|
+
mode: "development",
|
|
79
|
+
target: "web",
|
|
80
|
+
framework: "auto",
|
|
81
|
+
resolve: defaultResolve,
|
|
82
|
+
server: defaultServer,
|
|
83
|
+
build: defaultBuild,
|
|
84
|
+
electron: defaultElectron,
|
|
85
|
+
plugins: [],
|
|
86
|
+
envPrefix: ["NASTI_", "VITE_"],
|
|
87
|
+
logLevel: "info"
|
|
88
|
+
};
|
|
71
89
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// src/config/index.ts
|
|
93
|
+
function loadTsconfigPaths(root) {
|
|
94
|
+
const tsconfigPath = import_node_path.default.resolve(root, "tsconfig.json");
|
|
95
|
+
if (!import_node_fs.default.existsSync(tsconfigPath)) return {};
|
|
96
|
+
try {
|
|
97
|
+
const content = import_node_fs.default.readFileSync(tsconfigPath, "utf-8");
|
|
98
|
+
const stripped = content.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
99
|
+
const tsconfig = JSON.parse(stripped);
|
|
100
|
+
const paths = tsconfig?.compilerOptions?.paths ?? {};
|
|
101
|
+
const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? ".";
|
|
102
|
+
const alias = {};
|
|
103
|
+
for (const [pattern, targets] of Object.entries(paths)) {
|
|
104
|
+
if (!targets.length) continue;
|
|
105
|
+
const cleanKey = pattern.replace(/\/\*$/, "");
|
|
106
|
+
const cleanTarget = targets[0].replace(/\/\*$/, "");
|
|
107
|
+
alias[cleanKey] = import_node_path.default.resolve(root, baseUrl, cleanTarget);
|
|
108
|
+
}
|
|
109
|
+
return alias;
|
|
110
|
+
} catch {
|
|
111
|
+
return {};
|
|
83
112
|
}
|
|
84
|
-
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
85
113
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (!import_node_fs4.default.existsSync(htmlPath)) return null;
|
|
89
|
-
return import_node_fs4.default.readFileSync(htmlPath, "utf-8");
|
|
114
|
+
function defineConfig(config) {
|
|
115
|
+
return config;
|
|
90
116
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
117
|
+
async function loadConfigFromFile(root) {
|
|
118
|
+
for (const file of CONFIG_FILES) {
|
|
119
|
+
const filePath = import_node_path.default.resolve(root, file);
|
|
120
|
+
if (!import_node_fs.default.existsSync(filePath)) continue;
|
|
121
|
+
if (file.endsWith(".ts") || file.endsWith(".mts")) {
|
|
122
|
+
return await loadTsConfig(filePath);
|
|
123
|
+
}
|
|
124
|
+
const mod = await import((0, import_node_url.pathToFileURL)(filePath).href);
|
|
125
|
+
return mod.default ?? mod;
|
|
97
126
|
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// src/core/transformer.ts
|
|
101
|
-
function shouldTransform(id) {
|
|
102
|
-
return TS_EXTENSIONS.test(id) || JSX_EXTENSIONS.test(id) || JS_EXTENSIONS.test(id) && false;
|
|
127
|
+
return {};
|
|
103
128
|
}
|
|
104
|
-
function
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
const result = (
|
|
108
|
-
typescript:
|
|
109
|
-
jsx: isJSX || /\.tsx$/.test(filename) ? {
|
|
110
|
-
runtime: options.jsxRuntime ?? "automatic",
|
|
111
|
-
importSource: options.jsxImportSource ?? "react",
|
|
112
|
-
refresh: options.reactRefresh ?? false
|
|
113
|
-
} : void 0,
|
|
114
|
-
sourcemap: options.sourcemap ?? true
|
|
129
|
+
async function loadTsConfig(filePath) {
|
|
130
|
+
const { transformSync: transformSync2 } = await import("oxc-transform");
|
|
131
|
+
const code = import_node_fs.default.readFileSync(filePath, "utf-8");
|
|
132
|
+
const result = transformSync2(filePath, code, {
|
|
133
|
+
typescript: {}
|
|
115
134
|
});
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
135
|
+
const tmpFile = filePath + ".timestamp-" + Date.now() + ".mjs";
|
|
136
|
+
try {
|
|
137
|
+
import_node_fs.default.writeFileSync(tmpFile, result.code);
|
|
138
|
+
const mod = await import((0, import_node_url.pathToFileURL)(tmpFile).href);
|
|
139
|
+
return mod.default ?? mod;
|
|
140
|
+
} finally {
|
|
141
|
+
import_node_fs.default.unlinkSync(tmpFile);
|
|
120
142
|
}
|
|
121
|
-
return {
|
|
122
|
-
code: result.code,
|
|
123
|
-
map: result.map ? JSON.stringify(result.map) : null
|
|
124
|
-
};
|
|
125
143
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
JSX_EXTENSIONS = /\.(jsx|tsx)$/;
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// src/core/env.ts
|
|
138
|
-
function loadEnv(mode, root, prefixes) {
|
|
139
|
-
const envFiles = [
|
|
140
|
-
".env",
|
|
141
|
-
`.env.${mode}`,
|
|
142
|
-
".env.local",
|
|
143
|
-
`.env.${mode}.local`
|
|
144
|
+
async function resolveConfig(inlineConfig = {}, command) {
|
|
145
|
+
const root = import_node_path.default.resolve(inlineConfig.root ?? defaults.root);
|
|
146
|
+
const fileConfig = await loadConfigFromFile(root);
|
|
147
|
+
const merged = deepMerge(deepMerge({}, fileConfig), inlineConfig);
|
|
148
|
+
const rawPlugins = [
|
|
149
|
+
...fileConfig.plugins ?? [],
|
|
150
|
+
...inlineConfig.plugins ?? []
|
|
144
151
|
];
|
|
145
|
-
const
|
|
146
|
-
for (const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
for (const line of content.split("\n")) {
|
|
151
|
-
const trimmed = line.trim();
|
|
152
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
153
|
-
const eqIdx = trimmed.indexOf("=");
|
|
154
|
-
if (eqIdx === -1) continue;
|
|
155
|
-
const key = trimmed.slice(0, eqIdx).trim();
|
|
156
|
-
let value = trimmed.slice(eqIdx + 1).trim();
|
|
157
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
158
|
-
value = value.slice(1, -1);
|
|
159
|
-
}
|
|
160
|
-
raw[key] = value;
|
|
152
|
+
const env = { mode: merged.mode ?? defaults.mode, command };
|
|
153
|
+
for (const plugin of rawPlugins) {
|
|
154
|
+
if (plugin.config) {
|
|
155
|
+
const result = await plugin.config(merged, env);
|
|
156
|
+
if (result) Object.assign(merged, result);
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
159
|
+
const resolved = {
|
|
160
|
+
root,
|
|
161
|
+
base: merged.base ?? defaults.base,
|
|
162
|
+
mode: command === "build" ? "production" : "development",
|
|
163
|
+
target: merged.target ?? defaults.target,
|
|
164
|
+
framework: merged.framework ?? defaults.framework,
|
|
165
|
+
command,
|
|
166
|
+
resolve: {
|
|
167
|
+
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
168
|
+
alias: { ...loadTsconfigPaths(root), ...defaults.resolve.alias, ...merged.resolve?.alias },
|
|
169
|
+
extensions: merged.resolve?.extensions ?? defaults.resolve.extensions,
|
|
170
|
+
conditions: merged.resolve?.conditions ?? defaults.resolve.conditions,
|
|
171
|
+
mainFields: merged.resolve?.mainFields ?? defaults.resolve.mainFields
|
|
172
|
+
},
|
|
173
|
+
plugins: [],
|
|
174
|
+
server: { ...defaults.server, ...merged.server },
|
|
175
|
+
build: { ...defaults.build, ...merged.build },
|
|
176
|
+
electron: { ...defaults.electron, ...merged.electron },
|
|
177
|
+
envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
|
|
178
|
+
logLevel: merged.logLevel ?? defaults.logLevel
|
|
179
|
+
};
|
|
180
|
+
const filteredPlugins = rawPlugins.filter((p) => {
|
|
181
|
+
if (!p.apply) return true;
|
|
182
|
+
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
183
|
+
return p.apply === command;
|
|
184
|
+
});
|
|
185
|
+
resolved.plugins = filteredPlugins;
|
|
186
|
+
for (const plugin of resolved.plugins) {
|
|
187
|
+
if (plugin.configResolved) {
|
|
188
|
+
await plugin.configResolved(resolved);
|
|
167
189
|
}
|
|
168
190
|
}
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
function buildEnvDefine(env, mode) {
|
|
172
|
-
const define = {};
|
|
173
|
-
for (const [key, value] of Object.entries(env)) {
|
|
174
|
-
define[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
175
|
-
}
|
|
176
|
-
define["import.meta.env.MODE"] = JSON.stringify(mode);
|
|
177
|
-
define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
|
|
178
|
-
define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
|
|
179
|
-
define["import.meta.env.SSR"] = "false";
|
|
180
|
-
return define;
|
|
191
|
+
return resolved;
|
|
181
192
|
}
|
|
182
|
-
function
|
|
183
|
-
|
|
184
|
-
for (const
|
|
185
|
-
const
|
|
186
|
-
|
|
193
|
+
function deepMerge(target, source) {
|
|
194
|
+
const result = { ...target };
|
|
195
|
+
for (const key of Object.keys(source)) {
|
|
196
|
+
const val = source[key];
|
|
197
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
198
|
+
result[key] = deepMerge(
|
|
199
|
+
result[key] ?? {},
|
|
200
|
+
val
|
|
201
|
+
);
|
|
202
|
+
} else if (val !== void 0) {
|
|
203
|
+
result[key] = val;
|
|
204
|
+
}
|
|
187
205
|
}
|
|
188
206
|
return result;
|
|
189
207
|
}
|
|
190
|
-
var
|
|
191
|
-
var
|
|
192
|
-
"src/
|
|
208
|
+
var import_node_url, import_node_path, import_node_fs, CONFIG_FILES;
|
|
209
|
+
var init_config = __esm({
|
|
210
|
+
"src/config/index.ts"() {
|
|
193
211
|
"use strict";
|
|
194
|
-
|
|
195
|
-
|
|
212
|
+
import_node_url = require("url");
|
|
213
|
+
import_node_path = __toESM(require("path"), 1);
|
|
214
|
+
import_node_fs = __toESM(require("fs"), 1);
|
|
215
|
+
init_defaults();
|
|
216
|
+
CONFIG_FILES = [
|
|
217
|
+
"nasti.config.ts",
|
|
218
|
+
"nasti.config.js",
|
|
219
|
+
"nasti.config.mjs",
|
|
220
|
+
"nasti.config.mts"
|
|
221
|
+
];
|
|
196
222
|
}
|
|
197
223
|
});
|
|
198
224
|
|
|
199
|
-
// src/
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (ctx.config.server.cors) {
|
|
213
|
-
const origin = req.headers.origin ?? "*";
|
|
214
|
-
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
215
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
|
|
216
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
217
|
-
if (req.method === "OPTIONS") {
|
|
218
|
-
res.statusCode = 204;
|
|
219
|
-
res.end();
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (req.method !== "GET") return next();
|
|
224
|
-
if (url === "/@nasti/client") {
|
|
225
|
-
res.setHeader("Content-Type", "application/javascript");
|
|
226
|
-
res.end(getHmrClientCode());
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
if (url === "/" || url.endsWith(".html")) {
|
|
230
|
-
const html = await readHtmlFile(ctx.config.root);
|
|
231
|
-
if (html) {
|
|
232
|
-
let processedHtml = html;
|
|
233
|
-
for (const plugin of ctx.config.plugins) {
|
|
234
|
-
if (plugin.transformIndexHtml) {
|
|
235
|
-
const result = await plugin.transformIndexHtml(processedHtml);
|
|
236
|
-
if (typeof result === "string") {
|
|
237
|
-
processedHtml = result;
|
|
238
|
-
} else if (result && "html" in result) {
|
|
239
|
-
processedHtml = processHtml(result.html, result.tags);
|
|
240
|
-
} else if (Array.isArray(result)) {
|
|
241
|
-
processedHtml = processHtml(processedHtml, result);
|
|
242
|
-
}
|
|
225
|
+
// src/plugins/resolve.ts
|
|
226
|
+
function resolvePlugin(config) {
|
|
227
|
+
const { alias, extensions } = config.resolve;
|
|
228
|
+
const require2 = (0, import_node_module.createRequire)(import_node_path2.default.resolve(config.root, "package.json"));
|
|
229
|
+
return {
|
|
230
|
+
name: "nasti:resolve",
|
|
231
|
+
enforce: "pre",
|
|
232
|
+
resolveId(source, importer) {
|
|
233
|
+
for (const [key, value] of Object.entries(alias)) {
|
|
234
|
+
if (source === key || source.startsWith(key + "/")) {
|
|
235
|
+
source = source.replace(key, value);
|
|
236
|
+
if (!import_node_path2.default.isAbsolute(source)) {
|
|
237
|
+
source = import_node_path2.default.resolve(config.root, source);
|
|
243
238
|
}
|
|
239
|
+
break;
|
|
244
240
|
}
|
|
245
|
-
res.setHeader("Content-Type", "text/html");
|
|
246
|
-
res.end(processedHtml);
|
|
247
|
-
return;
|
|
248
241
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
242
|
+
if (import_node_path2.default.isAbsolute(source)) {
|
|
243
|
+
const resolved = tryResolveFile(source, extensions);
|
|
244
|
+
if (resolved) return resolved;
|
|
245
|
+
}
|
|
246
|
+
if (source.startsWith(".")) {
|
|
247
|
+
const dir = importer ? import_node_path2.default.dirname(importer) : config.root;
|
|
248
|
+
const absolute = import_node_path2.default.resolve(dir, source);
|
|
249
|
+
const resolved = tryResolveFile(absolute, extensions);
|
|
250
|
+
if (resolved) return resolved;
|
|
251
|
+
}
|
|
252
|
+
if (!source.startsWith("/") && !source.startsWith(".")) {
|
|
253
|
+
try {
|
|
254
|
+
const resolved = require2.resolve(source, {
|
|
255
|
+
paths: [importer ? import_node_path2.default.dirname(importer) : config.root]
|
|
256
|
+
});
|
|
257
|
+
return resolved;
|
|
258
|
+
} catch {
|
|
259
|
+
return null;
|
|
259
260
|
}
|
|
260
|
-
} catch (err) {
|
|
261
|
-
console.error(`[nasti] Transform error: ${url}`, err.message);
|
|
262
|
-
res.statusCode = 500;
|
|
263
|
-
res.end(`Transform error: ${err.message}`);
|
|
264
|
-
return;
|
|
265
261
|
}
|
|
262
|
+
return null;
|
|
263
|
+
},
|
|
264
|
+
load(id) {
|
|
265
|
+
if (!import_node_fs2.default.existsSync(id)) return null;
|
|
266
|
+
if (id.endsWith(".json")) {
|
|
267
|
+
const content = import_node_fs2.default.readFileSync(id, "utf-8");
|
|
268
|
+
return `export default ${content}`;
|
|
269
|
+
}
|
|
270
|
+
return import_node_fs2.default.readFileSync(id, "utf-8");
|
|
266
271
|
}
|
|
267
|
-
next();
|
|
268
272
|
};
|
|
269
273
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const cached = moduleGraph.getModuleByUrl(url);
|
|
274
|
-
if (cached?.transformResult) {
|
|
275
|
-
return cached.transformResult;
|
|
276
|
-
}
|
|
277
|
-
if (cleanReqUrl === "/@react-refresh") {
|
|
278
|
-
return { code: REACT_REFRESH_RUNTIME };
|
|
279
|
-
}
|
|
280
|
-
const filePath = resolveUrlToFile(url, config.root);
|
|
281
|
-
if (!filePath || !import_node_fs7.default.existsSync(filePath)) return null;
|
|
282
|
-
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
283
|
-
moduleGraph.registerModule(mod, filePath);
|
|
284
|
-
if (cleanReqUrl.startsWith("/@modules/")) {
|
|
285
|
-
const code2 = await bundlePackageAsEsm(filePath);
|
|
286
|
-
const transformResult2 = { code: code2 };
|
|
287
|
-
mod.transformResult = transformResult2;
|
|
288
|
-
return transformResult2;
|
|
274
|
+
function tryResolveFile(file, extensions) {
|
|
275
|
+
if (import_node_fs2.default.existsSync(file) && import_node_fs2.default.statSync(file).isFile()) {
|
|
276
|
+
return file;
|
|
289
277
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
278
|
+
for (const ext of extensions) {
|
|
279
|
+
const withExt = file + ext;
|
|
280
|
+
if (import_node_fs2.default.existsSync(withExt) && import_node_fs2.default.statSync(withExt).isFile()) {
|
|
281
|
+
return withExt;
|
|
282
|
+
}
|
|
294
283
|
}
|
|
295
|
-
if (
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
302
|
-
reactRefresh: useRefresh
|
|
303
|
-
});
|
|
304
|
-
code = result.code;
|
|
305
|
-
if (useRefresh) {
|
|
306
|
-
code = REACT_REFRESH_PREAMBLE + code + REACT_REFRESH_FOOTER;
|
|
284
|
+
if (import_node_fs2.default.existsSync(file) && import_node_fs2.default.statSync(file).isDirectory()) {
|
|
285
|
+
for (const ext of extensions) {
|
|
286
|
+
const indexFile = import_node_path2.default.join(file, "index" + ext);
|
|
287
|
+
if (import_node_fs2.default.existsSync(indexFile)) {
|
|
288
|
+
return indexFile;
|
|
289
|
+
}
|
|
307
290
|
}
|
|
308
291
|
}
|
|
309
|
-
|
|
310
|
-
loadEnv(config.mode, config.root, config.envPrefix),
|
|
311
|
-
config.mode
|
|
312
|
-
);
|
|
313
|
-
code = replaceEnvInCode(code, envDefine);
|
|
314
|
-
code = rewriteImports(code, config);
|
|
315
|
-
const transformResult = { code };
|
|
316
|
-
mod.transformResult = transformResult;
|
|
317
|
-
return transformResult;
|
|
292
|
+
return null;
|
|
318
293
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
294
|
+
var import_node_path2, import_node_fs2, import_node_module;
|
|
295
|
+
var init_resolve = __esm({
|
|
296
|
+
"src/plugins/resolve.ts"() {
|
|
297
|
+
"use strict";
|
|
298
|
+
import_node_path2 = __toESM(require("path"), 1);
|
|
299
|
+
import_node_fs2 = __toESM(require("fs"), 1);
|
|
300
|
+
import_node_module = require("module");
|
|
322
301
|
}
|
|
323
|
-
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// src/plugins/css.ts
|
|
305
|
+
function cssPlugin(config) {
|
|
306
|
+
return {
|
|
307
|
+
name: "nasti:css",
|
|
308
|
+
resolveId(source) {
|
|
309
|
+
if (source.endsWith(".css")) return null;
|
|
310
|
+
return null;
|
|
311
|
+
},
|
|
312
|
+
transform(code, id) {
|
|
313
|
+
if (!id.endsWith(".css")) return null;
|
|
314
|
+
const rewritten = rewriteCssUrls(code, id, config.root);
|
|
315
|
+
if (config.command === "serve") {
|
|
316
|
+
const escaped = JSON.stringify(rewritten);
|
|
317
|
+
return {
|
|
318
|
+
code: `
|
|
319
|
+
const css = ${escaped};
|
|
320
|
+
const __nasti_css_id__ = ${JSON.stringify(id)};
|
|
321
|
+
const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
|
|
322
|
+
if (__nasti_existing__) __nasti_existing__.remove();
|
|
323
|
+
const style = document.createElement('style');
|
|
324
|
+
style.setAttribute('data-nasti-css', __nasti_css_id__);
|
|
325
|
+
style.textContent = css;
|
|
326
|
+
document.head.appendChild(style);
|
|
327
|
+
|
|
328
|
+
// HMR
|
|
329
|
+
if (import.meta.hot) {
|
|
330
|
+
import.meta.hot.accept();
|
|
331
|
+
import.meta.hot.prune(() => {
|
|
332
|
+
style.remove();
|
|
333
|
+
});
|
|
324
334
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
335
|
+
|
|
336
|
+
export default css;
|
|
337
|
+
`
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
return rewritten !== code ? { code: rewritten } : null;
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function rewriteCssUrls(css, from, root) {
|
|
345
|
+
return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
|
|
346
|
+
if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
|
|
347
|
+
return match;
|
|
333
348
|
}
|
|
349
|
+
const resolved = import_node_path3.default.resolve(import_node_path3.default.dirname(from), url);
|
|
350
|
+
const relative = "/" + import_node_path3.default.relative(root, resolved);
|
|
351
|
+
return `url(${relative})`;
|
|
334
352
|
});
|
|
335
|
-
const result = await bundle.generate({ format: "esm", exports: "named" });
|
|
336
|
-
await bundle.close();
|
|
337
|
-
let code = result.output[0].code;
|
|
338
|
-
code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
|
|
339
|
-
code = code.replace(
|
|
340
|
-
/^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
341
|
-
(_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
|
|
342
|
-
).replace(
|
|
343
|
-
/^(export\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
344
|
-
(_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
|
|
345
|
-
).replace(
|
|
346
|
-
/^(import\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
347
|
-
(_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
|
|
348
|
-
);
|
|
349
|
-
code = rewriteExternalRequires(code);
|
|
350
|
-
if (code.includes("__commonJSMin")) {
|
|
351
|
-
code = await injectCjsNamedExports(code, entryFile);
|
|
352
|
-
}
|
|
353
|
-
return code;
|
|
354
353
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
pkgs.add(m[1]);
|
|
361
|
-
}
|
|
362
|
-
if (pkgs.size === 0) return code;
|
|
363
|
-
let result = code;
|
|
364
|
-
const imports = [];
|
|
365
|
-
for (const pkg of pkgs) {
|
|
366
|
-
const safe = pkg.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
367
|
-
imports.push(`import __req_${safe} from "/@modules/${pkg}";`);
|
|
368
|
-
result = result.replaceAll(`__require("${pkg}")`, `__req_${safe}`);
|
|
369
|
-
result = result.replaceAll(`__require('${pkg}')`, `__req_${safe}`);
|
|
354
|
+
var import_node_path3;
|
|
355
|
+
var init_css = __esm({
|
|
356
|
+
"src/plugins/css.ts"() {
|
|
357
|
+
"use strict";
|
|
358
|
+
import_node_path3 = __toESM(require("path"), 1);
|
|
370
359
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
(k) => k !== "__esModule" && k !== "default" && VALID_IDENT.test(k)
|
|
381
|
-
);
|
|
382
|
-
if (namedKeys.length === 0) return code;
|
|
383
|
-
return code.replace(
|
|
384
|
-
/^export default (\w+\(\));?\s*$/m,
|
|
385
|
-
(_, call) => [
|
|
386
|
-
`const __cjsMod = ${call};`,
|
|
387
|
-
`export default __cjsMod;`,
|
|
388
|
-
...namedKeys.map((k) => `export const ${k} = __cjsMod[${JSON.stringify(k)}];`)
|
|
389
|
-
].join("\n")
|
|
390
|
-
);
|
|
391
|
-
} catch {
|
|
392
|
-
return code;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
function rewriteImports(code, _config) {
|
|
396
|
-
return code.replace(
|
|
397
|
-
/\bfrom\s+(['"])([^'"./][^'"]*)\1/g,
|
|
398
|
-
(match, quote, specifier) => {
|
|
399
|
-
return `from ${quote}/@modules/${specifier}${quote}`;
|
|
400
|
-
}
|
|
401
|
-
).replace(
|
|
402
|
-
// 处理纯副作用导入: import 'bare-specifier'
|
|
403
|
-
/\bimport\s+(['"])([^'"./][^'"]*)\1/g,
|
|
404
|
-
(match, quote, specifier) => {
|
|
405
|
-
return `import ${quote}/@modules/${specifier}${quote}`;
|
|
406
|
-
}
|
|
407
|
-
).replace(
|
|
408
|
-
// 处理动态导入: import('bare-specifier')
|
|
409
|
-
/\bimport\s*\(\s*(['"])([^'"./][^'"]*)\1\s*\)/g,
|
|
410
|
-
(match, quote, specifier) => {
|
|
411
|
-
return `import(${quote}/@modules/${specifier}${quote})`;
|
|
412
|
-
}
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
function resolveNodeModule(root, moduleName) {
|
|
416
|
-
let pkgName;
|
|
417
|
-
let subpath;
|
|
418
|
-
if (moduleName.startsWith("@")) {
|
|
419
|
-
const parts = moduleName.split("/");
|
|
420
|
-
pkgName = parts.slice(0, 2).join("/");
|
|
421
|
-
subpath = parts.slice(2).join("/");
|
|
422
|
-
} else {
|
|
423
|
-
const slash = moduleName.indexOf("/");
|
|
424
|
-
pkgName = slash === -1 ? moduleName : moduleName.slice(0, slash);
|
|
425
|
-
subpath = slash === -1 ? "" : moduleName.slice(slash + 1);
|
|
426
|
-
}
|
|
427
|
-
let pkgDir = null;
|
|
428
|
-
let dir = root;
|
|
429
|
-
for (; ; ) {
|
|
430
|
-
const candidate = import_node_path8.default.join(dir, "node_modules", pkgName);
|
|
431
|
-
if (import_node_fs7.default.existsSync(candidate)) {
|
|
432
|
-
pkgDir = candidate;
|
|
433
|
-
break;
|
|
434
|
-
}
|
|
435
|
-
const parent = import_node_path8.default.dirname(dir);
|
|
436
|
-
if (parent === dir) break;
|
|
437
|
-
dir = parent;
|
|
438
|
-
}
|
|
439
|
-
if (!pkgDir) return null;
|
|
440
|
-
const pkgJsonPath = import_node_path8.default.join(pkgDir, "package.json");
|
|
441
|
-
if (!import_node_fs7.default.existsSync(pkgJsonPath)) return null;
|
|
442
|
-
let pkg;
|
|
443
|
-
try {
|
|
444
|
-
pkg = JSON.parse(import_node_fs7.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
445
|
-
} catch {
|
|
446
|
-
return null;
|
|
447
|
-
}
|
|
448
|
-
if (pkg.exports) {
|
|
449
|
-
const exportKey = subpath ? `./${subpath}` : ".";
|
|
450
|
-
const resolved = resolvePackageExports(pkg.exports, exportKey, pkgDir);
|
|
451
|
-
if (resolved) return resolved;
|
|
452
|
-
}
|
|
453
|
-
if (subpath) {
|
|
454
|
-
const subDirs = [""];
|
|
455
|
-
for (const field of ["module", "main"]) {
|
|
456
|
-
if (typeof pkg[field] === "string") {
|
|
457
|
-
const dir2 = import_node_path8.default.dirname(pkg[field]);
|
|
458
|
-
if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// src/plugins/assets.ts
|
|
363
|
+
function assetsPlugin(config) {
|
|
364
|
+
return {
|
|
365
|
+
name: "nasti:assets",
|
|
366
|
+
resolveId(source) {
|
|
367
|
+
if (source.endsWith("?url") || source.endsWith("?raw")) {
|
|
368
|
+
return source;
|
|
459
369
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
370
|
+
return null;
|
|
371
|
+
},
|
|
372
|
+
load(id) {
|
|
373
|
+
const ext = import_node_path4.default.extname(id.replace(/\?.*$/, ""));
|
|
374
|
+
if (id.endsWith("?raw")) {
|
|
375
|
+
const file = id.slice(0, -4);
|
|
376
|
+
if (import_node_fs3.default.existsSync(file)) {
|
|
377
|
+
const content = import_node_fs3.default.readFileSync(file, "utf-8");
|
|
378
|
+
return `export default ${JSON.stringify(content)}`;
|
|
379
|
+
}
|
|
466
380
|
}
|
|
381
|
+
if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
|
|
382
|
+
const file = id.replace(/\?.*$/, "");
|
|
383
|
+
if (!import_node_fs3.default.existsSync(file)) return null;
|
|
384
|
+
if (config.command === "serve") {
|
|
385
|
+
const url = "/" + import_node_path4.default.relative(config.root, file);
|
|
386
|
+
return `export default ${JSON.stringify(url)}`;
|
|
387
|
+
}
|
|
388
|
+
const content = import_node_fs3.default.readFileSync(file);
|
|
389
|
+
const hash = import_node_crypto.default.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
390
|
+
const basename = import_node_path4.default.basename(file, ext);
|
|
391
|
+
const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
|
|
392
|
+
return `export default ${JSON.stringify(config.base + hashedName)}`;
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
467
395
|
}
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
|
|
471
|
-
if (typeof pkg[field] === "string") {
|
|
472
|
-
const entry = import_node_path8.default.join(pkgDir, pkg[field]);
|
|
473
|
-
if (import_node_fs7.default.existsSync(entry)) return entry;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
const indexFallback = import_node_path8.default.join(pkgDir, "index.js");
|
|
477
|
-
if (import_node_fs7.default.existsSync(indexFallback)) return indexFallback;
|
|
478
|
-
return null;
|
|
479
|
-
}
|
|
480
|
-
function resolvePackageExports(exports2, key, pkgDir) {
|
|
481
|
-
if (typeof exports2 === "string") {
|
|
482
|
-
return key === "." ? import_node_path8.default.join(pkgDir, exports2) : null;
|
|
483
|
-
}
|
|
484
|
-
const entry = exports2[key];
|
|
485
|
-
if (entry === void 0) return null;
|
|
486
|
-
return resolveExportValue(entry, pkgDir);
|
|
396
|
+
};
|
|
487
397
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
398
|
+
var import_node_path4, import_node_fs3, import_node_crypto, ASSET_EXTENSIONS;
|
|
399
|
+
var init_assets = __esm({
|
|
400
|
+
"src/plugins/assets.ts"() {
|
|
401
|
+
"use strict";
|
|
402
|
+
import_node_path4 = __toESM(require("path"), 1);
|
|
403
|
+
import_node_fs3 = __toESM(require("fs"), 1);
|
|
404
|
+
import_node_crypto = __toESM(require("crypto"), 1);
|
|
405
|
+
ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
406
|
+
".png",
|
|
407
|
+
".jpg",
|
|
408
|
+
".jpeg",
|
|
409
|
+
".gif",
|
|
410
|
+
".svg",
|
|
411
|
+
".ico",
|
|
412
|
+
".webp",
|
|
413
|
+
".avif",
|
|
414
|
+
".mp4",
|
|
415
|
+
".webm",
|
|
416
|
+
".ogg",
|
|
417
|
+
".mp3",
|
|
418
|
+
".wav",
|
|
419
|
+
".flac",
|
|
420
|
+
".aac",
|
|
421
|
+
".woff",
|
|
422
|
+
".woff2",
|
|
423
|
+
".eot",
|
|
424
|
+
".ttf",
|
|
425
|
+
".otf",
|
|
426
|
+
".pdf",
|
|
427
|
+
".txt"
|
|
428
|
+
]);
|
|
496
429
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// src/plugins/html.ts
|
|
433
|
+
function htmlPlugin(config) {
|
|
434
|
+
return {
|
|
435
|
+
name: "nasti:html",
|
|
436
|
+
enforce: "post",
|
|
437
|
+
transformIndexHtml(html) {
|
|
438
|
+
const tags = [];
|
|
439
|
+
if (config.command === "serve") {
|
|
440
|
+
tags.push({
|
|
441
|
+
tag: "script",
|
|
442
|
+
attrs: { type: "module", src: "/@nasti/client" },
|
|
443
|
+
injectTo: "head-prepend"
|
|
444
|
+
});
|
|
502
445
|
}
|
|
446
|
+
return { html, tags };
|
|
503
447
|
}
|
|
504
|
-
}
|
|
505
|
-
return null;
|
|
448
|
+
};
|
|
506
449
|
}
|
|
507
|
-
function
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
450
|
+
function processHtml(html, tags) {
|
|
451
|
+
const headPrepend = tags.filter((t) => t.injectTo === "head-prepend");
|
|
452
|
+
const head = tags.filter((t) => t.injectTo === "head" || !t.injectTo);
|
|
453
|
+
const bodyPrepend = tags.filter((t) => t.injectTo === "body-prepend");
|
|
454
|
+
const body = tags.filter((t) => t.injectTo === "body");
|
|
455
|
+
if (headPrepend.length) {
|
|
456
|
+
html = html.replace(/<head([^>]*)>/i, `<head$1>
|
|
457
|
+
${serializeTags(headPrepend)}`);
|
|
512
458
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
459
|
+
if (head.length) {
|
|
460
|
+
html = html.replace(/<\/head>/i, `${serializeTags(head)}
|
|
461
|
+
</head>`);
|
|
516
462
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
463
|
+
if (bodyPrepend.length) {
|
|
464
|
+
html = html.replace(/<body([^>]*)>/i, `<body$1>
|
|
465
|
+
${serializeTags(bodyPrepend)}`);
|
|
520
466
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
467
|
+
if (body.length) {
|
|
468
|
+
html = html.replace(/<\/body>/i, `${serializeTags(body)}
|
|
469
|
+
</body>`);
|
|
524
470
|
}
|
|
525
|
-
return
|
|
471
|
+
return html;
|
|
526
472
|
}
|
|
527
|
-
function
|
|
528
|
-
|
|
529
|
-
if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
|
|
530
|
-
if (cleanUrl.startsWith("/@modules/")) return true;
|
|
531
|
-
if (!import_node_path8.default.extname(cleanUrl)) return true;
|
|
532
|
-
return false;
|
|
473
|
+
function serializeTags(tags) {
|
|
474
|
+
return tags.map(serializeTag).join("\n");
|
|
533
475
|
}
|
|
534
|
-
function
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
socket.addEventListener('message', ({ data }) => {
|
|
541
|
-
const payload = JSON.parse(data);
|
|
542
|
-
switch (payload.type) {
|
|
543
|
-
case 'connected':
|
|
544
|
-
console.log('[nasti] connected.');
|
|
545
|
-
break;
|
|
546
|
-
case 'update':
|
|
547
|
-
payload.updates.forEach((update) => {
|
|
548
|
-
if (update.type === 'js-update') {
|
|
549
|
-
fetchUpdate(update);
|
|
550
|
-
} else if (update.type === 'css-update') {
|
|
551
|
-
updateCss(update.path);
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
break;
|
|
555
|
-
case 'full-reload':
|
|
556
|
-
console.log('[nasti] full reload');
|
|
557
|
-
location.reload();
|
|
558
|
-
break;
|
|
559
|
-
case 'error':
|
|
560
|
-
console.error('[nasti] error:', payload.err.message);
|
|
561
|
-
showErrorOverlay(payload.err);
|
|
562
|
-
break;
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
async function fetchUpdate(update) {
|
|
567
|
-
const mod = hotModulesMap.get(update.path);
|
|
568
|
-
if (mod) {
|
|
569
|
-
const newMod = await import(update.acceptedPath + '?t=' + update.timestamp);
|
|
570
|
-
mod.callbacks.forEach((cb) => cb(newMod));
|
|
571
|
-
} else {
|
|
572
|
-
// \u6CA1\u6709\u6CE8\u518C hot \u56DE\u8C03\uFF0C\u5C1D\u8BD5\u91CD\u65B0 import
|
|
573
|
-
await import(update.path + '?t=' + update.timestamp);
|
|
476
|
+
function serializeTag(tag) {
|
|
477
|
+
const attrs = tag.attrs ? " " + Object.entries(tag.attrs).map(([k, v]) => v === true ? k : `${k}="${v}"`).join(" ") : "";
|
|
478
|
+
const children = typeof tag.children === "string" ? tag.children : tag.children ? serializeTags(tag.children) : "";
|
|
479
|
+
const selfClosing = ["link", "meta", "br", "hr", "img", "input"].includes(tag.tag);
|
|
480
|
+
if (selfClosing && !children) {
|
|
481
|
+
return ` <${tag.tag}${attrs} />`;
|
|
574
482
|
}
|
|
483
|
+
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
575
484
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
fetch(path + '?t=' + Date.now())
|
|
581
|
-
.then(r => r.text())
|
|
582
|
-
.then(css => { el.textContent = css; });
|
|
583
|
-
}
|
|
485
|
+
async function readHtmlFile(root) {
|
|
486
|
+
const htmlPath = import_node_path5.default.resolve(root, "index.html");
|
|
487
|
+
if (!import_node_fs4.default.existsSync(htmlPath)) return null;
|
|
488
|
+
return import_node_fs4.default.readFileSync(htmlPath, "utf-8");
|
|
584
489
|
}
|
|
490
|
+
var import_node_path5, import_node_fs4;
|
|
491
|
+
var init_html = __esm({
|
|
492
|
+
"src/plugins/html.ts"() {
|
|
493
|
+
"use strict";
|
|
494
|
+
import_node_path5 = __toESM(require("path"), 1);
|
|
495
|
+
import_node_fs4 = __toESM(require("fs"), 1);
|
|
496
|
+
}
|
|
497
|
+
});
|
|
585
498
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
overlay.style.cssText = 'position:fixed;inset:0;z-index:99999;background:rgba(0,0,0,0.85);color:#fff;font-family:monospace;padding:2rem;overflow:auto;';
|
|
590
|
-
const title = document.createElement('h2');
|
|
591
|
-
title.style.color = '#ff5555';
|
|
592
|
-
title.textContent = 'Build Error';
|
|
593
|
-
const pre = document.createElement('pre');
|
|
594
|
-
pre.textContent = err.message + '\\n' + (err.stack || '');
|
|
595
|
-
const btn = document.createElement('button');
|
|
596
|
-
btn.style.cssText = 'margin-top:1rem;padding:0.5rem 1rem;cursor:pointer';
|
|
597
|
-
btn.textContent = 'Close';
|
|
598
|
-
btn.onclick = () => overlay.remove();
|
|
599
|
-
overlay.appendChild(title);
|
|
600
|
-
overlay.appendChild(pre);
|
|
601
|
-
overlay.appendChild(btn);
|
|
602
|
-
document.body.appendChild(overlay);
|
|
499
|
+
// src/core/transformer.ts
|
|
500
|
+
function shouldTransform(id) {
|
|
501
|
+
return TS_EXTENSIONS.test(id) || JSX_EXTENSIONS.test(id) || JS_EXTENSIONS.test(id) && false;
|
|
603
502
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
// \u66B4\u9732\u7ED9\u6A21\u5757\u4F7F\u7528
|
|
628
|
-
if (!window.__nasti_hot_map) window.__nasti_hot_map = new Map();
|
|
629
|
-
window.__NASTI_HMR__ = { createHotContext };
|
|
630
|
-
`;
|
|
503
|
+
function transformCode(filename, code, options = {}) {
|
|
504
|
+
const isTS = TS_EXTENSIONS.test(filename) || /\.tsx$/.test(filename);
|
|
505
|
+
const isJSX = JSX_EXTENSIONS.test(filename);
|
|
506
|
+
const result = (0, import_oxc_transform.transformSync)(filename, code, {
|
|
507
|
+
typescript: isTS ? {} : void 0,
|
|
508
|
+
jsx: isJSX || /\.tsx$/.test(filename) ? {
|
|
509
|
+
runtime: options.jsxRuntime ?? "automatic",
|
|
510
|
+
importSource: options.jsxImportSource ?? "react",
|
|
511
|
+
refresh: options.reactRefresh ?? false
|
|
512
|
+
} : void 0,
|
|
513
|
+
sourcemap: options.sourcemap ?? true
|
|
514
|
+
});
|
|
515
|
+
if (result.errors && result.errors.length > 0) {
|
|
516
|
+
const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
|
|
517
|
+
throw new Error(`OXC transform failed for ${filename}:
|
|
518
|
+
${msg}`);
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
code: result.code,
|
|
522
|
+
map: result.map ? JSON.stringify(result.map) : null
|
|
523
|
+
};
|
|
631
524
|
}
|
|
632
|
-
var
|
|
633
|
-
var
|
|
634
|
-
"src/
|
|
525
|
+
var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
|
|
526
|
+
var init_transformer = __esm({
|
|
527
|
+
"src/core/transformer.ts"() {
|
|
635
528
|
"use strict";
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
init_env();
|
|
641
|
-
REACT_REFRESH_RUNTIME = `
|
|
642
|
-
export function createSignatureFunctionForTransform() {
|
|
643
|
-
return function(type, key, forceReset, getCustomHooks) { return type; };
|
|
644
|
-
}
|
|
645
|
-
export function register(type, id) {}
|
|
646
|
-
export default { createSignatureFunctionForTransform, register };
|
|
647
|
-
`;
|
|
648
|
-
REACT_REFRESH_PREAMBLE = `
|
|
649
|
-
import RefreshRuntime from '/@react-refresh';
|
|
650
|
-
if (!window.$RefreshReg$) {
|
|
651
|
-
window.$RefreshReg$ = (type, id) => RefreshRuntime.register(type, import.meta.url + ' ' + id);
|
|
652
|
-
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
|
|
653
|
-
}
|
|
654
|
-
`;
|
|
655
|
-
REACT_REFRESH_FOOTER = `
|
|
656
|
-
if (import.meta.hot) {
|
|
657
|
-
import.meta.hot.accept();
|
|
658
|
-
}
|
|
659
|
-
`;
|
|
660
|
-
esmBundleCache = /* @__PURE__ */ new Map();
|
|
661
|
-
VALID_IDENT = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
662
|
-
RESOLVE_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".json", ".vue"];
|
|
663
|
-
ESM_CONDITIONS = ["import", "browser", "module", "default"];
|
|
529
|
+
import_oxc_transform = require("oxc-transform");
|
|
530
|
+
JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
|
|
531
|
+
TS_EXTENSIONS = /\.(ts|mts|cts)$/;
|
|
532
|
+
JSX_EXTENSIONS = /\.(jsx|tsx)$/;
|
|
664
533
|
}
|
|
665
534
|
});
|
|
666
535
|
|
|
667
|
-
// src/
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
host: "localhost",
|
|
692
|
-
https: false,
|
|
693
|
-
open: false,
|
|
694
|
-
proxy: {},
|
|
695
|
-
cors: true,
|
|
696
|
-
hmr: true
|
|
697
|
-
};
|
|
698
|
-
var defaultBuild = {
|
|
699
|
-
outDir: "dist",
|
|
700
|
-
assetsDir: "assets",
|
|
701
|
-
minify: true,
|
|
702
|
-
sourcemap: false,
|
|
703
|
-
target: "es2022",
|
|
704
|
-
rolldownOptions: {},
|
|
705
|
-
emptyOutDir: true
|
|
706
|
-
};
|
|
707
|
-
var defaults = {
|
|
708
|
-
root: ".",
|
|
709
|
-
base: "/",
|
|
710
|
-
mode: "development",
|
|
711
|
-
framework: "auto",
|
|
712
|
-
resolve: defaultResolve,
|
|
713
|
-
server: defaultServer,
|
|
714
|
-
build: defaultBuild,
|
|
715
|
-
plugins: [],
|
|
716
|
-
envPrefix: ["NASTI_", "VITE_"],
|
|
717
|
-
logLevel: "info"
|
|
718
|
-
};
|
|
719
|
-
|
|
720
|
-
// src/config/index.ts
|
|
721
|
-
function loadTsconfigPaths(root) {
|
|
722
|
-
const tsconfigPath = import_node_path.default.resolve(root, "tsconfig.json");
|
|
723
|
-
if (!import_node_fs.default.existsSync(tsconfigPath)) return {};
|
|
724
|
-
try {
|
|
725
|
-
const content = import_node_fs.default.readFileSync(tsconfigPath, "utf-8");
|
|
726
|
-
const stripped = content.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
727
|
-
const tsconfig = JSON.parse(stripped);
|
|
728
|
-
const paths = tsconfig?.compilerOptions?.paths ?? {};
|
|
729
|
-
const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? ".";
|
|
730
|
-
const alias = {};
|
|
731
|
-
for (const [pattern, targets] of Object.entries(paths)) {
|
|
732
|
-
if (!targets.length) continue;
|
|
733
|
-
const cleanKey = pattern.replace(/\/\*$/, "");
|
|
734
|
-
const cleanTarget = targets[0].replace(/\/\*$/, "");
|
|
735
|
-
alias[cleanKey] = import_node_path.default.resolve(root, baseUrl, cleanTarget);
|
|
536
|
+
// src/core/env.ts
|
|
537
|
+
function loadEnv(mode, root, prefixes) {
|
|
538
|
+
const envFiles = [
|
|
539
|
+
".env",
|
|
540
|
+
`.env.${mode}`,
|
|
541
|
+
".env.local",
|
|
542
|
+
`.env.${mode}.local`
|
|
543
|
+
];
|
|
544
|
+
const raw = {};
|
|
545
|
+
for (const file of envFiles) {
|
|
546
|
+
const filePath = import_node_path6.default.resolve(root, file);
|
|
547
|
+
if (!import_node_fs5.default.existsSync(filePath)) continue;
|
|
548
|
+
const content = import_node_fs5.default.readFileSync(filePath, "utf-8");
|
|
549
|
+
for (const line of content.split("\n")) {
|
|
550
|
+
const trimmed = line.trim();
|
|
551
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
552
|
+
const eqIdx = trimmed.indexOf("=");
|
|
553
|
+
if (eqIdx === -1) continue;
|
|
554
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
555
|
+
let value = trimmed.slice(eqIdx + 1).trim();
|
|
556
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
557
|
+
value = value.slice(1, -1);
|
|
558
|
+
}
|
|
559
|
+
raw[key] = value;
|
|
736
560
|
}
|
|
737
|
-
return alias;
|
|
738
|
-
} catch {
|
|
739
|
-
return {};
|
|
740
561
|
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
var CONFIG_FILES = [
|
|
746
|
-
"nasti.config.ts",
|
|
747
|
-
"nasti.config.js",
|
|
748
|
-
"nasti.config.mjs",
|
|
749
|
-
"nasti.config.mts"
|
|
750
|
-
];
|
|
751
|
-
async function loadConfigFromFile(root) {
|
|
752
|
-
for (const file of CONFIG_FILES) {
|
|
753
|
-
const filePath = import_node_path.default.resolve(root, file);
|
|
754
|
-
if (!import_node_fs.default.existsSync(filePath)) continue;
|
|
755
|
-
if (file.endsWith(".ts") || file.endsWith(".mts")) {
|
|
756
|
-
return await loadTsConfig(filePath);
|
|
562
|
+
const filtered = {};
|
|
563
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
564
|
+
if (prefixes.some((prefix) => key.startsWith(prefix))) {
|
|
565
|
+
filtered[key] = value;
|
|
757
566
|
}
|
|
758
|
-
const mod = await import((0, import_node_url.pathToFileURL)(filePath).href);
|
|
759
|
-
return mod.default ?? mod;
|
|
760
567
|
}
|
|
761
|
-
return
|
|
568
|
+
return filtered;
|
|
762
569
|
}
|
|
763
|
-
|
|
764
|
-
const
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
typescript: {}
|
|
768
|
-
});
|
|
769
|
-
const tmpFile = filePath + ".timestamp-" + Date.now() + ".mjs";
|
|
770
|
-
try {
|
|
771
|
-
import_node_fs.default.writeFileSync(tmpFile, result.code);
|
|
772
|
-
const mod = await import((0, import_node_url.pathToFileURL)(tmpFile).href);
|
|
773
|
-
return mod.default ?? mod;
|
|
774
|
-
} finally {
|
|
775
|
-
import_node_fs.default.unlinkSync(tmpFile);
|
|
570
|
+
function buildEnvDefine(env, mode) {
|
|
571
|
+
const define = {};
|
|
572
|
+
for (const [key, value] of Object.entries(env)) {
|
|
573
|
+
define[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
776
574
|
}
|
|
575
|
+
define["import.meta.env.MODE"] = JSON.stringify(mode);
|
|
576
|
+
define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
|
|
577
|
+
define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
|
|
578
|
+
define["import.meta.env.SSR"] = "false";
|
|
579
|
+
return define;
|
|
777
580
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
...fileConfig.plugins ?? [],
|
|
784
|
-
...inlineConfig.plugins ?? []
|
|
785
|
-
];
|
|
786
|
-
const env = { mode: merged.mode ?? defaults.mode, command };
|
|
787
|
-
for (const plugin of rawPlugins) {
|
|
788
|
-
if (plugin.config) {
|
|
789
|
-
const result = await plugin.config(merged, env);
|
|
790
|
-
if (result) Object.assign(merged, result);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
const resolved = {
|
|
794
|
-
root,
|
|
795
|
-
base: merged.base ?? defaults.base,
|
|
796
|
-
mode: command === "build" ? "production" : "development",
|
|
797
|
-
framework: merged.framework ?? defaults.framework,
|
|
798
|
-
command,
|
|
799
|
-
resolve: {
|
|
800
|
-
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
801
|
-
alias: { ...loadTsconfigPaths(root), ...defaults.resolve.alias, ...merged.resolve?.alias },
|
|
802
|
-
extensions: merged.resolve?.extensions ?? defaults.resolve.extensions,
|
|
803
|
-
conditions: merged.resolve?.conditions ?? defaults.resolve.conditions,
|
|
804
|
-
mainFields: merged.resolve?.mainFields ?? defaults.resolve.mainFields
|
|
805
|
-
},
|
|
806
|
-
plugins: [],
|
|
807
|
-
server: { ...defaults.server, ...merged.server },
|
|
808
|
-
build: { ...defaults.build, ...merged.build },
|
|
809
|
-
envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
|
|
810
|
-
logLevel: merged.logLevel ?? defaults.logLevel
|
|
811
|
-
};
|
|
812
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
813
|
-
if (!p.apply) return true;
|
|
814
|
-
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
815
|
-
return p.apply === command;
|
|
816
|
-
});
|
|
817
|
-
resolved.plugins = filteredPlugins;
|
|
818
|
-
for (const plugin of resolved.plugins) {
|
|
819
|
-
if (plugin.configResolved) {
|
|
820
|
-
await plugin.configResolved(resolved);
|
|
821
|
-
}
|
|
581
|
+
function replaceEnvInCode(code, define) {
|
|
582
|
+
let result = code;
|
|
583
|
+
for (const [key, value] of Object.entries(define)) {
|
|
584
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
585
|
+
result = result.replace(new RegExp(escaped, "g"), value);
|
|
822
586
|
}
|
|
823
|
-
return
|
|
587
|
+
return result;
|
|
824
588
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
result[key] ?? {},
|
|
832
|
-
val
|
|
833
|
-
);
|
|
834
|
-
} else if (val !== void 0) {
|
|
835
|
-
result[key] = val;
|
|
836
|
-
}
|
|
589
|
+
var import_node_path6, import_node_fs5;
|
|
590
|
+
var init_env = __esm({
|
|
591
|
+
"src/core/env.ts"() {
|
|
592
|
+
"use strict";
|
|
593
|
+
import_node_path6 = __toESM(require("path"), 1);
|
|
594
|
+
import_node_fs5 = __toESM(require("fs"), 1);
|
|
837
595
|
}
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// src/build/index.ts
|
|
842
|
-
var import_node_path7 = __toESM(require("path"), 1);
|
|
843
|
-
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
844
|
-
var import_rolldown = require("rolldown");
|
|
596
|
+
});
|
|
845
597
|
|
|
846
|
-
// src/
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
598
|
+
// src/core/plugin-container.ts
|
|
599
|
+
function sortPlugins(plugins) {
|
|
600
|
+
const pre = [];
|
|
601
|
+
const normal = [];
|
|
602
|
+
const post = [];
|
|
603
|
+
for (const plugin of plugins) {
|
|
604
|
+
if (plugin.enforce === "pre") pre.push(plugin);
|
|
605
|
+
else if (plugin.enforce === "post") post.push(plugin);
|
|
606
|
+
else normal.push(plugin);
|
|
607
|
+
}
|
|
608
|
+
return [...pre, ...normal, ...post];
|
|
609
|
+
}
|
|
610
|
+
var PluginContainer;
|
|
611
|
+
var init_plugin_container = __esm({
|
|
612
|
+
"src/core/plugin-container.ts"() {
|
|
613
|
+
"use strict";
|
|
614
|
+
PluginContainer = class {
|
|
615
|
+
plugins;
|
|
616
|
+
config;
|
|
617
|
+
ctx;
|
|
618
|
+
emittedFiles = /* @__PURE__ */ new Map();
|
|
619
|
+
constructor(config) {
|
|
620
|
+
this.config = config;
|
|
621
|
+
this.plugins = sortPlugins(config.plugins);
|
|
622
|
+
this.ctx = this.createContext();
|
|
623
|
+
}
|
|
624
|
+
createContext() {
|
|
625
|
+
const container = this;
|
|
626
|
+
return {
|
|
627
|
+
async resolve(source, importer) {
|
|
628
|
+
return container.resolveId(source, importer);
|
|
629
|
+
},
|
|
630
|
+
emitFile(file) {
|
|
631
|
+
const fileName = file.fileName ?? file.name ?? `asset-${container.emittedFiles.size}`;
|
|
632
|
+
const id = `emitted:${fileName}`;
|
|
633
|
+
container.emittedFiles.set(id, {
|
|
634
|
+
fileName,
|
|
635
|
+
source: file.source ?? ""
|
|
636
|
+
});
|
|
637
|
+
return id;
|
|
638
|
+
},
|
|
639
|
+
getModuleInfo(_id) {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
/** 返回所有通过 emitFile() 输出的文件 */
|
|
645
|
+
getEmittedFiles() {
|
|
646
|
+
return Array.from(this.emittedFiles.values());
|
|
647
|
+
}
|
|
648
|
+
async buildStart() {
|
|
649
|
+
for (const plugin of this.plugins) {
|
|
650
|
+
if (plugin.buildStart) {
|
|
651
|
+
await plugin.buildStart.call(this.ctx);
|
|
862
652
|
}
|
|
863
|
-
break;
|
|
864
653
|
}
|
|
865
654
|
}
|
|
866
|
-
|
|
867
|
-
const
|
|
868
|
-
|
|
655
|
+
async buildEnd(error) {
|
|
656
|
+
for (const plugin of this.plugins) {
|
|
657
|
+
if (plugin.buildEnd) {
|
|
658
|
+
await plugin.buildEnd.call(this.ctx, error);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
869
661
|
}
|
|
870
|
-
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
662
|
+
async resolveId(source, importer, options = {}) {
|
|
663
|
+
for (const plugin of this.plugins) {
|
|
664
|
+
if (!plugin.resolveId) continue;
|
|
665
|
+
const result = await plugin.resolveId.call(
|
|
666
|
+
this.ctx,
|
|
667
|
+
source,
|
|
668
|
+
importer ?? void 0,
|
|
669
|
+
{ isEntry: options.isEntry ?? false, ssr: false }
|
|
670
|
+
);
|
|
671
|
+
if (result != null) return result;
|
|
672
|
+
}
|
|
673
|
+
return null;
|
|
875
674
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
return resolved;
|
|
882
|
-
} catch {
|
|
883
|
-
return null;
|
|
675
|
+
async load(id) {
|
|
676
|
+
for (const plugin of this.plugins) {
|
|
677
|
+
if (!plugin.load) continue;
|
|
678
|
+
const result = await plugin.load.call(this.ctx, id);
|
|
679
|
+
if (result != null) return result;
|
|
884
680
|
}
|
|
681
|
+
return null;
|
|
885
682
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
683
|
+
async transform(code, id) {
|
|
684
|
+
let currentCode = code;
|
|
685
|
+
for (const plugin of this.plugins) {
|
|
686
|
+
if (!plugin.transform) continue;
|
|
687
|
+
const result = await plugin.transform.call(this.ctx, currentCode, id);
|
|
688
|
+
if (result == null) continue;
|
|
689
|
+
if (typeof result === "string") {
|
|
690
|
+
currentCode = result;
|
|
691
|
+
} else {
|
|
692
|
+
currentCode = result.code;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return currentCode === code ? null : { code: currentCode };
|
|
893
696
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
697
|
+
/** 完整的模块处理管道: resolveId → load → transform */
|
|
698
|
+
async processModule(source, importer) {
|
|
699
|
+
const resolveResult = await this.resolveId(source, importer, {
|
|
700
|
+
isEntry: !importer
|
|
701
|
+
});
|
|
702
|
+
if (resolveResult == null) return null;
|
|
703
|
+
const id = typeof resolveResult === "string" ? resolveResult : resolveResult.id;
|
|
704
|
+
const loadResult = await this.load(id);
|
|
705
|
+
if (loadResult == null) return null;
|
|
706
|
+
const loadedCode = typeof loadResult === "string" ? loadResult : loadResult.code;
|
|
707
|
+
const transformResult = await this.transform(loadedCode, id);
|
|
708
|
+
const finalCode = transformResult == null ? loadedCode : typeof transformResult === "string" ? transformResult : transformResult.code;
|
|
709
|
+
return { id, code: finalCode };
|
|
710
|
+
}
|
|
711
|
+
getPlugins() {
|
|
712
|
+
return this.plugins;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
901
715
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// src/build/index.ts
|
|
719
|
+
var build_exports = {};
|
|
720
|
+
__export(build_exports, {
|
|
721
|
+
build: () => build
|
|
722
|
+
});
|
|
723
|
+
async function build(inlineConfig = {}) {
|
|
724
|
+
const config = await resolveConfig(inlineConfig, "build");
|
|
725
|
+
const startTime = performance.now();
|
|
726
|
+
console.log(import_picocolors.default.cyan("\n\u{1F528} nasti build") + import_picocolors.default.dim(` v${"1.4.0"}`));
|
|
727
|
+
console.log(import_picocolors.default.dim(` root: ${config.root}`));
|
|
728
|
+
console.log(import_picocolors.default.dim(` mode: ${config.mode}`));
|
|
729
|
+
const outDir = import_node_path7.default.resolve(config.root, config.build.outDir);
|
|
730
|
+
if (config.build.emptyOutDir && import_node_fs6.default.existsSync(outDir)) {
|
|
731
|
+
import_node_fs6.default.rmSync(outDir, { recursive: true, force: true });
|
|
732
|
+
}
|
|
733
|
+
import_node_fs6.default.mkdirSync(outDir, { recursive: true });
|
|
734
|
+
const html = await readHtmlFile(config.root);
|
|
735
|
+
let entryPoints = [];
|
|
736
|
+
if (html) {
|
|
737
|
+
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
738
|
+
for (const match of scriptMatches) {
|
|
739
|
+
const src = match[1];
|
|
740
|
+
if (src && !src.startsWith("http")) {
|
|
741
|
+
entryPoints.push(import_node_path7.default.resolve(config.root, src.replace(/^\//, "")));
|
|
742
|
+
}
|
|
906
743
|
}
|
|
907
744
|
}
|
|
908
|
-
if (
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
745
|
+
if (entryPoints.length === 0) {
|
|
746
|
+
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
747
|
+
for (const entry of fallbackEntries) {
|
|
748
|
+
const fullPath = import_node_path7.default.resolve(config.root, entry);
|
|
749
|
+
if (import_node_fs6.default.existsSync(fullPath)) {
|
|
750
|
+
entryPoints.push(fullPath);
|
|
751
|
+
break;
|
|
913
752
|
}
|
|
914
753
|
}
|
|
915
754
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
755
|
+
if (entryPoints.length === 0) {
|
|
756
|
+
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
757
|
+
}
|
|
758
|
+
const builtinPlugins = [
|
|
759
|
+
resolvePlugin(config),
|
|
760
|
+
cssPlugin(config),
|
|
761
|
+
assetsPlugin(config)
|
|
762
|
+
];
|
|
763
|
+
const allPlugins = [...builtinPlugins, ...config.plugins];
|
|
764
|
+
const pluginContainer = new PluginContainer(config);
|
|
765
|
+
await pluginContainer.buildStart();
|
|
766
|
+
const oxcTransformPlugin = {
|
|
767
|
+
name: "nasti:oxc-transform",
|
|
928
768
|
transform(code, id) {
|
|
929
|
-
if (!id
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
769
|
+
if (!shouldTransform(id)) return null;
|
|
770
|
+
const result = transformCode(id, code, {
|
|
771
|
+
sourcemap: !!config.build.sourcemap,
|
|
772
|
+
jsxRuntime: "automatic",
|
|
773
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
774
|
+
});
|
|
775
|
+
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
779
|
+
const envDefine = buildEnvDefine(env, config.mode);
|
|
780
|
+
const bundle = await (0, import_rolldown.rolldown)({
|
|
781
|
+
input: entryPoints,
|
|
782
|
+
define: envDefine,
|
|
783
|
+
plugins: [
|
|
784
|
+
oxcTransformPlugin,
|
|
785
|
+
// 转换 Nasti 插件为 Rolldown 插件格式
|
|
786
|
+
...allPlugins.map((p) => ({
|
|
787
|
+
name: p.name,
|
|
788
|
+
resolveId: p.resolveId,
|
|
789
|
+
load: p.load,
|
|
790
|
+
transform: p.transform,
|
|
791
|
+
buildStart: p.buildStart,
|
|
792
|
+
buildEnd: p.buildEnd
|
|
793
|
+
}))
|
|
794
|
+
],
|
|
795
|
+
...config.build.rolldownOptions
|
|
949
796
|
});
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
797
|
+
const { output } = await bundle.write({
|
|
798
|
+
dir: outDir,
|
|
799
|
+
format: "esm",
|
|
800
|
+
sourcemap: !!config.build.sourcemap,
|
|
801
|
+
minify: !!config.build.minify,
|
|
802
|
+
entryFileNames: "assets/[name].[hash].js",
|
|
803
|
+
chunkFileNames: "assets/[name].[hash].js",
|
|
804
|
+
assetFileNames: "assets/[name].[hash][extname]"
|
|
805
|
+
});
|
|
806
|
+
await bundle.close();
|
|
807
|
+
await pluginContainer.buildEnd();
|
|
808
|
+
for (const ef of pluginContainer.getEmittedFiles()) {
|
|
809
|
+
const dest = import_node_path7.default.resolve(outDir, ef.fileName);
|
|
810
|
+
import_node_fs6.default.mkdirSync(import_node_path7.default.dirname(dest), { recursive: true });
|
|
811
|
+
import_node_fs6.default.writeFileSync(dest, ef.source);
|
|
812
|
+
}
|
|
813
|
+
if (html) {
|
|
814
|
+
let processedHtml = html;
|
|
815
|
+
const htmlPlugin_ = htmlPlugin(config);
|
|
816
|
+
if (htmlPlugin_.transformIndexHtml) {
|
|
817
|
+
const result = await htmlPlugin_.transformIndexHtml(processedHtml);
|
|
818
|
+
if (typeof result === "string") {
|
|
819
|
+
processedHtml = result;
|
|
820
|
+
} else if (result && "html" in result) {
|
|
821
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
822
|
+
} else if (Array.isArray(result)) {
|
|
823
|
+
processedHtml = processHtml(processedHtml, result);
|
|
955
824
|
}
|
|
956
|
-
return rewritten !== code ? { code: rewritten } : null;
|
|
957
825
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
826
|
+
for (const chunk of output) {
|
|
827
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
828
|
+
const originalEntry = import_node_path7.default.relative(config.root, chunk.facadeModuleId);
|
|
829
|
+
processedHtml = processedHtml.replace(
|
|
830
|
+
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
831
|
+
`$1${config.base}${chunk.fileName}$3`
|
|
832
|
+
);
|
|
833
|
+
}
|
|
964
834
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
835
|
+
import_node_fs6.default.writeFileSync(import_node_path7.default.resolve(outDir, "index.html"), processedHtml);
|
|
836
|
+
}
|
|
837
|
+
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
838
|
+
const totalSize = output.reduce((sum, chunk) => {
|
|
839
|
+
if (chunk.type === "chunk" && chunk.code) return sum + chunk.code.length;
|
|
840
|
+
return sum;
|
|
841
|
+
}, 0);
|
|
842
|
+
console.log(import_picocolors.default.green(`
|
|
843
|
+
\u2713 Built in ${elapsed}s`));
|
|
844
|
+
console.log(import_picocolors.default.dim(` ${output.length} files, ${formatSize(totalSize)} total`));
|
|
845
|
+
console.log(import_picocolors.default.dim(` output: ${config.build.outDir}/
|
|
846
|
+
`));
|
|
847
|
+
return { output };
|
|
969
848
|
}
|
|
849
|
+
function formatSize(bytes) {
|
|
850
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
851
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;
|
|
852
|
+
return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
|
|
853
|
+
}
|
|
854
|
+
function escapeRegExp(string) {
|
|
855
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
856
|
+
}
|
|
857
|
+
var import_node_path7, import_node_fs6, import_rolldown, import_picocolors;
|
|
858
|
+
var init_build = __esm({
|
|
859
|
+
"src/build/index.ts"() {
|
|
860
|
+
"use strict";
|
|
861
|
+
import_node_path7 = __toESM(require("path"), 1);
|
|
862
|
+
import_node_fs6 = __toESM(require("fs"), 1);
|
|
863
|
+
import_rolldown = require("rolldown");
|
|
864
|
+
init_config();
|
|
865
|
+
init_resolve();
|
|
866
|
+
init_css();
|
|
867
|
+
init_assets();
|
|
868
|
+
init_html();
|
|
869
|
+
init_transformer();
|
|
870
|
+
init_env();
|
|
871
|
+
init_plugin_container();
|
|
872
|
+
import_picocolors = __toESM(require("picocolors"), 1);
|
|
873
|
+
}
|
|
874
|
+
});
|
|
970
875
|
|
|
971
|
-
// src/
|
|
972
|
-
var
|
|
973
|
-
var
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
".webp",
|
|
983
|
-
".avif",
|
|
984
|
-
".mp4",
|
|
985
|
-
".webm",
|
|
986
|
-
".ogg",
|
|
987
|
-
".mp3",
|
|
988
|
-
".wav",
|
|
989
|
-
".flac",
|
|
990
|
-
".aac",
|
|
991
|
-
".woff",
|
|
992
|
-
".woff2",
|
|
993
|
-
".eot",
|
|
994
|
-
".ttf",
|
|
995
|
-
".otf",
|
|
996
|
-
".pdf",
|
|
997
|
-
".txt"
|
|
998
|
-
]);
|
|
999
|
-
function assetsPlugin(config) {
|
|
1000
|
-
return {
|
|
1001
|
-
name: "nasti:assets",
|
|
1002
|
-
resolveId(source) {
|
|
1003
|
-
if (source.endsWith("?url") || source.endsWith("?raw")) {
|
|
1004
|
-
return source;
|
|
876
|
+
// src/core/module-graph.ts
|
|
877
|
+
var ModuleGraph;
|
|
878
|
+
var init_module_graph = __esm({
|
|
879
|
+
"src/core/module-graph.ts"() {
|
|
880
|
+
"use strict";
|
|
881
|
+
ModuleGraph = class {
|
|
882
|
+
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
883
|
+
idToModuleMap = /* @__PURE__ */ new Map();
|
|
884
|
+
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
885
|
+
getModuleByUrl(url) {
|
|
886
|
+
return this.urlToModuleMap.get(url);
|
|
1005
887
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
888
|
+
getModuleById(id) {
|
|
889
|
+
return this.idToModuleMap.get(id);
|
|
890
|
+
}
|
|
891
|
+
getModulesByFile(file) {
|
|
892
|
+
return this.fileToModulesMap.get(file);
|
|
893
|
+
}
|
|
894
|
+
async ensureEntryFromUrl(url) {
|
|
895
|
+
let mod = this.urlToModuleMap.get(url);
|
|
896
|
+
if (mod) return mod;
|
|
897
|
+
mod = this.createModule(url);
|
|
898
|
+
this.urlToModuleMap.set(url, mod);
|
|
899
|
+
return mod;
|
|
900
|
+
}
|
|
901
|
+
createModule(url, id) {
|
|
902
|
+
const mod = {
|
|
903
|
+
id: id ?? url,
|
|
904
|
+
file: null,
|
|
905
|
+
url,
|
|
906
|
+
type: url.endsWith(".css") ? "css" : "js",
|
|
907
|
+
importers: /* @__PURE__ */ new Set(),
|
|
908
|
+
importedModules: /* @__PURE__ */ new Set(),
|
|
909
|
+
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
910
|
+
transformResult: null,
|
|
911
|
+
lastHMRTimestamp: 0,
|
|
912
|
+
isSelfAccepting: false
|
|
913
|
+
};
|
|
914
|
+
this.idToModuleMap.set(mod.id, mod);
|
|
915
|
+
return mod;
|
|
916
|
+
}
|
|
917
|
+
/** 注册文件路径到模块的映射 */
|
|
918
|
+
registerModule(mod, file) {
|
|
919
|
+
mod.file = file;
|
|
920
|
+
let mods = this.fileToModulesMap.get(file);
|
|
921
|
+
if (!mods) {
|
|
922
|
+
mods = /* @__PURE__ */ new Set();
|
|
923
|
+
this.fileToModulesMap.set(file, mods);
|
|
1015
924
|
}
|
|
925
|
+
mods.add(mod);
|
|
1016
926
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
927
|
+
/** 更新模块依赖关系 */
|
|
928
|
+
updateModuleImports(mod, importedIds) {
|
|
929
|
+
for (const imported of mod.importedModules) {
|
|
930
|
+
imported.importers.delete(mod);
|
|
931
|
+
}
|
|
932
|
+
mod.importedModules.clear();
|
|
933
|
+
for (const id of importedIds) {
|
|
934
|
+
const importedMod = this.idToModuleMap.get(id);
|
|
935
|
+
if (importedMod) {
|
|
936
|
+
mod.importedModules.add(importedMod);
|
|
937
|
+
importedMod.importers.add(mod);
|
|
938
|
+
}
|
|
1023
939
|
}
|
|
1024
|
-
const content = import_node_fs3.default.readFileSync(file);
|
|
1025
|
-
const hash = import_node_crypto.default.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
1026
|
-
const basename = import_node_path4.default.basename(file, ext);
|
|
1027
|
-
const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
|
|
1028
|
-
return `export default ${JSON.stringify(config.base + hashedName)}`;
|
|
1029
940
|
}
|
|
1030
|
-
|
|
941
|
+
/** 使模块的转换缓存失效 */
|
|
942
|
+
invalidateModule(mod) {
|
|
943
|
+
mod.transformResult = null;
|
|
944
|
+
mod.lastHMRTimestamp = Date.now();
|
|
945
|
+
}
|
|
946
|
+
/** 使所有模块缓存失效 */
|
|
947
|
+
invalidateAll() {
|
|
948
|
+
for (const mod of this.idToModuleMap.values()) {
|
|
949
|
+
this.invalidateModule(mod);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
953
|
+
getHmrBoundaries(mod) {
|
|
954
|
+
const boundaries = [];
|
|
955
|
+
const visited = /* @__PURE__ */ new Set();
|
|
956
|
+
const propagate = (node, via) => {
|
|
957
|
+
if (visited.has(node)) return true;
|
|
958
|
+
visited.add(node);
|
|
959
|
+
if (node.isSelfAccepting) {
|
|
960
|
+
boundaries.push({ boundary: node, acceptedVia: via });
|
|
961
|
+
return true;
|
|
962
|
+
}
|
|
963
|
+
if (node.acceptedHmrDeps.has(via)) {
|
|
964
|
+
boundaries.push({ boundary: node, acceptedVia: via });
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
if (node.importers.size === 0) return false;
|
|
968
|
+
for (const importer of node.importers) {
|
|
969
|
+
if (!propagate(importer, node)) return false;
|
|
970
|
+
}
|
|
971
|
+
return true;
|
|
972
|
+
};
|
|
973
|
+
if (mod.isSelfAccepting) {
|
|
974
|
+
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
975
|
+
return boundaries;
|
|
976
|
+
}
|
|
977
|
+
for (const importer of mod.importers) {
|
|
978
|
+
if (!propagate(importer, mod)) {
|
|
979
|
+
return [];
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
return boundaries;
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
// src/server/ws.ts
|
|
989
|
+
function createWebSocketServer(server) {
|
|
990
|
+
const wss = new import_ws.WebSocketServer({ noServer: true });
|
|
991
|
+
const clients = /* @__PURE__ */ new Set();
|
|
992
|
+
server.on("upgrade", (req, socket, head) => {
|
|
993
|
+
if (req.headers["sec-websocket-protocol"] === "nasti-hmr") {
|
|
994
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
995
|
+
wss.emit("connection", ws, req);
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
wss.on("connection", (ws) => {
|
|
1000
|
+
clients.add(ws);
|
|
1001
|
+
ws.send(JSON.stringify({ type: "connected" }));
|
|
1002
|
+
ws.on("close", () => {
|
|
1003
|
+
clients.delete(ws);
|
|
1004
|
+
});
|
|
1005
|
+
ws.on("error", (err) => {
|
|
1006
|
+
console.error("[nasti] WebSocket error:", err);
|
|
1007
|
+
clients.delete(ws);
|
|
1008
|
+
});
|
|
1009
|
+
});
|
|
1010
|
+
return {
|
|
1011
|
+
send(payload) {
|
|
1012
|
+
const data = JSON.stringify(payload);
|
|
1013
|
+
for (const client of clients) {
|
|
1014
|
+
if (client.readyState === 1) {
|
|
1015
|
+
client.send(data);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
close() {
|
|
1020
|
+
clients.clear();
|
|
1021
|
+
wss.close();
|
|
1031
1022
|
}
|
|
1032
1023
|
};
|
|
1033
1024
|
}
|
|
1025
|
+
var import_ws;
|
|
1026
|
+
var init_ws = __esm({
|
|
1027
|
+
"src/server/ws.ts"() {
|
|
1028
|
+
"use strict";
|
|
1029
|
+
import_ws = require("ws");
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1034
1032
|
|
|
1035
|
-
// src/
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
emitFile(file) {
|
|
1058
|
-
const fileName = file.fileName ?? file.name ?? `asset-${container.emittedFiles.size}`;
|
|
1059
|
-
const id = `emitted:${fileName}`;
|
|
1060
|
-
container.emittedFiles.set(id, {
|
|
1061
|
-
fileName,
|
|
1062
|
-
source: file.source ?? ""
|
|
1063
|
-
});
|
|
1064
|
-
return id;
|
|
1065
|
-
},
|
|
1066
|
-
getModuleInfo(_id) {
|
|
1067
|
-
return null;
|
|
1033
|
+
// src/server/middleware.ts
|
|
1034
|
+
var middleware_exports = {};
|
|
1035
|
+
__export(middleware_exports, {
|
|
1036
|
+
transformMiddleware: () => transformMiddleware,
|
|
1037
|
+
transformRequest: () => transformRequest
|
|
1038
|
+
});
|
|
1039
|
+
function transformMiddleware(ctx) {
|
|
1040
|
+
ctx.envDefine = buildEnvDefine(
|
|
1041
|
+
loadEnv(ctx.config.mode, ctx.config.root, ctx.config.envPrefix),
|
|
1042
|
+
ctx.config.mode
|
|
1043
|
+
);
|
|
1044
|
+
return async (req, res, next) => {
|
|
1045
|
+
const url = req.url ?? "/";
|
|
1046
|
+
if (ctx.config.server.cors) {
|
|
1047
|
+
const origin = req.headers.origin ?? "*";
|
|
1048
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
1049
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
|
|
1050
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
1051
|
+
if (req.method === "OPTIONS") {
|
|
1052
|
+
res.statusCode = 204;
|
|
1053
|
+
res.end();
|
|
1054
|
+
return;
|
|
1068
1055
|
}
|
|
1069
|
-
}
|
|
1056
|
+
}
|
|
1057
|
+
if (req.method !== "GET") return next();
|
|
1058
|
+
if (url === "/@nasti/client") {
|
|
1059
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
1060
|
+
res.end(getHmrClientCode());
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
if (url === "/" || url.endsWith(".html")) {
|
|
1064
|
+
const html = await readHtmlFile(ctx.config.root);
|
|
1065
|
+
if (html) {
|
|
1066
|
+
let processedHtml = html;
|
|
1067
|
+
for (const plugin of ctx.config.plugins) {
|
|
1068
|
+
if (plugin.transformIndexHtml) {
|
|
1069
|
+
const result = await plugin.transformIndexHtml(processedHtml);
|
|
1070
|
+
if (typeof result === "string") {
|
|
1071
|
+
processedHtml = result;
|
|
1072
|
+
} else if (result && "html" in result) {
|
|
1073
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
1074
|
+
} else if (Array.isArray(result)) {
|
|
1075
|
+
processedHtml = processHtml(processedHtml, result);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
res.setHeader("Content-Type", "text/html");
|
|
1080
|
+
res.end(processedHtml);
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
if (isModuleRequest(url)) {
|
|
1085
|
+
try {
|
|
1086
|
+
const result = await transformRequest(url, ctx);
|
|
1087
|
+
if (result) {
|
|
1088
|
+
const contentType = url.endsWith(".css") ? "application/javascript" : "application/javascript";
|
|
1089
|
+
res.setHeader("Content-Type", contentType);
|
|
1090
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
1091
|
+
res.end(typeof result === "string" ? result : result.code);
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
} catch (err) {
|
|
1095
|
+
console.error(`[nasti] Transform error: ${url}`, err.message);
|
|
1096
|
+
res.statusCode = 500;
|
|
1097
|
+
res.end(`Transform error: ${err.message}`);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
next();
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
async function transformRequest(url, ctx) {
|
|
1105
|
+
const { config, pluginContainer, moduleGraph } = ctx;
|
|
1106
|
+
const cleanReqUrl = url.split("?")[0];
|
|
1107
|
+
const cached = moduleGraph.getModuleByUrl(url);
|
|
1108
|
+
if (cached?.transformResult) {
|
|
1109
|
+
return cached.transformResult;
|
|
1110
|
+
}
|
|
1111
|
+
if (cleanReqUrl === "/@react-refresh") {
|
|
1112
|
+
return { code: REACT_REFRESH_RUNTIME };
|
|
1113
|
+
}
|
|
1114
|
+
const filePath = resolveUrlToFile(url, config.root);
|
|
1115
|
+
if (!filePath || !import_node_fs8.default.existsSync(filePath)) return null;
|
|
1116
|
+
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
1117
|
+
moduleGraph.registerModule(mod, filePath);
|
|
1118
|
+
if (cleanReqUrl.startsWith("/@modules/")) {
|
|
1119
|
+
const code2 = await bundlePackageAsEsm(filePath);
|
|
1120
|
+
const transformResult2 = { code: code2 };
|
|
1121
|
+
mod.transformResult = transformResult2;
|
|
1122
|
+
return transformResult2;
|
|
1123
|
+
}
|
|
1124
|
+
let code = import_node_fs8.default.readFileSync(filePath, "utf-8");
|
|
1125
|
+
const pluginResult = await pluginContainer.transform(code, filePath);
|
|
1126
|
+
if (pluginResult) {
|
|
1127
|
+
code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
|
|
1128
|
+
}
|
|
1129
|
+
if (shouldTransform(filePath)) {
|
|
1130
|
+
const isJsx = /\.[jt]sx$/.test(filePath);
|
|
1131
|
+
const useRefresh = isJsx && config.framework !== "vue";
|
|
1132
|
+
const result = transformCode(filePath, code, {
|
|
1133
|
+
sourcemap: true,
|
|
1134
|
+
jsxRuntime: "automatic",
|
|
1135
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
1136
|
+
reactRefresh: useRefresh
|
|
1137
|
+
});
|
|
1138
|
+
code = result.code;
|
|
1139
|
+
if (useRefresh) {
|
|
1140
|
+
code = REACT_REFRESH_PREAMBLE + code + REACT_REFRESH_FOOTER;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
const envDefine = ctx.envDefine ?? buildEnvDefine(
|
|
1144
|
+
loadEnv(config.mode, config.root, config.envPrefix),
|
|
1145
|
+
config.mode
|
|
1146
|
+
);
|
|
1147
|
+
code = replaceEnvInCode(code, envDefine);
|
|
1148
|
+
code = rewriteImports(code, config);
|
|
1149
|
+
const transformResult = { code };
|
|
1150
|
+
mod.transformResult = transformResult;
|
|
1151
|
+
return transformResult;
|
|
1152
|
+
}
|
|
1153
|
+
async function bundlePackageAsEsm(entryFile) {
|
|
1154
|
+
if (!esmBundleCache.has(entryFile)) {
|
|
1155
|
+
esmBundleCache.set(entryFile, doBundlePackage(entryFile));
|
|
1156
|
+
}
|
|
1157
|
+
return esmBundleCache.get(entryFile);
|
|
1158
|
+
}
|
|
1159
|
+
async function doBundlePackage(entryFile) {
|
|
1160
|
+
const { rolldown: rolldown4 } = await import("rolldown");
|
|
1161
|
+
const bundle = await rolldown4({
|
|
1162
|
+
input: entryFile,
|
|
1163
|
+
// 仅将其他 npm 包外部化;相对路径(包内部文件)全部内联打包
|
|
1164
|
+
external: (id) => {
|
|
1165
|
+
if (id.startsWith(".") || id.startsWith("/") || /^[A-Za-z]:\\/.test(id)) return false;
|
|
1166
|
+
return true;
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
const result = await bundle.generate({ format: "esm", exports: "named" });
|
|
1170
|
+
await bundle.close();
|
|
1171
|
+
let code = result.output[0].code;
|
|
1172
|
+
code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
|
|
1173
|
+
code = code.replace(
|
|
1174
|
+
/^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
1175
|
+
(_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
|
|
1176
|
+
).replace(
|
|
1177
|
+
/^(export\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
1178
|
+
(_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
|
|
1179
|
+
).replace(
|
|
1180
|
+
/^(import\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
1181
|
+
(_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
|
|
1182
|
+
);
|
|
1183
|
+
code = rewriteExternalRequires(code);
|
|
1184
|
+
if (code.includes("__commonJSMin")) {
|
|
1185
|
+
code = await injectCjsNamedExports(code, entryFile);
|
|
1186
|
+
}
|
|
1187
|
+
return code;
|
|
1188
|
+
}
|
|
1189
|
+
function rewriteExternalRequires(code) {
|
|
1190
|
+
const pkgs = /* @__PURE__ */ new Set();
|
|
1191
|
+
const re = /__require\(["']([^"']+)["']\)/g;
|
|
1192
|
+
let m;
|
|
1193
|
+
while ((m = re.exec(code)) !== null) {
|
|
1194
|
+
pkgs.add(m[1]);
|
|
1195
|
+
}
|
|
1196
|
+
if (pkgs.size === 0) return code;
|
|
1197
|
+
let result = code;
|
|
1198
|
+
const imports = [];
|
|
1199
|
+
for (const pkg of pkgs) {
|
|
1200
|
+
const safe = pkg.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1201
|
+
imports.push(`import * as __ns_${safe} from "/@modules/${pkg}";`);
|
|
1202
|
+
imports.push(`var __req_${safe} = "default" in __ns_${safe} ? __ns_${safe}["default"] : __ns_${safe};`);
|
|
1203
|
+
result = result.replaceAll(`__require("${pkg}")`, `__req_${safe}`);
|
|
1204
|
+
result = result.replaceAll(`__require('${pkg}')`, `__req_${safe}`);
|
|
1205
|
+
}
|
|
1206
|
+
return imports.join("\n") + "\n" + result;
|
|
1207
|
+
}
|
|
1208
|
+
async function injectCjsNamedExports(code, entryFile) {
|
|
1209
|
+
try {
|
|
1210
|
+
const { createRequire: createRequire3 } = await import("module");
|
|
1211
|
+
const req = createRequire3(entryFile);
|
|
1212
|
+
const cjsExports = req(entryFile);
|
|
1213
|
+
if (!cjsExports || typeof cjsExports !== "object" && typeof cjsExports !== "function" || Array.isArray(cjsExports)) return code;
|
|
1214
|
+
const namedKeys = Object.keys(cjsExports).filter(
|
|
1215
|
+
(k) => k !== "__esModule" && k !== "default" && VALID_IDENT.test(k)
|
|
1216
|
+
);
|
|
1217
|
+
if (namedKeys.length === 0) return code;
|
|
1218
|
+
return code.replace(
|
|
1219
|
+
/^export default (\w+\(\));?\s*$/m,
|
|
1220
|
+
(_, call) => [
|
|
1221
|
+
`const __cjsMod = ${call};`,
|
|
1222
|
+
`export default __cjsMod;`,
|
|
1223
|
+
...namedKeys.map((k) => `export const ${k} = __cjsMod[${JSON.stringify(k)}];`)
|
|
1224
|
+
].join("\n")
|
|
1225
|
+
);
|
|
1226
|
+
} catch {
|
|
1227
|
+
return code;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
function rewriteImports(code, _config) {
|
|
1231
|
+
return code.replace(
|
|
1232
|
+
/\bfrom\s+(['"])([^'"./][^'"]*)\1/g,
|
|
1233
|
+
(match, quote, specifier) => {
|
|
1234
|
+
return `from ${quote}/@modules/${specifier}${quote}`;
|
|
1235
|
+
}
|
|
1236
|
+
).replace(
|
|
1237
|
+
// 处理纯副作用导入: import 'bare-specifier'
|
|
1238
|
+
/\bimport\s+(['"])([^'"./][^'"]*)\1/g,
|
|
1239
|
+
(match, quote, specifier) => {
|
|
1240
|
+
return `import ${quote}/@modules/${specifier}${quote}`;
|
|
1241
|
+
}
|
|
1242
|
+
).replace(
|
|
1243
|
+
// 处理动态导入: import('bare-specifier')
|
|
1244
|
+
/\bimport\s*\(\s*(['"])([^'"./][^'"]*)\1\s*\)/g,
|
|
1245
|
+
(match, quote, specifier) => {
|
|
1246
|
+
return `import(${quote}/@modules/${specifier}${quote})`;
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function resolveNodeModule(root, moduleName) {
|
|
1251
|
+
let pkgName;
|
|
1252
|
+
let subpath;
|
|
1253
|
+
if (moduleName.startsWith("@")) {
|
|
1254
|
+
const parts = moduleName.split("/");
|
|
1255
|
+
pkgName = parts.slice(0, 2).join("/");
|
|
1256
|
+
subpath = parts.slice(2).join("/");
|
|
1257
|
+
} else {
|
|
1258
|
+
const slash = moduleName.indexOf("/");
|
|
1259
|
+
pkgName = slash === -1 ? moduleName : moduleName.slice(0, slash);
|
|
1260
|
+
subpath = slash === -1 ? "" : moduleName.slice(slash + 1);
|
|
1261
|
+
}
|
|
1262
|
+
let pkgDir = null;
|
|
1263
|
+
let dir = root;
|
|
1264
|
+
for (; ; ) {
|
|
1265
|
+
const candidate = import_node_path9.default.join(dir, "node_modules", pkgName);
|
|
1266
|
+
if (import_node_fs8.default.existsSync(candidate)) {
|
|
1267
|
+
pkgDir = candidate;
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
const parent = import_node_path9.default.dirname(dir);
|
|
1271
|
+
if (parent === dir) break;
|
|
1272
|
+
dir = parent;
|
|
1070
1273
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1274
|
+
if (!pkgDir) return null;
|
|
1275
|
+
const pkgJsonPath = import_node_path9.default.join(pkgDir, "package.json");
|
|
1276
|
+
if (!import_node_fs8.default.existsSync(pkgJsonPath)) return null;
|
|
1277
|
+
let pkg;
|
|
1278
|
+
try {
|
|
1279
|
+
pkg = JSON.parse(import_node_fs8.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
1280
|
+
} catch {
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
if (pkg.exports) {
|
|
1284
|
+
const exportKey = subpath ? `./${subpath}` : ".";
|
|
1285
|
+
const resolved = resolvePackageExports(pkg.exports, exportKey, pkgDir);
|
|
1286
|
+
if (resolved) return resolved;
|
|
1074
1287
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1288
|
+
if (subpath) {
|
|
1289
|
+
const subDirs = [""];
|
|
1290
|
+
for (const field of ["module", "main"]) {
|
|
1291
|
+
if (typeof pkg[field] === "string") {
|
|
1292
|
+
const dir2 = import_node_path9.default.dirname(pkg[field]);
|
|
1293
|
+
if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
|
|
1079
1294
|
}
|
|
1080
1295
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1296
|
+
for (const dir2 of subDirs) {
|
|
1297
|
+
const direct = import_node_path9.default.join(pkgDir, dir2, subpath);
|
|
1298
|
+
if (import_node_fs8.default.existsSync(direct) && import_node_fs8.default.statSync(direct).isFile()) return direct;
|
|
1299
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
1300
|
+
if (import_node_fs8.default.existsSync(direct + ext)) return direct + ext;
|
|
1086
1301
|
}
|
|
1087
1302
|
}
|
|
1303
|
+
return null;
|
|
1088
1304
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
this.ctx,
|
|
1094
|
-
source,
|
|
1095
|
-
importer ?? void 0,
|
|
1096
|
-
{ isEntry: options.isEntry ?? false, ssr: false }
|
|
1097
|
-
);
|
|
1098
|
-
if (result != null) return result;
|
|
1305
|
+
for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
|
|
1306
|
+
if (typeof pkg[field] === "string") {
|
|
1307
|
+
const entry = import_node_path9.default.join(pkgDir, pkg[field]);
|
|
1308
|
+
if (import_node_fs8.default.existsSync(entry)) return entry;
|
|
1099
1309
|
}
|
|
1100
|
-
return null;
|
|
1101
1310
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1311
|
+
const indexFallback = import_node_path9.default.join(pkgDir, "index.js");
|
|
1312
|
+
if (import_node_fs8.default.existsSync(indexFallback)) return indexFallback;
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
function resolvePackageExports(exports2, key, pkgDir) {
|
|
1316
|
+
if (typeof exports2 === "string") {
|
|
1317
|
+
return key === "." ? import_node_path9.default.join(pkgDir, exports2) : null;
|
|
1318
|
+
}
|
|
1319
|
+
const entry = exports2[key];
|
|
1320
|
+
if (entry === void 0) return null;
|
|
1321
|
+
return resolveExportValue(entry, pkgDir);
|
|
1322
|
+
}
|
|
1323
|
+
function resolveExportValue(value, pkgDir) {
|
|
1324
|
+
if (typeof value === "string") return import_node_path9.default.join(pkgDir, value);
|
|
1325
|
+
if (Array.isArray(value)) {
|
|
1326
|
+
for (const item of value) {
|
|
1327
|
+
const r = resolveExportValue(item, pkgDir);
|
|
1328
|
+
if (r) return r;
|
|
1107
1329
|
}
|
|
1108
1330
|
return null;
|
|
1109
1331
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (result == null) continue;
|
|
1116
|
-
if (typeof result === "string") {
|
|
1117
|
-
currentCode = result;
|
|
1118
|
-
} else {
|
|
1119
|
-
currentCode = result.code;
|
|
1332
|
+
if (value && typeof value === "object") {
|
|
1333
|
+
for (const cond of ESM_CONDITIONS) {
|
|
1334
|
+
if (cond in value) {
|
|
1335
|
+
const r = resolveExportValue(value[cond], pkgDir);
|
|
1336
|
+
if (r) return r;
|
|
1120
1337
|
}
|
|
1121
1338
|
}
|
|
1122
|
-
return currentCode === code ? null : { code: currentCode };
|
|
1123
|
-
}
|
|
1124
|
-
/** 完整的模块处理管道: resolveId → load → transform */
|
|
1125
|
-
async processModule(source, importer) {
|
|
1126
|
-
const resolveResult = await this.resolveId(source, importer, {
|
|
1127
|
-
isEntry: !importer
|
|
1128
|
-
});
|
|
1129
|
-
if (resolveResult == null) return null;
|
|
1130
|
-
const id = typeof resolveResult === "string" ? resolveResult : resolveResult.id;
|
|
1131
|
-
const loadResult = await this.load(id);
|
|
1132
|
-
if (loadResult == null) return null;
|
|
1133
|
-
const loadedCode = typeof loadResult === "string" ? loadResult : loadResult.code;
|
|
1134
|
-
const transformResult = await this.transform(loadedCode, id);
|
|
1135
|
-
const finalCode = transformResult == null ? loadedCode : typeof transformResult === "string" ? transformResult : transformResult.code;
|
|
1136
|
-
return { id, code: finalCode };
|
|
1137
|
-
}
|
|
1138
|
-
getPlugins() {
|
|
1139
|
-
return this.plugins;
|
|
1140
|
-
}
|
|
1141
|
-
};
|
|
1142
|
-
function sortPlugins(plugins) {
|
|
1143
|
-
const pre = [];
|
|
1144
|
-
const normal = [];
|
|
1145
|
-
const post = [];
|
|
1146
|
-
for (const plugin of plugins) {
|
|
1147
|
-
if (plugin.enforce === "pre") pre.push(plugin);
|
|
1148
|
-
else if (plugin.enforce === "post") post.push(plugin);
|
|
1149
|
-
else normal.push(plugin);
|
|
1150
1339
|
}
|
|
1151
|
-
return
|
|
1340
|
+
return null;
|
|
1152
1341
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
const startTime = performance.now();
|
|
1159
|
-
console.log(import_picocolors.default.cyan("\n\u{1F528} nasti build") + import_picocolors.default.dim(` v${"1.3.9"}`));
|
|
1160
|
-
console.log(import_picocolors.default.dim(` root: ${config.root}`));
|
|
1161
|
-
console.log(import_picocolors.default.dim(` mode: ${config.mode}`));
|
|
1162
|
-
const outDir = import_node_path7.default.resolve(config.root, config.build.outDir);
|
|
1163
|
-
if (config.build.emptyOutDir && import_node_fs6.default.existsSync(outDir)) {
|
|
1164
|
-
import_node_fs6.default.rmSync(outDir, { recursive: true, force: true });
|
|
1342
|
+
function resolveUrlToFile(url, root) {
|
|
1343
|
+
const cleanUrl = url.split("?")[0];
|
|
1344
|
+
if (cleanUrl.startsWith("/@modules/")) {
|
|
1345
|
+
const moduleName = cleanUrl.slice("/@modules/".length);
|
|
1346
|
+
return resolveNodeModule(root, moduleName);
|
|
1165
1347
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
if (html) {
|
|
1170
|
-
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
1171
|
-
for (const match of scriptMatches) {
|
|
1172
|
-
const src = match[1];
|
|
1173
|
-
if (src && !src.startsWith("http")) {
|
|
1174
|
-
entryPoints.push(import_node_path7.default.resolve(config.root, src.replace(/^\//, "")));
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1348
|
+
const filePath = import_node_path9.default.resolve(root, cleanUrl.replace(/^\//, ""));
|
|
1349
|
+
if (import_node_fs8.default.existsSync(filePath) && import_node_fs8.default.statSync(filePath).isFile()) {
|
|
1350
|
+
return filePath;
|
|
1177
1351
|
}
|
|
1178
|
-
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
const fullPath = import_node_path7.default.resolve(config.root, entry);
|
|
1182
|
-
if (import_node_fs6.default.existsSync(fullPath)) {
|
|
1183
|
-
entryPoints.push(fullPath);
|
|
1184
|
-
break;
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1352
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
1353
|
+
const withExt = filePath + ext;
|
|
1354
|
+
if (import_node_fs8.default.existsSync(withExt)) return withExt;
|
|
1187
1355
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1356
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
1357
|
+
const indexFile = import_node_path9.default.join(filePath, "index" + ext);
|
|
1358
|
+
if (import_node_fs8.default.existsSync(indexFile)) return indexFile;
|
|
1190
1359
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
function isModuleRequest(url) {
|
|
1363
|
+
const cleanUrl = url.split("?")[0];
|
|
1364
|
+
if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
|
|
1365
|
+
if (cleanUrl.startsWith("/@modules/")) return true;
|
|
1366
|
+
if (!import_node_path9.default.extname(cleanUrl)) return true;
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
function getHmrClientCode() {
|
|
1370
|
+
return `
|
|
1371
|
+
// Nasti HMR Client
|
|
1372
|
+
const socket = new WebSocket(\`ws://\${location.host}\`, 'nasti-hmr');
|
|
1373
|
+
const hotModulesMap = new Map();
|
|
1374
|
+
|
|
1375
|
+
socket.addEventListener('message', ({ data }) => {
|
|
1376
|
+
const payload = JSON.parse(data);
|
|
1377
|
+
switch (payload.type) {
|
|
1378
|
+
case 'connected':
|
|
1379
|
+
console.log('[nasti] connected.');
|
|
1380
|
+
break;
|
|
1381
|
+
case 'update':
|
|
1382
|
+
payload.updates.forEach((update) => {
|
|
1383
|
+
if (update.type === 'js-update') {
|
|
1384
|
+
fetchUpdate(update);
|
|
1385
|
+
} else if (update.type === 'css-update') {
|
|
1386
|
+
updateCss(update.path);
|
|
1387
|
+
}
|
|
1207
1388
|
});
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
oxcTransformPlugin,
|
|
1218
|
-
// 转换 Nasti 插件为 Rolldown 插件格式
|
|
1219
|
-
...allPlugins.map((p) => ({
|
|
1220
|
-
name: p.name,
|
|
1221
|
-
resolveId: p.resolveId,
|
|
1222
|
-
load: p.load,
|
|
1223
|
-
transform: p.transform,
|
|
1224
|
-
buildStart: p.buildStart,
|
|
1225
|
-
buildEnd: p.buildEnd
|
|
1226
|
-
}))
|
|
1227
|
-
],
|
|
1228
|
-
...config.build.rolldownOptions
|
|
1229
|
-
});
|
|
1230
|
-
const { output } = await bundle.write({
|
|
1231
|
-
dir: outDir,
|
|
1232
|
-
format: "esm",
|
|
1233
|
-
sourcemap: !!config.build.sourcemap,
|
|
1234
|
-
minify: !!config.build.minify,
|
|
1235
|
-
entryFileNames: "assets/[name].[hash].js",
|
|
1236
|
-
chunkFileNames: "assets/[name].[hash].js",
|
|
1237
|
-
assetFileNames: "assets/[name].[hash][extname]"
|
|
1238
|
-
});
|
|
1239
|
-
await bundle.close();
|
|
1240
|
-
await pluginContainer.buildEnd();
|
|
1241
|
-
for (const ef of pluginContainer.getEmittedFiles()) {
|
|
1242
|
-
const dest = import_node_path7.default.resolve(outDir, ef.fileName);
|
|
1243
|
-
import_node_fs6.default.mkdirSync(import_node_path7.default.dirname(dest), { recursive: true });
|
|
1244
|
-
import_node_fs6.default.writeFileSync(dest, ef.source);
|
|
1389
|
+
break;
|
|
1390
|
+
case 'full-reload':
|
|
1391
|
+
console.log('[nasti] full reload');
|
|
1392
|
+
location.reload();
|
|
1393
|
+
break;
|
|
1394
|
+
case 'error':
|
|
1395
|
+
console.error('[nasti] error:', payload.err.message);
|
|
1396
|
+
showErrorOverlay(payload.err);
|
|
1397
|
+
break;
|
|
1245
1398
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
processedHtml = processHtml(processedHtml, result);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
for (const chunk of output) {
|
|
1260
|
-
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
1261
|
-
const originalEntry = import_node_path7.default.relative(config.root, chunk.facadeModuleId);
|
|
1262
|
-
processedHtml = processedHtml.replace(
|
|
1263
|
-
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
1264
|
-
`$1${config.base}${chunk.fileName}$3`
|
|
1265
|
-
);
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
import_node_fs6.default.writeFileSync(import_node_path7.default.resolve(outDir, "index.html"), processedHtml);
|
|
1399
|
+
});
|
|
1400
|
+
|
|
1401
|
+
async function fetchUpdate(update) {
|
|
1402
|
+
const mod = hotModulesMap.get(update.path);
|
|
1403
|
+
if (mod) {
|
|
1404
|
+
const newMod = await import(update.acceptedPath + '?t=' + update.timestamp);
|
|
1405
|
+
mod.callbacks.forEach((cb) => cb(newMod));
|
|
1406
|
+
} else {
|
|
1407
|
+
// \u6CA1\u6709\u6CE8\u518C hot \u56DE\u8C03\uFF0C\u5C1D\u8BD5\u91CD\u65B0 import
|
|
1408
|
+
await import(update.path + '?t=' + update.timestamp);
|
|
1269
1409
|
}
|
|
1270
|
-
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
1271
|
-
const totalSize = output.reduce((sum, chunk) => {
|
|
1272
|
-
if (chunk.type === "chunk" && chunk.code) return sum + chunk.code.length;
|
|
1273
|
-
return sum;
|
|
1274
|
-
}, 0);
|
|
1275
|
-
console.log(import_picocolors.default.green(`
|
|
1276
|
-
\u2713 Built in ${elapsed}s`));
|
|
1277
|
-
console.log(import_picocolors.default.dim(` ${output.length} files, ${formatSize(totalSize)} total`));
|
|
1278
|
-
console.log(import_picocolors.default.dim(` output: ${config.build.outDir}/
|
|
1279
|
-
`));
|
|
1280
|
-
return { output };
|
|
1281
1410
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1411
|
+
|
|
1412
|
+
function updateCss(path) {
|
|
1413
|
+
const el = document.querySelector(\`style[data-nasti-css="\${path}"]\`);
|
|
1414
|
+
if (el) {
|
|
1415
|
+
fetch(path + '?t=' + Date.now())
|
|
1416
|
+
.then(r => r.text())
|
|
1417
|
+
.then(css => { el.textContent = css; });
|
|
1418
|
+
}
|
|
1286
1419
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1420
|
+
|
|
1421
|
+
function showErrorOverlay(err) {
|
|
1422
|
+
const overlay = document.createElement('div');
|
|
1423
|
+
overlay.id = 'nasti-error-overlay';
|
|
1424
|
+
overlay.style.cssText = 'position:fixed;inset:0;z-index:99999;background:rgba(0,0,0,0.85);color:#fff;font-family:monospace;padding:2rem;overflow:auto;';
|
|
1425
|
+
const title = document.createElement('h2');
|
|
1426
|
+
title.style.color = '#ff5555';
|
|
1427
|
+
title.textContent = 'Build Error';
|
|
1428
|
+
const pre = document.createElement('pre');
|
|
1429
|
+
pre.textContent = err.message + '\\n' + (err.stack || '');
|
|
1430
|
+
const btn = document.createElement('button');
|
|
1431
|
+
btn.style.cssText = 'margin-top:1rem;padding:0.5rem 1rem;cursor:pointer';
|
|
1432
|
+
btn.textContent = 'Close';
|
|
1433
|
+
btn.onclick = () => overlay.remove();
|
|
1434
|
+
overlay.appendChild(title);
|
|
1435
|
+
overlay.appendChild(pre);
|
|
1436
|
+
overlay.appendChild(btn);
|
|
1437
|
+
document.body.appendChild(overlay);
|
|
1289
1438
|
}
|
|
1290
1439
|
|
|
1291
|
-
//
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
// src/core/module-graph.ts
|
|
1301
|
-
var ModuleGraph = class {
|
|
1302
|
-
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
1303
|
-
idToModuleMap = /* @__PURE__ */ new Map();
|
|
1304
|
-
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
1305
|
-
getModuleByUrl(url) {
|
|
1306
|
-
return this.urlToModuleMap.get(url);
|
|
1307
|
-
}
|
|
1308
|
-
getModuleById(id) {
|
|
1309
|
-
return this.idToModuleMap.get(id);
|
|
1310
|
-
}
|
|
1311
|
-
getModulesByFile(file) {
|
|
1312
|
-
return this.fileToModulesMap.get(file);
|
|
1313
|
-
}
|
|
1314
|
-
async ensureEntryFromUrl(url) {
|
|
1315
|
-
let mod = this.urlToModuleMap.get(url);
|
|
1316
|
-
if (mod) return mod;
|
|
1317
|
-
mod = this.createModule(url);
|
|
1318
|
-
this.urlToModuleMap.set(url, mod);
|
|
1319
|
-
return mod;
|
|
1320
|
-
}
|
|
1321
|
-
createModule(url, id) {
|
|
1322
|
-
const mod = {
|
|
1323
|
-
id: id ?? url,
|
|
1324
|
-
file: null,
|
|
1325
|
-
url,
|
|
1326
|
-
type: url.endsWith(".css") ? "css" : "js",
|
|
1327
|
-
importers: /* @__PURE__ */ new Set(),
|
|
1328
|
-
importedModules: /* @__PURE__ */ new Set(),
|
|
1329
|
-
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
1330
|
-
transformResult: null,
|
|
1331
|
-
lastHMRTimestamp: 0,
|
|
1332
|
-
isSelfAccepting: false
|
|
1333
|
-
};
|
|
1334
|
-
this.idToModuleMap.set(mod.id, mod);
|
|
1335
|
-
return mod;
|
|
1336
|
-
}
|
|
1337
|
-
/** 注册文件路径到模块的映射 */
|
|
1338
|
-
registerModule(mod, file) {
|
|
1339
|
-
mod.file = file;
|
|
1340
|
-
let mods = this.fileToModulesMap.get(file);
|
|
1341
|
-
if (!mods) {
|
|
1342
|
-
mods = /* @__PURE__ */ new Set();
|
|
1343
|
-
this.fileToModulesMap.set(file, mods);
|
|
1344
|
-
}
|
|
1345
|
-
mods.add(mod);
|
|
1346
|
-
}
|
|
1347
|
-
/** 更新模块依赖关系 */
|
|
1348
|
-
updateModuleImports(mod, importedIds) {
|
|
1349
|
-
for (const imported of mod.importedModules) {
|
|
1350
|
-
imported.importers.delete(mod);
|
|
1351
|
-
}
|
|
1352
|
-
mod.importedModules.clear();
|
|
1353
|
-
for (const id of importedIds) {
|
|
1354
|
-
const importedMod = this.idToModuleMap.get(id);
|
|
1355
|
-
if (importedMod) {
|
|
1356
|
-
mod.importedModules.add(importedMod);
|
|
1357
|
-
importedMod.importers.add(mod);
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
/** 使模块的转换缓存失效 */
|
|
1362
|
-
invalidateModule(mod) {
|
|
1363
|
-
mod.transformResult = null;
|
|
1364
|
-
mod.lastHMRTimestamp = Date.now();
|
|
1365
|
-
}
|
|
1366
|
-
/** 使所有模块缓存失效 */
|
|
1367
|
-
invalidateAll() {
|
|
1368
|
-
for (const mod of this.idToModuleMap.values()) {
|
|
1369
|
-
this.invalidateModule(mod);
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
1373
|
-
getHmrBoundaries(mod) {
|
|
1374
|
-
const boundaries = [];
|
|
1375
|
-
const visited = /* @__PURE__ */ new Set();
|
|
1376
|
-
const propagate = (node, via) => {
|
|
1377
|
-
if (visited.has(node)) return true;
|
|
1378
|
-
visited.add(node);
|
|
1379
|
-
if (node.isSelfAccepting) {
|
|
1380
|
-
boundaries.push({ boundary: node, acceptedVia: via });
|
|
1381
|
-
return true;
|
|
1382
|
-
}
|
|
1383
|
-
if (node.acceptedHmrDeps.has(via)) {
|
|
1384
|
-
boundaries.push({ boundary: node, acceptedVia: via });
|
|
1385
|
-
return true;
|
|
1386
|
-
}
|
|
1387
|
-
if (node.importers.size === 0) return false;
|
|
1388
|
-
for (const importer of node.importers) {
|
|
1389
|
-
if (!propagate(importer, node)) return false;
|
|
1390
|
-
}
|
|
1391
|
-
return true;
|
|
1392
|
-
};
|
|
1393
|
-
if (mod.isSelfAccepting) {
|
|
1394
|
-
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
1395
|
-
return boundaries;
|
|
1396
|
-
}
|
|
1397
|
-
for (const importer of mod.importers) {
|
|
1398
|
-
if (!propagate(importer, mod)) {
|
|
1399
|
-
return [];
|
|
1400
|
-
}
|
|
1440
|
+
// import.meta.hot API
|
|
1441
|
+
const createHotContext = (ownerPath) => ({
|
|
1442
|
+
accept(deps, callback) {
|
|
1443
|
+
if (typeof deps === 'function' || !deps) {
|
|
1444
|
+
// self-accepting
|
|
1445
|
+
const callbacks = hotModulesMap.get(ownerPath)?.callbacks || [];
|
|
1446
|
+
callbacks.push(deps || (() => {}));
|
|
1447
|
+
hotModulesMap.set(ownerPath, { callbacks });
|
|
1401
1448
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1449
|
+
},
|
|
1450
|
+
prune(callback) {
|
|
1451
|
+
// \u6A21\u5757\u88AB\u79FB\u9664\u65F6\u6267\u884C
|
|
1452
|
+
},
|
|
1453
|
+
dispose(callback) {
|
|
1454
|
+
// \u6A21\u5757\u66F4\u65B0\u524D\u6267\u884C\u6E05\u7406
|
|
1455
|
+
},
|
|
1456
|
+
invalidate() {
|
|
1457
|
+
location.reload();
|
|
1458
|
+
},
|
|
1459
|
+
data: {},
|
|
1460
|
+
});
|
|
1405
1461
|
|
|
1406
|
-
//
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
const clients = /* @__PURE__ */ new Set();
|
|
1411
|
-
server.on("upgrade", (req, socket, head) => {
|
|
1412
|
-
if (req.headers["sec-websocket-protocol"] === "nasti-hmr") {
|
|
1413
|
-
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
1414
|
-
wss.emit("connection", ws, req);
|
|
1415
|
-
});
|
|
1416
|
-
}
|
|
1417
|
-
});
|
|
1418
|
-
wss.on("connection", (ws) => {
|
|
1419
|
-
clients.add(ws);
|
|
1420
|
-
ws.send(JSON.stringify({ type: "connected" }));
|
|
1421
|
-
ws.on("close", () => {
|
|
1422
|
-
clients.delete(ws);
|
|
1423
|
-
});
|
|
1424
|
-
ws.on("error", (err) => {
|
|
1425
|
-
console.error("[nasti] WebSocket error:", err);
|
|
1426
|
-
clients.delete(ws);
|
|
1427
|
-
});
|
|
1428
|
-
});
|
|
1429
|
-
return {
|
|
1430
|
-
send(payload) {
|
|
1431
|
-
const data = JSON.stringify(payload);
|
|
1432
|
-
for (const client of clients) {
|
|
1433
|
-
if (client.readyState === 1) {
|
|
1434
|
-
client.send(data);
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
},
|
|
1438
|
-
close() {
|
|
1439
|
-
clients.clear();
|
|
1440
|
-
wss.close();
|
|
1441
|
-
}
|
|
1442
|
-
};
|
|
1462
|
+
// \u66B4\u9732\u7ED9\u6A21\u5757\u4F7F\u7528
|
|
1463
|
+
if (!window.__nasti_hot_map) window.__nasti_hot_map = new Map();
|
|
1464
|
+
window.__NASTI_HMR__ = { createHotContext };
|
|
1465
|
+
`;
|
|
1443
1466
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1467
|
+
var import_node_path9, import_node_fs8, REACT_REFRESH_RUNTIME, REACT_REFRESH_PREAMBLE, REACT_REFRESH_FOOTER, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
1468
|
+
var init_middleware = __esm({
|
|
1469
|
+
"src/server/middleware.ts"() {
|
|
1470
|
+
"use strict";
|
|
1471
|
+
import_node_path9 = __toESM(require("path"), 1);
|
|
1472
|
+
import_node_fs8 = __toESM(require("fs"), 1);
|
|
1473
|
+
init_transformer();
|
|
1474
|
+
init_html();
|
|
1475
|
+
init_env();
|
|
1476
|
+
REACT_REFRESH_RUNTIME = `
|
|
1477
|
+
export function createSignatureFunctionForTransform() {
|
|
1478
|
+
return function(type, key, forceReset, getCustomHooks) { return type; };
|
|
1479
|
+
}
|
|
1480
|
+
export function register(type, id) {}
|
|
1481
|
+
export default { createSignatureFunctionForTransform, register };
|
|
1482
|
+
`;
|
|
1483
|
+
REACT_REFRESH_PREAMBLE = `
|
|
1484
|
+
import RefreshRuntime from '/@react-refresh';
|
|
1485
|
+
if (!window.$RefreshReg$) {
|
|
1486
|
+
window.$RefreshReg$ = (type, id) => RefreshRuntime.register(type, import.meta.url + ' ' + id);
|
|
1487
|
+
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
|
|
1488
|
+
}
|
|
1489
|
+
`;
|
|
1490
|
+
REACT_REFRESH_FOOTER = `
|
|
1491
|
+
if (import.meta.hot) {
|
|
1492
|
+
import.meta.hot.accept();
|
|
1493
|
+
}
|
|
1494
|
+
`;
|
|
1495
|
+
esmBundleCache = /* @__PURE__ */ new Map();
|
|
1496
|
+
VALID_IDENT = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
1497
|
+
RESOLVE_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".json", ".vue"];
|
|
1498
|
+
ESM_CONDITIONS = ["import", "browser", "module", "default"];
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1447
1501
|
|
|
1448
1502
|
// src/server/hmr.ts
|
|
1449
|
-
var import_node_path9 = __toESM(require("path"), 1);
|
|
1450
|
-
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
1451
1503
|
async function handleFileChange(file, server) {
|
|
1452
1504
|
const { moduleGraph, ws, config } = server;
|
|
1453
|
-
const relativePath = "/" +
|
|
1505
|
+
const relativePath = "/" + import_node_path10.default.relative(config.root, file);
|
|
1454
1506
|
const mods = moduleGraph.getModulesByFile(file);
|
|
1455
1507
|
if (!mods || mods.size === 0) {
|
|
1456
1508
|
return;
|
|
@@ -1463,7 +1515,7 @@ async function handleFileChange(file, server) {
|
|
|
1463
1515
|
file,
|
|
1464
1516
|
timestamp,
|
|
1465
1517
|
modules: [mod],
|
|
1466
|
-
read: () =>
|
|
1518
|
+
read: () => import_node_fs9.default.readFileSync(file, "utf-8"),
|
|
1467
1519
|
server
|
|
1468
1520
|
};
|
|
1469
1521
|
let affectedModules = [mod];
|
|
@@ -1495,9 +1547,20 @@ async function handleFileChange(file, server) {
|
|
|
1495
1547
|
ws.send({ type: "update", updates });
|
|
1496
1548
|
}
|
|
1497
1549
|
}
|
|
1550
|
+
var import_node_path10, import_node_fs9;
|
|
1551
|
+
var init_hmr = __esm({
|
|
1552
|
+
"src/server/hmr.ts"() {
|
|
1553
|
+
"use strict";
|
|
1554
|
+
import_node_path10 = __toESM(require("path"), 1);
|
|
1555
|
+
import_node_fs9 = __toESM(require("fs"), 1);
|
|
1556
|
+
}
|
|
1557
|
+
});
|
|
1498
1558
|
|
|
1499
1559
|
// src/server/index.ts
|
|
1500
|
-
|
|
1560
|
+
var server_exports = {};
|
|
1561
|
+
__export(server_exports, {
|
|
1562
|
+
createServer: () => createServer
|
|
1563
|
+
});
|
|
1501
1564
|
async function createServer(inlineConfig = {}) {
|
|
1502
1565
|
const config = await resolveConfig(inlineConfig, "serve");
|
|
1503
1566
|
const allPlugins = [
|
|
@@ -1516,7 +1579,7 @@ async function createServer(inlineConfig = {}) {
|
|
|
1516
1579
|
pluginContainer,
|
|
1517
1580
|
moduleGraph
|
|
1518
1581
|
}));
|
|
1519
|
-
const publicDir =
|
|
1582
|
+
const publicDir = import_node_path11.default.resolve(config.root, "public");
|
|
1520
1583
|
app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
|
|
1521
1584
|
app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
|
|
1522
1585
|
const httpServer = import_node_http.default.createServer(app);
|
|
@@ -1559,14 +1622,15 @@ async function createServer(inlineConfig = {}) {
|
|
|
1559
1622
|
let currentPort = finalPort;
|
|
1560
1623
|
const onListening = () => {
|
|
1561
1624
|
const actualPort = httpServer.address()?.port ?? currentPort;
|
|
1625
|
+
config.server.port = actualPort;
|
|
1562
1626
|
const localUrl = `http://localhost:${actualPort}`;
|
|
1563
1627
|
const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
|
|
1564
1628
|
console.log();
|
|
1565
|
-
console.log(
|
|
1629
|
+
console.log(import_picocolors3.default.cyan(" nasti dev server") + import_picocolors3.default.dim(` v${"1.4.0"}`));
|
|
1566
1630
|
console.log();
|
|
1567
|
-
console.log(` ${
|
|
1631
|
+
console.log(` ${import_picocolors3.default.green(">")} Local: ${import_picocolors3.default.cyan(localUrl)}`);
|
|
1568
1632
|
if (networkUrl) {
|
|
1569
|
-
console.log(` ${
|
|
1633
|
+
console.log(` ${import_picocolors3.default.green(">")} Network: ${import_picocolors3.default.cyan(networkUrl)}`);
|
|
1570
1634
|
}
|
|
1571
1635
|
console.log();
|
|
1572
1636
|
resolve(server);
|
|
@@ -1575,7 +1639,7 @@ async function createServer(inlineConfig = {}) {
|
|
|
1575
1639
|
httpServer.on("error", (err) => {
|
|
1576
1640
|
if (err.code === "EADDRINUSE") {
|
|
1577
1641
|
currentPort++;
|
|
1578
|
-
console.log(
|
|
1642
|
+
console.log(import_picocolors3.default.yellow(`Port ${currentPort - 1} is in use, trying ${currentPort}...`));
|
|
1579
1643
|
httpServer.listen(currentPort, host);
|
|
1580
1644
|
} else {
|
|
1581
1645
|
reject(err);
|
|
@@ -1608,11 +1672,411 @@ function getNetworkAddress() {
|
|
|
1608
1672
|
}
|
|
1609
1673
|
return "localhost";
|
|
1610
1674
|
}
|
|
1675
|
+
var import_node_http, import_node_path11, import_node_os, import_connect, import_sirv, import_chokidar, import_picocolors3;
|
|
1676
|
+
var init_server = __esm({
|
|
1677
|
+
"src/server/index.ts"() {
|
|
1678
|
+
"use strict";
|
|
1679
|
+
import_node_http = __toESM(require("http"), 1);
|
|
1680
|
+
import_node_path11 = __toESM(require("path"), 1);
|
|
1681
|
+
import_node_os = __toESM(require("os"), 1);
|
|
1682
|
+
import_connect = __toESM(require("connect"), 1);
|
|
1683
|
+
import_sirv = __toESM(require("sirv"), 1);
|
|
1684
|
+
import_chokidar = require("chokidar");
|
|
1685
|
+
import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
1686
|
+
init_config();
|
|
1687
|
+
init_plugin_container();
|
|
1688
|
+
init_module_graph();
|
|
1689
|
+
init_ws();
|
|
1690
|
+
init_middleware();
|
|
1691
|
+
init_hmr();
|
|
1692
|
+
init_resolve();
|
|
1693
|
+
init_css();
|
|
1694
|
+
init_assets();
|
|
1695
|
+
init_html();
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
// src/index.ts
|
|
1700
|
+
var src_exports = {};
|
|
1701
|
+
__export(src_exports, {
|
|
1702
|
+
build: () => build,
|
|
1703
|
+
buildElectron: () => buildElectron,
|
|
1704
|
+
createServer: () => createServer,
|
|
1705
|
+
defineConfig: () => defineConfig,
|
|
1706
|
+
electronPlugin: () => electronPlugin,
|
|
1707
|
+
resolveConfig: () => resolveConfig,
|
|
1708
|
+
startElectronDev: () => startElectronDev
|
|
1709
|
+
});
|
|
1710
|
+
module.exports = __toCommonJS(src_exports);
|
|
1711
|
+
init_config();
|
|
1712
|
+
init_build();
|
|
1713
|
+
|
|
1714
|
+
// src/build/electron.ts
|
|
1715
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
1716
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
1717
|
+
var import_rolldown2 = require("rolldown");
|
|
1718
|
+
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1719
|
+
init_config();
|
|
1720
|
+
init_resolve();
|
|
1721
|
+
|
|
1722
|
+
// src/plugins/electron.ts
|
|
1723
|
+
var import_node_module2 = require("module");
|
|
1724
|
+
var NODE_BUILTINS = /* @__PURE__ */ new Set([
|
|
1725
|
+
...import_node_module2.builtinModules,
|
|
1726
|
+
...import_node_module2.builtinModules.map((m) => `node:${m}`)
|
|
1727
|
+
]);
|
|
1728
|
+
var ELECTRON_MODULES = /* @__PURE__ */ new Set([
|
|
1729
|
+
"electron",
|
|
1730
|
+
"electron/main",
|
|
1731
|
+
"electron/common",
|
|
1732
|
+
"electron/renderer"
|
|
1733
|
+
]);
|
|
1734
|
+
function electronPlugin(config) {
|
|
1735
|
+
const external = /* @__PURE__ */ new Set([
|
|
1736
|
+
...ELECTRON_MODULES,
|
|
1737
|
+
...NODE_BUILTINS,
|
|
1738
|
+
...config.electron.external ?? []
|
|
1739
|
+
]);
|
|
1740
|
+
return {
|
|
1741
|
+
name: "nasti:electron",
|
|
1742
|
+
enforce: "pre",
|
|
1743
|
+
resolveId(source) {
|
|
1744
|
+
if (external.has(source)) {
|
|
1745
|
+
return { id: source, external: true };
|
|
1746
|
+
}
|
|
1747
|
+
if (source.startsWith("electron/")) {
|
|
1748
|
+
return { id: source, external: true };
|
|
1749
|
+
}
|
|
1750
|
+
return null;
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
// src/build/electron.ts
|
|
1756
|
+
init_transformer();
|
|
1757
|
+
init_env();
|
|
1758
|
+
async function buildElectron(inlineConfig = {}) {
|
|
1759
|
+
const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
|
|
1760
|
+
const startTime = performance.now();
|
|
1761
|
+
assertElectronVersion(config);
|
|
1762
|
+
console.log(import_picocolors2.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors2.default.dim(` v${"1.4.0"}`));
|
|
1763
|
+
console.log(import_picocolors2.default.dim(` root: ${config.root}`));
|
|
1764
|
+
console.log(import_picocolors2.default.dim(` mode: ${config.mode}`));
|
|
1765
|
+
console.log(import_picocolors2.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
|
|
1766
|
+
const outDir = import_node_path8.default.resolve(config.root, config.build.outDir);
|
|
1767
|
+
if (config.build.emptyOutDir && import_node_fs7.default.existsSync(outDir)) {
|
|
1768
|
+
import_node_fs7.default.rmSync(outDir, { recursive: true, force: true });
|
|
1769
|
+
}
|
|
1770
|
+
import_node_fs7.default.mkdirSync(outDir, { recursive: true });
|
|
1771
|
+
const rendererOutDir = import_node_path8.default.join(outDir, "renderer");
|
|
1772
|
+
const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
1773
|
+
await build2({
|
|
1774
|
+
...inlineConfig,
|
|
1775
|
+
target: "web",
|
|
1776
|
+
build: {
|
|
1777
|
+
...inlineConfig.build,
|
|
1778
|
+
outDir: rendererOutDir,
|
|
1779
|
+
emptyOutDir: false
|
|
1780
|
+
}
|
|
1781
|
+
});
|
|
1782
|
+
const mainEntry = import_node_path8.default.resolve(config.root, config.electron.main);
|
|
1783
|
+
if (!import_node_fs7.default.existsSync(mainEntry)) {
|
|
1784
|
+
throw new Error(
|
|
1785
|
+
`Electron main entry not found: ${config.electron.main}
|
|
1786
|
+
\u5728 nasti.config.ts \u7684 electron.main \u6307\u5B9A\u4E3B\u8FDB\u7A0B\u5165\u53E3\u6587\u4EF6\u3002`
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
const mainFile = await bundleNode(config, mainEntry, {
|
|
1790
|
+
outFile: outFileName(outDir, "main", config.electron.mainFormat),
|
|
1791
|
+
format: config.electron.mainFormat,
|
|
1792
|
+
label: "main"
|
|
1793
|
+
});
|
|
1794
|
+
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
1795
|
+
const preloadFiles = [];
|
|
1796
|
+
for (const entry of preloadEntries) {
|
|
1797
|
+
if (!import_node_fs7.default.existsSync(entry)) {
|
|
1798
|
+
console.warn(import_picocolors2.default.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
const base = import_node_path8.default.basename(entry).replace(/\.[^.]+$/, "");
|
|
1802
|
+
const out = outFileName(outDir, base, config.electron.preloadFormat);
|
|
1803
|
+
await bundleNode(config, entry, {
|
|
1804
|
+
outFile: out,
|
|
1805
|
+
format: config.electron.preloadFormat,
|
|
1806
|
+
label: `preload (${base})`
|
|
1807
|
+
});
|
|
1808
|
+
preloadFiles.push(out);
|
|
1809
|
+
}
|
|
1810
|
+
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
1811
|
+
console.log(import_picocolors2.default.green(`
|
|
1812
|
+
\u2713 Electron build complete in ${elapsed}s`));
|
|
1813
|
+
console.log(import_picocolors2.default.dim(` renderer: ${import_node_path8.default.relative(config.root, rendererOutDir)}/`));
|
|
1814
|
+
console.log(import_picocolors2.default.dim(` main: ${import_node_path8.default.relative(config.root, mainFile)}`));
|
|
1815
|
+
for (const pf of preloadFiles) {
|
|
1816
|
+
console.log(import_picocolors2.default.dim(` preload: ${import_node_path8.default.relative(config.root, pf)}`));
|
|
1817
|
+
}
|
|
1818
|
+
console.log();
|
|
1819
|
+
return { rendererOutDir, mainFile, preloadFiles };
|
|
1820
|
+
}
|
|
1821
|
+
async function bundleNode(config, entry, opts) {
|
|
1822
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
1823
|
+
const envDefine = {
|
|
1824
|
+
...buildEnvDefine(env, config.mode),
|
|
1825
|
+
__ELECTRON__: "true",
|
|
1826
|
+
__NASTI_TARGET__: JSON.stringify("electron")
|
|
1827
|
+
};
|
|
1828
|
+
const oxcTransformPlugin = {
|
|
1829
|
+
name: "nasti:oxc-transform",
|
|
1830
|
+
transform(code, id) {
|
|
1831
|
+
if (!shouldTransform(id)) return null;
|
|
1832
|
+
const result = transformCode(id, code, {
|
|
1833
|
+
sourcemap: !!config.build.sourcemap,
|
|
1834
|
+
jsxRuntime: "automatic",
|
|
1835
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
1836
|
+
});
|
|
1837
|
+
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
const bundle = await (0, import_rolldown2.rolldown)({
|
|
1841
|
+
input: entry,
|
|
1842
|
+
define: envDefine,
|
|
1843
|
+
platform: "node",
|
|
1844
|
+
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)],
|
|
1845
|
+
...config.build.rolldownOptions
|
|
1846
|
+
});
|
|
1847
|
+
import_node_fs7.default.mkdirSync(import_node_path8.default.dirname(opts.outFile), { recursive: true });
|
|
1848
|
+
await bundle.write({
|
|
1849
|
+
file: opts.outFile,
|
|
1850
|
+
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
1851
|
+
sourcemap: !!config.build.sourcemap,
|
|
1852
|
+
minify: !!config.build.minify,
|
|
1853
|
+
inlineDynamicImports: true
|
|
1854
|
+
});
|
|
1855
|
+
await bundle.close();
|
|
1856
|
+
console.log(import_picocolors2.default.dim(` \u2713 ${opts.label} \u2192 ${import_node_path8.default.relative(config.root, opts.outFile)}`));
|
|
1857
|
+
return opts.outFile;
|
|
1858
|
+
}
|
|
1859
|
+
function outFileName(outDir, base, format) {
|
|
1860
|
+
const ext = format === "cjs" ? ".cjs" : ".mjs";
|
|
1861
|
+
return import_node_path8.default.join(outDir, base + ext);
|
|
1862
|
+
}
|
|
1863
|
+
function normalizePreload(preload, root) {
|
|
1864
|
+
const list = Array.isArray(preload) ? preload : preload ? [preload] : [];
|
|
1865
|
+
return list.map((p) => import_node_path8.default.resolve(root, p));
|
|
1866
|
+
}
|
|
1867
|
+
function assertElectronVersion(config) {
|
|
1868
|
+
const min = config.electron.minVersion;
|
|
1869
|
+
const installed = detectInstalledElectron(config.root);
|
|
1870
|
+
if (installed && installed < min) {
|
|
1871
|
+
console.warn(
|
|
1872
|
+
import_picocolors2.default.yellow(
|
|
1873
|
+
` \u26A0 \u68C0\u6D4B\u5230 Electron ${installed}\uFF0CNasti \u8981\u6C42 \u2265 ${min}\u3002\u65E7\u7248\u672C\u53EF\u80FD\u7F3A\u5C11 ESM \u4E3B\u8FDB\u7A0B\u652F\u6301\u3002`
|
|
1874
|
+
)
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
function detectInstalledElectron(root) {
|
|
1879
|
+
try {
|
|
1880
|
+
const pkgPath = import_node_path8.default.resolve(root, "node_modules/electron/package.json");
|
|
1881
|
+
if (!import_node_fs7.default.existsSync(pkgPath)) return null;
|
|
1882
|
+
const pkg = JSON.parse(import_node_fs7.default.readFileSync(pkgPath, "utf-8"));
|
|
1883
|
+
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
1884
|
+
return Number.isFinite(major) ? major : null;
|
|
1885
|
+
} catch {
|
|
1886
|
+
return null;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// src/index.ts
|
|
1891
|
+
init_server();
|
|
1892
|
+
|
|
1893
|
+
// src/server/electron-dev.ts
|
|
1894
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
1895
|
+
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
1896
|
+
var import_node_module3 = require("module");
|
|
1897
|
+
var import_node_child_process = require("child_process");
|
|
1898
|
+
var import_chokidar2 = __toESM(require("chokidar"), 1);
|
|
1899
|
+
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
1900
|
+
init_config();
|
|
1901
|
+
var import_rolldown3 = require("rolldown");
|
|
1902
|
+
init_resolve();
|
|
1903
|
+
init_transformer();
|
|
1904
|
+
init_env();
|
|
1905
|
+
async function startElectronDev(inlineConfig = {}) {
|
|
1906
|
+
const { noSpawn, ...rest } = inlineConfig;
|
|
1907
|
+
const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
|
|
1908
|
+
warnElectronVersion(config);
|
|
1909
|
+
console.log(import_picocolors4.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors4.default.dim(` v${"1.4.0"}`));
|
|
1910
|
+
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
1911
|
+
const server = await createServer2({ ...rest, target: "electron" });
|
|
1912
|
+
await server.listen();
|
|
1913
|
+
const devUrl = `http://localhost:${server.config.server.port}/`;
|
|
1914
|
+
console.log(import_picocolors4.default.dim(` renderer: ${devUrl}`));
|
|
1915
|
+
const stageDir = import_node_path12.default.resolve(config.root, ".nasti");
|
|
1916
|
+
import_node_fs10.default.mkdirSync(stageDir, { recursive: true });
|
|
1917
|
+
const mainEntry = import_node_path12.default.resolve(config.root, config.electron.main);
|
|
1918
|
+
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
1919
|
+
const builtMainFile = import_node_path12.default.join(stageDir, "main" + extFor(config.electron.mainFormat));
|
|
1920
|
+
const builtPreloadFiles = [];
|
|
1921
|
+
const compileAll = async () => {
|
|
1922
|
+
await compileNode(config, mainEntry, {
|
|
1923
|
+
outFile: builtMainFile,
|
|
1924
|
+
format: config.electron.mainFormat,
|
|
1925
|
+
devUrl
|
|
1926
|
+
});
|
|
1927
|
+
builtPreloadFiles.length = 0;
|
|
1928
|
+
for (const entry of preloadEntries) {
|
|
1929
|
+
if (!import_node_fs10.default.existsSync(entry)) continue;
|
|
1930
|
+
const base = import_node_path12.default.basename(entry).replace(/\.[^.]+$/, "");
|
|
1931
|
+
const out = import_node_path12.default.join(stageDir, base + extFor(config.electron.preloadFormat));
|
|
1932
|
+
await compileNode(config, entry, {
|
|
1933
|
+
outFile: out,
|
|
1934
|
+
format: config.electron.preloadFormat,
|
|
1935
|
+
devUrl
|
|
1936
|
+
});
|
|
1937
|
+
builtPreloadFiles.push(out);
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
await compileAll();
|
|
1941
|
+
if (noSpawn) {
|
|
1942
|
+
console.log(import_picocolors4.default.dim(" (noSpawn) \u5DF2\u7F16\u8BD1\u4E3B/preload\uFF0C\u8DF3\u8FC7\u542F\u52A8 Electron\u3002"));
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
const electronBin = resolveElectronBinary(config);
|
|
1946
|
+
if (!electronBin) {
|
|
1947
|
+
console.warn(
|
|
1948
|
+
import_picocolors4.default.yellow(
|
|
1949
|
+
" \u26A0 \u672A\u627E\u5230 Electron \u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u8BF7\u5148\u5B89\u88C5\uFF1Anpm install -D electron\n \u5DF2\u7F16\u8BD1\u4E3B/preload \u81F3 .nasti/\uFF0C\u53EF\u624B\u52A8\u8FD0\u884C\u3002"
|
|
1950
|
+
)
|
|
1951
|
+
);
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
let child = null;
|
|
1955
|
+
const spawnElectron = () => {
|
|
1956
|
+
const args = [builtMainFile, ...config.electron.electronArgs];
|
|
1957
|
+
child = (0, import_node_child_process.spawn)(electronBin, args, {
|
|
1958
|
+
stdio: "inherit",
|
|
1959
|
+
env: { ...process.env, NASTI_DEV_SERVER_URL: devUrl, NASTI_TARGET: "electron" }
|
|
1960
|
+
});
|
|
1961
|
+
child.on("exit", (code) => {
|
|
1962
|
+
if (code !== null && child && child.__nastiKilled !== true) {
|
|
1963
|
+
console.log(import_picocolors4.default.dim(` Electron exited (${code}).`));
|
|
1964
|
+
process.exit(code ?? 0);
|
|
1965
|
+
}
|
|
1966
|
+
});
|
|
1967
|
+
};
|
|
1968
|
+
spawnElectron();
|
|
1969
|
+
if (config.electron.autoRestart) {
|
|
1970
|
+
const watchTargets = [mainEntry, ...preloadEntries].filter(import_node_fs10.default.existsSync);
|
|
1971
|
+
const watcher = import_chokidar2.default.watch(watchTargets, { ignoreInitial: true });
|
|
1972
|
+
let restarting = null;
|
|
1973
|
+
watcher.on("all", async () => {
|
|
1974
|
+
if (restarting) return;
|
|
1975
|
+
restarting = (async () => {
|
|
1976
|
+
console.log(import_picocolors4.default.cyan("\n \u267B \u4E3B/preload \u53D8\u66F4\uFF0C\u91CD\u542F Electron..."));
|
|
1977
|
+
try {
|
|
1978
|
+
if (child && !child.killed) {
|
|
1979
|
+
;
|
|
1980
|
+
child.__nastiKilled = true;
|
|
1981
|
+
const dying = child;
|
|
1982
|
+
await new Promise((resolve) => {
|
|
1983
|
+
const timer = setTimeout(() => resolve(), 3e3);
|
|
1984
|
+
dying.once("exit", () => {
|
|
1985
|
+
clearTimeout(timer);
|
|
1986
|
+
resolve();
|
|
1987
|
+
});
|
|
1988
|
+
dying.kill();
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
await compileAll();
|
|
1992
|
+
spawnElectron();
|
|
1993
|
+
} finally {
|
|
1994
|
+
restarting = null;
|
|
1995
|
+
}
|
|
1996
|
+
})();
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function extFor(format) {
|
|
2001
|
+
return format === "cjs" ? ".cjs" : ".mjs";
|
|
2002
|
+
}
|
|
2003
|
+
async function compileNode(config, entry, opts) {
|
|
2004
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
2005
|
+
const envDefine = {
|
|
2006
|
+
...buildEnvDefine(env, config.mode),
|
|
2007
|
+
__ELECTRON__: "true",
|
|
2008
|
+
__NASTI_TARGET__: JSON.stringify("electron"),
|
|
2009
|
+
__NASTI_DEV_SERVER_URL__: JSON.stringify(opts.devUrl)
|
|
2010
|
+
};
|
|
2011
|
+
const oxcTransformPlugin = {
|
|
2012
|
+
name: "nasti:oxc-transform",
|
|
2013
|
+
transform(code, id) {
|
|
2014
|
+
if (!shouldTransform(id)) return null;
|
|
2015
|
+
const result = transformCode(id, code, {
|
|
2016
|
+
sourcemap: !!config.build.sourcemap,
|
|
2017
|
+
jsxRuntime: "automatic",
|
|
2018
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
2019
|
+
});
|
|
2020
|
+
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
const bundle = await (0, import_rolldown3.rolldown)({
|
|
2024
|
+
input: entry,
|
|
2025
|
+
transform: { define: envDefine },
|
|
2026
|
+
platform: "node",
|
|
2027
|
+
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
2028
|
+
});
|
|
2029
|
+
import_node_fs10.default.mkdirSync(import_node_path12.default.dirname(opts.outFile), { recursive: true });
|
|
2030
|
+
await bundle.write({
|
|
2031
|
+
file: opts.outFile,
|
|
2032
|
+
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
2033
|
+
sourcemap: false,
|
|
2034
|
+
minify: false,
|
|
2035
|
+
inlineDynamicImports: true
|
|
2036
|
+
});
|
|
2037
|
+
await bundle.close();
|
|
2038
|
+
}
|
|
2039
|
+
function resolveElectronBinary(config) {
|
|
2040
|
+
if (config.electron.electronPath && import_node_fs10.default.existsSync(config.electron.electronPath)) {
|
|
2041
|
+
return config.electron.electronPath;
|
|
2042
|
+
}
|
|
2043
|
+
try {
|
|
2044
|
+
const require2 = (0, import_node_module3.createRequire)(import_node_path12.default.resolve(config.root, "package.json"));
|
|
2045
|
+
const pathFile = require2.resolve("electron");
|
|
2046
|
+
const electronModule = require2(pathFile);
|
|
2047
|
+
if (typeof electronModule === "string" && import_node_fs10.default.existsSync(electronModule)) {
|
|
2048
|
+
return electronModule;
|
|
2049
|
+
}
|
|
2050
|
+
} catch {
|
|
2051
|
+
}
|
|
2052
|
+
return null;
|
|
2053
|
+
}
|
|
2054
|
+
function warnElectronVersion(config) {
|
|
2055
|
+
const installed = detectInstalledElectron(config.root);
|
|
2056
|
+
if (installed === null) {
|
|
2057
|
+
console.warn(
|
|
2058
|
+
import_picocolors4.default.yellow(
|
|
2059
|
+
` \u26A0 \u672A\u68C0\u6D4B\u5230 Electron\uFF0C\u8BF7\u5B89\u88C5\uFF1Anpm install -D electron@^${config.electron.minVersion}`
|
|
2060
|
+
)
|
|
2061
|
+
);
|
|
2062
|
+
return;
|
|
2063
|
+
}
|
|
2064
|
+
if (installed < config.electron.minVersion) {
|
|
2065
|
+
console.warn(
|
|
2066
|
+
import_picocolors4.default.yellow(
|
|
2067
|
+
` \u26A0 Electron ${installed} \u4F4E\u4E8E Nasti \u8981\u6C42\u7684 ${config.electron.minVersion}\uFF0C\u67D0\u4E9B\u7279\u6027\uFF08\u5982 ESM \u4E3B\u8FDB\u7A0B\uFF09\u4E0D\u53EF\u7528\u3002`
|
|
2068
|
+
)
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
1611
2072
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1612
2073
|
0 && (module.exports = {
|
|
1613
2074
|
build,
|
|
2075
|
+
buildElectron,
|
|
1614
2076
|
createServer,
|
|
1615
2077
|
defineConfig,
|
|
1616
|
-
|
|
2078
|
+
electronPlugin,
|
|
2079
|
+
resolveConfig,
|
|
2080
|
+
startElectronDev
|
|
1617
2081
|
});
|
|
1618
2082
|
//# sourceMappingURL=index.cjs.map
|