@nasti-toolchain/nasti 1.3.10 → 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 +484 -23
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +482 -23
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1752 -1289
- 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 -1282
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,1428 +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 * as __ns_${safe} from "/@modules/${pkg}";`);
|
|
368
|
-
imports.push(`var __req_${safe} = "default" in __ns_${safe} ? __ns_${safe}["default"] : __ns_${safe};`);
|
|
369
|
-
result = result.replaceAll(`__require("${pkg}")`, `__req_${safe}`);
|
|
370
|
-
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);
|
|
371
359
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
(k) => k !== "__esModule" && k !== "default" && VALID_IDENT.test(k)
|
|
382
|
-
);
|
|
383
|
-
if (namedKeys.length === 0) return code;
|
|
384
|
-
return code.replace(
|
|
385
|
-
/^export default (\w+\(\));?\s*$/m,
|
|
386
|
-
(_, call) => [
|
|
387
|
-
`const __cjsMod = ${call};`,
|
|
388
|
-
`export default __cjsMod;`,
|
|
389
|
-
...namedKeys.map((k) => `export const ${k} = __cjsMod[${JSON.stringify(k)}];`)
|
|
390
|
-
].join("\n")
|
|
391
|
-
);
|
|
392
|
-
} catch {
|
|
393
|
-
return code;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
function rewriteImports(code, _config) {
|
|
397
|
-
return code.replace(
|
|
398
|
-
/\bfrom\s+(['"])([^'"./][^'"]*)\1/g,
|
|
399
|
-
(match, quote, specifier) => {
|
|
400
|
-
return `from ${quote}/@modules/${specifier}${quote}`;
|
|
401
|
-
}
|
|
402
|
-
).replace(
|
|
403
|
-
// 处理纯副作用导入: import 'bare-specifier'
|
|
404
|
-
/\bimport\s+(['"])([^'"./][^'"]*)\1/g,
|
|
405
|
-
(match, quote, specifier) => {
|
|
406
|
-
return `import ${quote}/@modules/${specifier}${quote}`;
|
|
407
|
-
}
|
|
408
|
-
).replace(
|
|
409
|
-
// 处理动态导入: import('bare-specifier')
|
|
410
|
-
/\bimport\s*\(\s*(['"])([^'"./][^'"]*)\1\s*\)/g,
|
|
411
|
-
(match, quote, specifier) => {
|
|
412
|
-
return `import(${quote}/@modules/${specifier}${quote})`;
|
|
413
|
-
}
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
function resolveNodeModule(root, moduleName) {
|
|
417
|
-
let pkgName;
|
|
418
|
-
let subpath;
|
|
419
|
-
if (moduleName.startsWith("@")) {
|
|
420
|
-
const parts = moduleName.split("/");
|
|
421
|
-
pkgName = parts.slice(0, 2).join("/");
|
|
422
|
-
subpath = parts.slice(2).join("/");
|
|
423
|
-
} else {
|
|
424
|
-
const slash = moduleName.indexOf("/");
|
|
425
|
-
pkgName = slash === -1 ? moduleName : moduleName.slice(0, slash);
|
|
426
|
-
subpath = slash === -1 ? "" : moduleName.slice(slash + 1);
|
|
427
|
-
}
|
|
428
|
-
let pkgDir = null;
|
|
429
|
-
let dir = root;
|
|
430
|
-
for (; ; ) {
|
|
431
|
-
const candidate = import_node_path8.default.join(dir, "node_modules", pkgName);
|
|
432
|
-
if (import_node_fs7.default.existsSync(candidate)) {
|
|
433
|
-
pkgDir = candidate;
|
|
434
|
-
break;
|
|
435
|
-
}
|
|
436
|
-
const parent = import_node_path8.default.dirname(dir);
|
|
437
|
-
if (parent === dir) break;
|
|
438
|
-
dir = parent;
|
|
439
|
-
}
|
|
440
|
-
if (!pkgDir) return null;
|
|
441
|
-
const pkgJsonPath = import_node_path8.default.join(pkgDir, "package.json");
|
|
442
|
-
if (!import_node_fs7.default.existsSync(pkgJsonPath)) return null;
|
|
443
|
-
let pkg;
|
|
444
|
-
try {
|
|
445
|
-
pkg = JSON.parse(import_node_fs7.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
446
|
-
} catch {
|
|
447
|
-
return null;
|
|
448
|
-
}
|
|
449
|
-
if (pkg.exports) {
|
|
450
|
-
const exportKey = subpath ? `./${subpath}` : ".";
|
|
451
|
-
const resolved = resolvePackageExports(pkg.exports, exportKey, pkgDir);
|
|
452
|
-
if (resolved) return resolved;
|
|
453
|
-
}
|
|
454
|
-
if (subpath) {
|
|
455
|
-
const subDirs = [""];
|
|
456
|
-
for (const field of ["module", "main"]) {
|
|
457
|
-
if (typeof pkg[field] === "string") {
|
|
458
|
-
const dir2 = import_node_path8.default.dirname(pkg[field]);
|
|
459
|
-
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;
|
|
460
369
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
+
}
|
|
467
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;
|
|
468
395
|
}
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
|
|
472
|
-
if (typeof pkg[field] === "string") {
|
|
473
|
-
const entry = import_node_path8.default.join(pkgDir, pkg[field]);
|
|
474
|
-
if (import_node_fs7.default.existsSync(entry)) return entry;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
const indexFallback = import_node_path8.default.join(pkgDir, "index.js");
|
|
478
|
-
if (import_node_fs7.default.existsSync(indexFallback)) return indexFallback;
|
|
479
|
-
return null;
|
|
480
|
-
}
|
|
481
|
-
function resolvePackageExports(exports2, key, pkgDir) {
|
|
482
|
-
if (typeof exports2 === "string") {
|
|
483
|
-
return key === "." ? import_node_path8.default.join(pkgDir, exports2) : null;
|
|
484
|
-
}
|
|
485
|
-
const entry = exports2[key];
|
|
486
|
-
if (entry === void 0) return null;
|
|
487
|
-
return resolveExportValue(entry, pkgDir);
|
|
396
|
+
};
|
|
488
397
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
+
]);
|
|
497
429
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
+
});
|
|
503
445
|
}
|
|
446
|
+
return { html, tags };
|
|
504
447
|
}
|
|
505
|
-
}
|
|
506
|
-
return null;
|
|
448
|
+
};
|
|
507
449
|
}
|
|
508
|
-
function
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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)}`);
|
|
513
458
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
459
|
+
if (head.length) {
|
|
460
|
+
html = html.replace(/<\/head>/i, `${serializeTags(head)}
|
|
461
|
+
</head>`);
|
|
517
462
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
463
|
+
if (bodyPrepend.length) {
|
|
464
|
+
html = html.replace(/<body([^>]*)>/i, `<body$1>
|
|
465
|
+
${serializeTags(bodyPrepend)}`);
|
|
521
466
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
467
|
+
if (body.length) {
|
|
468
|
+
html = html.replace(/<\/body>/i, `${serializeTags(body)}
|
|
469
|
+
</body>`);
|
|
525
470
|
}
|
|
526
|
-
return
|
|
471
|
+
return html;
|
|
527
472
|
}
|
|
528
|
-
function
|
|
529
|
-
|
|
530
|
-
if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
|
|
531
|
-
if (cleanUrl.startsWith("/@modules/")) return true;
|
|
532
|
-
if (!import_node_path8.default.extname(cleanUrl)) return true;
|
|
533
|
-
return false;
|
|
473
|
+
function serializeTags(tags) {
|
|
474
|
+
return tags.map(serializeTag).join("\n");
|
|
534
475
|
}
|
|
535
|
-
function
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
break;
|
|
556
|
-
case 'full-reload':
|
|
557
|
-
console.log('[nasti] full reload');
|
|
558
|
-
location.reload();
|
|
559
|
-
break;
|
|
560
|
-
case 'error':
|
|
561
|
-
console.error('[nasti] error:', payload.err.message);
|
|
562
|
-
showErrorOverlay(payload.err);
|
|
563
|
-
break;
|
|
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} />`;
|
|
482
|
+
}
|
|
483
|
+
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
484
|
+
}
|
|
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");
|
|
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);
|
|
564
496
|
}
|
|
565
497
|
});
|
|
566
498
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const newMod = await import(update.acceptedPath + '?t=' + update.timestamp);
|
|
571
|
-
mod.callbacks.forEach((cb) => cb(newMod));
|
|
572
|
-
} else {
|
|
573
|
-
// \u6CA1\u6709\u6CE8\u518C hot \u56DE\u8C03\uFF0C\u5C1D\u8BD5\u91CD\u65B0 import
|
|
574
|
-
await import(update.path + '?t=' + update.timestamp);
|
|
575
|
-
}
|
|
499
|
+
// src/core/transformer.ts
|
|
500
|
+
function shouldTransform(id) {
|
|
501
|
+
return TS_EXTENSIONS.test(id) || JSX_EXTENSIONS.test(id) || JS_EXTENSIONS.test(id) && false;
|
|
576
502
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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}`);
|
|
584
519
|
}
|
|
520
|
+
return {
|
|
521
|
+
code: result.code,
|
|
522
|
+
map: result.map ? JSON.stringify(result.map) : null
|
|
523
|
+
};
|
|
585
524
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
overlay.id = 'nasti-error-overlay';
|
|
590
|
-
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;';
|
|
591
|
-
const title = document.createElement('h2');
|
|
592
|
-
title.style.color = '#ff5555';
|
|
593
|
-
title.textContent = 'Build Error';
|
|
594
|
-
const pre = document.createElement('pre');
|
|
595
|
-
pre.textContent = err.message + '\\n' + (err.stack || '');
|
|
596
|
-
const btn = document.createElement('button');
|
|
597
|
-
btn.style.cssText = 'margin-top:1rem;padding:0.5rem 1rem;cursor:pointer';
|
|
598
|
-
btn.textContent = 'Close';
|
|
599
|
-
btn.onclick = () => overlay.remove();
|
|
600
|
-
overlay.appendChild(title);
|
|
601
|
-
overlay.appendChild(pre);
|
|
602
|
-
overlay.appendChild(btn);
|
|
603
|
-
document.body.appendChild(overlay);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// import.meta.hot API
|
|
607
|
-
const createHotContext = (ownerPath) => ({
|
|
608
|
-
accept(deps, callback) {
|
|
609
|
-
if (typeof deps === 'function' || !deps) {
|
|
610
|
-
// self-accepting
|
|
611
|
-
const callbacks = hotModulesMap.get(ownerPath)?.callbacks || [];
|
|
612
|
-
callbacks.push(deps || (() => {}));
|
|
613
|
-
hotModulesMap.set(ownerPath, { callbacks });
|
|
614
|
-
}
|
|
615
|
-
},
|
|
616
|
-
prune(callback) {
|
|
617
|
-
// \u6A21\u5757\u88AB\u79FB\u9664\u65F6\u6267\u884C
|
|
618
|
-
},
|
|
619
|
-
dispose(callback) {
|
|
620
|
-
// \u6A21\u5757\u66F4\u65B0\u524D\u6267\u884C\u6E05\u7406
|
|
621
|
-
},
|
|
622
|
-
invalidate() {
|
|
623
|
-
location.reload();
|
|
624
|
-
},
|
|
625
|
-
data: {},
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
// \u66B4\u9732\u7ED9\u6A21\u5757\u4F7F\u7528
|
|
629
|
-
if (!window.__nasti_hot_map) window.__nasti_hot_map = new Map();
|
|
630
|
-
window.__NASTI_HMR__ = { createHotContext };
|
|
631
|
-
`;
|
|
632
|
-
}
|
|
633
|
-
var import_node_path8, import_node_fs7, REACT_REFRESH_RUNTIME, REACT_REFRESH_PREAMBLE, REACT_REFRESH_FOOTER, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
634
|
-
var init_middleware = __esm({
|
|
635
|
-
"src/server/middleware.ts"() {
|
|
525
|
+
var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
|
|
526
|
+
var init_transformer = __esm({
|
|
527
|
+
"src/core/transformer.ts"() {
|
|
636
528
|
"use strict";
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
init_env();
|
|
642
|
-
REACT_REFRESH_RUNTIME = `
|
|
643
|
-
export function createSignatureFunctionForTransform() {
|
|
644
|
-
return function(type, key, forceReset, getCustomHooks) { return type; };
|
|
645
|
-
}
|
|
646
|
-
export function register(type, id) {}
|
|
647
|
-
export default { createSignatureFunctionForTransform, register };
|
|
648
|
-
`;
|
|
649
|
-
REACT_REFRESH_PREAMBLE = `
|
|
650
|
-
import RefreshRuntime from '/@react-refresh';
|
|
651
|
-
if (!window.$RefreshReg$) {
|
|
652
|
-
window.$RefreshReg$ = (type, id) => RefreshRuntime.register(type, import.meta.url + ' ' + id);
|
|
653
|
-
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
|
|
654
|
-
}
|
|
655
|
-
`;
|
|
656
|
-
REACT_REFRESH_FOOTER = `
|
|
657
|
-
if (import.meta.hot) {
|
|
658
|
-
import.meta.hot.accept();
|
|
659
|
-
}
|
|
660
|
-
`;
|
|
661
|
-
esmBundleCache = /* @__PURE__ */ new Map();
|
|
662
|
-
VALID_IDENT = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
663
|
-
RESOLVE_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".json", ".vue"];
|
|
664
|
-
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)$/;
|
|
665
533
|
}
|
|
666
534
|
});
|
|
667
535
|
|
|
668
|
-
// src/
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
host: "localhost",
|
|
693
|
-
https: false,
|
|
694
|
-
open: false,
|
|
695
|
-
proxy: {},
|
|
696
|
-
cors: true,
|
|
697
|
-
hmr: true
|
|
698
|
-
};
|
|
699
|
-
var defaultBuild = {
|
|
700
|
-
outDir: "dist",
|
|
701
|
-
assetsDir: "assets",
|
|
702
|
-
minify: true,
|
|
703
|
-
sourcemap: false,
|
|
704
|
-
target: "es2022",
|
|
705
|
-
rolldownOptions: {},
|
|
706
|
-
emptyOutDir: true
|
|
707
|
-
};
|
|
708
|
-
var defaults = {
|
|
709
|
-
root: ".",
|
|
710
|
-
base: "/",
|
|
711
|
-
mode: "development",
|
|
712
|
-
framework: "auto",
|
|
713
|
-
resolve: defaultResolve,
|
|
714
|
-
server: defaultServer,
|
|
715
|
-
build: defaultBuild,
|
|
716
|
-
plugins: [],
|
|
717
|
-
envPrefix: ["NASTI_", "VITE_"],
|
|
718
|
-
logLevel: "info"
|
|
719
|
-
};
|
|
720
|
-
|
|
721
|
-
// src/config/index.ts
|
|
722
|
-
function loadTsconfigPaths(root) {
|
|
723
|
-
const tsconfigPath = import_node_path.default.resolve(root, "tsconfig.json");
|
|
724
|
-
if (!import_node_fs.default.existsSync(tsconfigPath)) return {};
|
|
725
|
-
try {
|
|
726
|
-
const content = import_node_fs.default.readFileSync(tsconfigPath, "utf-8");
|
|
727
|
-
const stripped = content.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
728
|
-
const tsconfig = JSON.parse(stripped);
|
|
729
|
-
const paths = tsconfig?.compilerOptions?.paths ?? {};
|
|
730
|
-
const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? ".";
|
|
731
|
-
const alias = {};
|
|
732
|
-
for (const [pattern, targets] of Object.entries(paths)) {
|
|
733
|
-
if (!targets.length) continue;
|
|
734
|
-
const cleanKey = pattern.replace(/\/\*$/, "");
|
|
735
|
-
const cleanTarget = targets[0].replace(/\/\*$/, "");
|
|
736
|
-
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;
|
|
737
560
|
}
|
|
738
|
-
return alias;
|
|
739
|
-
} catch {
|
|
740
|
-
return {};
|
|
741
561
|
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
var CONFIG_FILES = [
|
|
747
|
-
"nasti.config.ts",
|
|
748
|
-
"nasti.config.js",
|
|
749
|
-
"nasti.config.mjs",
|
|
750
|
-
"nasti.config.mts"
|
|
751
|
-
];
|
|
752
|
-
async function loadConfigFromFile(root) {
|
|
753
|
-
for (const file of CONFIG_FILES) {
|
|
754
|
-
const filePath = import_node_path.default.resolve(root, file);
|
|
755
|
-
if (!import_node_fs.default.existsSync(filePath)) continue;
|
|
756
|
-
if (file.endsWith(".ts") || file.endsWith(".mts")) {
|
|
757
|
-
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;
|
|
758
566
|
}
|
|
759
|
-
const mod = await import((0, import_node_url.pathToFileURL)(filePath).href);
|
|
760
|
-
return mod.default ?? mod;
|
|
761
567
|
}
|
|
762
|
-
return
|
|
568
|
+
return filtered;
|
|
763
569
|
}
|
|
764
|
-
|
|
765
|
-
const
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
typescript: {}
|
|
769
|
-
});
|
|
770
|
-
const tmpFile = filePath + ".timestamp-" + Date.now() + ".mjs";
|
|
771
|
-
try {
|
|
772
|
-
import_node_fs.default.writeFileSync(tmpFile, result.code);
|
|
773
|
-
const mod = await import((0, import_node_url.pathToFileURL)(tmpFile).href);
|
|
774
|
-
return mod.default ?? mod;
|
|
775
|
-
} finally {
|
|
776
|
-
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);
|
|
777
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;
|
|
778
580
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
...fileConfig.plugins ?? [],
|
|
785
|
-
...inlineConfig.plugins ?? []
|
|
786
|
-
];
|
|
787
|
-
const env = { mode: merged.mode ?? defaults.mode, command };
|
|
788
|
-
for (const plugin of rawPlugins) {
|
|
789
|
-
if (plugin.config) {
|
|
790
|
-
const result = await plugin.config(merged, env);
|
|
791
|
-
if (result) Object.assign(merged, result);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
const resolved = {
|
|
795
|
-
root,
|
|
796
|
-
base: merged.base ?? defaults.base,
|
|
797
|
-
mode: command === "build" ? "production" : "development",
|
|
798
|
-
framework: merged.framework ?? defaults.framework,
|
|
799
|
-
command,
|
|
800
|
-
resolve: {
|
|
801
|
-
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
802
|
-
alias: { ...loadTsconfigPaths(root), ...defaults.resolve.alias, ...merged.resolve?.alias },
|
|
803
|
-
extensions: merged.resolve?.extensions ?? defaults.resolve.extensions,
|
|
804
|
-
conditions: merged.resolve?.conditions ?? defaults.resolve.conditions,
|
|
805
|
-
mainFields: merged.resolve?.mainFields ?? defaults.resolve.mainFields
|
|
806
|
-
},
|
|
807
|
-
plugins: [],
|
|
808
|
-
server: { ...defaults.server, ...merged.server },
|
|
809
|
-
build: { ...defaults.build, ...merged.build },
|
|
810
|
-
envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
|
|
811
|
-
logLevel: merged.logLevel ?? defaults.logLevel
|
|
812
|
-
};
|
|
813
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
814
|
-
if (!p.apply) return true;
|
|
815
|
-
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
816
|
-
return p.apply === command;
|
|
817
|
-
});
|
|
818
|
-
resolved.plugins = filteredPlugins;
|
|
819
|
-
for (const plugin of resolved.plugins) {
|
|
820
|
-
if (plugin.configResolved) {
|
|
821
|
-
await plugin.configResolved(resolved);
|
|
822
|
-
}
|
|
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);
|
|
823
586
|
}
|
|
824
|
-
return
|
|
587
|
+
return result;
|
|
825
588
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
result[key] ?? {},
|
|
833
|
-
val
|
|
834
|
-
);
|
|
835
|
-
} else if (val !== void 0) {
|
|
836
|
-
result[key] = val;
|
|
837
|
-
}
|
|
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);
|
|
838
595
|
}
|
|
839
|
-
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// src/build/index.ts
|
|
843
|
-
var import_node_path7 = __toESM(require("path"), 1);
|
|
844
|
-
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
845
|
-
var import_rolldown = require("rolldown");
|
|
596
|
+
});
|
|
846
597
|
|
|
847
|
-
// src/
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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);
|
|
863
652
|
}
|
|
864
|
-
break;
|
|
865
653
|
}
|
|
866
654
|
}
|
|
867
|
-
|
|
868
|
-
const
|
|
869
|
-
|
|
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
|
+
}
|
|
870
661
|
}
|
|
871
|
-
|
|
872
|
-
const
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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;
|
|
876
674
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
return resolved;
|
|
883
|
-
} catch {
|
|
884
|
-
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;
|
|
885
680
|
}
|
|
681
|
+
return null;
|
|
886
682
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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 };
|
|
894
696
|
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
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
|
+
};
|
|
902
715
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
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
|
+
}
|
|
907
743
|
}
|
|
908
744
|
}
|
|
909
|
-
if (
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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;
|
|
914
752
|
}
|
|
915
753
|
}
|
|
916
754
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
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",
|
|
929
768
|
transform(code, id) {
|
|
930
|
-
if (!id
|
|
931
|
-
const
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
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
|
|
950
796
|
});
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
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);
|
|
956
824
|
}
|
|
957
|
-
return rewritten !== code ? { code: rewritten } : null;
|
|
958
825
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
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
|
+
}
|
|
965
834
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
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 };
|
|
970
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
|
+
});
|
|
971
875
|
|
|
972
|
-
// src/
|
|
973
|
-
var
|
|
974
|
-
var
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
".webp",
|
|
984
|
-
".avif",
|
|
985
|
-
".mp4",
|
|
986
|
-
".webm",
|
|
987
|
-
".ogg",
|
|
988
|
-
".mp3",
|
|
989
|
-
".wav",
|
|
990
|
-
".flac",
|
|
991
|
-
".aac",
|
|
992
|
-
".woff",
|
|
993
|
-
".woff2",
|
|
994
|
-
".eot",
|
|
995
|
-
".ttf",
|
|
996
|
-
".otf",
|
|
997
|
-
".pdf",
|
|
998
|
-
".txt"
|
|
999
|
-
]);
|
|
1000
|
-
function assetsPlugin(config) {
|
|
1001
|
-
return {
|
|
1002
|
-
name: "nasti:assets",
|
|
1003
|
-
resolveId(source) {
|
|
1004
|
-
if (source.endsWith("?url") || source.endsWith("?raw")) {
|
|
1005
|
-
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);
|
|
1006
887
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
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);
|
|
1016
924
|
}
|
|
925
|
+
mods.add(mod);
|
|
1017
926
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
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
|
+
}
|
|
1024
939
|
}
|
|
1025
|
-
const content = import_node_fs3.default.readFileSync(file);
|
|
1026
|
-
const hash = import_node_crypto.default.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
1027
|
-
const basename = import_node_path4.default.basename(file, ext);
|
|
1028
|
-
const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
|
|
1029
|
-
return `export default ${JSON.stringify(config.base + hashedName)}`;
|
|
1030
940
|
}
|
|
1031
|
-
|
|
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();
|
|
1032
1022
|
}
|
|
1033
1023
|
};
|
|
1034
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
|
+
});
|
|
1035
1032
|
|
|
1036
|
-
// src/
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
emitFile(file) {
|
|
1059
|
-
const fileName = file.fileName ?? file.name ?? `asset-${container.emittedFiles.size}`;
|
|
1060
|
-
const id = `emitted:${fileName}`;
|
|
1061
|
-
container.emittedFiles.set(id, {
|
|
1062
|
-
fileName,
|
|
1063
|
-
source: file.source ?? ""
|
|
1064
|
-
});
|
|
1065
|
-
return id;
|
|
1066
|
-
},
|
|
1067
|
-
getModuleInfo(_id) {
|
|
1068
|
-
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;
|
|
1069
1055
|
}
|
|
1070
|
-
}
|
|
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;
|
|
1071
1273
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
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;
|
|
1075
1287
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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);
|
|
1080
1294
|
}
|
|
1081
1295
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
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;
|
|
1087
1301
|
}
|
|
1088
1302
|
}
|
|
1303
|
+
return null;
|
|
1089
1304
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
this.ctx,
|
|
1095
|
-
source,
|
|
1096
|
-
importer ?? void 0,
|
|
1097
|
-
{ isEntry: options.isEntry ?? false, ssr: false }
|
|
1098
|
-
);
|
|
1099
|
-
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;
|
|
1100
1309
|
}
|
|
1101
|
-
return null;
|
|
1102
1310
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
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;
|
|
1108
1329
|
}
|
|
1109
1330
|
return null;
|
|
1110
1331
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
if (result == null) continue;
|
|
1117
|
-
if (typeof result === "string") {
|
|
1118
|
-
currentCode = result;
|
|
1119
|
-
} else {
|
|
1120
|
-
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;
|
|
1121
1337
|
}
|
|
1122
1338
|
}
|
|
1123
|
-
return currentCode === code ? null : { code: currentCode };
|
|
1124
|
-
}
|
|
1125
|
-
/** 完整的模块处理管道: resolveId → load → transform */
|
|
1126
|
-
async processModule(source, importer) {
|
|
1127
|
-
const resolveResult = await this.resolveId(source, importer, {
|
|
1128
|
-
isEntry: !importer
|
|
1129
|
-
});
|
|
1130
|
-
if (resolveResult == null) return null;
|
|
1131
|
-
const id = typeof resolveResult === "string" ? resolveResult : resolveResult.id;
|
|
1132
|
-
const loadResult = await this.load(id);
|
|
1133
|
-
if (loadResult == null) return null;
|
|
1134
|
-
const loadedCode = typeof loadResult === "string" ? loadResult : loadResult.code;
|
|
1135
|
-
const transformResult = await this.transform(loadedCode, id);
|
|
1136
|
-
const finalCode = transformResult == null ? loadedCode : typeof transformResult === "string" ? transformResult : transformResult.code;
|
|
1137
|
-
return { id, code: finalCode };
|
|
1138
|
-
}
|
|
1139
|
-
getPlugins() {
|
|
1140
|
-
return this.plugins;
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
function sortPlugins(plugins) {
|
|
1144
|
-
const pre = [];
|
|
1145
|
-
const normal = [];
|
|
1146
|
-
const post = [];
|
|
1147
|
-
for (const plugin of plugins) {
|
|
1148
|
-
if (plugin.enforce === "pre") pre.push(plugin);
|
|
1149
|
-
else if (plugin.enforce === "post") post.push(plugin);
|
|
1150
|
-
else normal.push(plugin);
|
|
1151
1339
|
}
|
|
1152
|
-
return
|
|
1340
|
+
return null;
|
|
1153
1341
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
const startTime = performance.now();
|
|
1160
|
-
console.log(import_picocolors.default.cyan("\n\u{1F528} nasti build") + import_picocolors.default.dim(` v${"1.3.10"}`));
|
|
1161
|
-
console.log(import_picocolors.default.dim(` root: ${config.root}`));
|
|
1162
|
-
console.log(import_picocolors.default.dim(` mode: ${config.mode}`));
|
|
1163
|
-
const outDir = import_node_path7.default.resolve(config.root, config.build.outDir);
|
|
1164
|
-
if (config.build.emptyOutDir && import_node_fs6.default.existsSync(outDir)) {
|
|
1165
|
-
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);
|
|
1166
1347
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
if (html) {
|
|
1171
|
-
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
1172
|
-
for (const match of scriptMatches) {
|
|
1173
|
-
const src = match[1];
|
|
1174
|
-
if (src && !src.startsWith("http")) {
|
|
1175
|
-
entryPoints.push(import_node_path7.default.resolve(config.root, src.replace(/^\//, "")));
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
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;
|
|
1178
1351
|
}
|
|
1179
|
-
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
const fullPath = import_node_path7.default.resolve(config.root, entry);
|
|
1183
|
-
if (import_node_fs6.default.existsSync(fullPath)) {
|
|
1184
|
-
entryPoints.push(fullPath);
|
|
1185
|
-
break;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1352
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
1353
|
+
const withExt = filePath + ext;
|
|
1354
|
+
if (import_node_fs8.default.existsSync(withExt)) return withExt;
|
|
1188
1355
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
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;
|
|
1191
1359
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
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
|
+
}
|
|
1208
1388
|
});
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
oxcTransformPlugin,
|
|
1219
|
-
// 转换 Nasti 插件为 Rolldown 插件格式
|
|
1220
|
-
...allPlugins.map((p) => ({
|
|
1221
|
-
name: p.name,
|
|
1222
|
-
resolveId: p.resolveId,
|
|
1223
|
-
load: p.load,
|
|
1224
|
-
transform: p.transform,
|
|
1225
|
-
buildStart: p.buildStart,
|
|
1226
|
-
buildEnd: p.buildEnd
|
|
1227
|
-
}))
|
|
1228
|
-
],
|
|
1229
|
-
...config.build.rolldownOptions
|
|
1230
|
-
});
|
|
1231
|
-
const { output } = await bundle.write({
|
|
1232
|
-
dir: outDir,
|
|
1233
|
-
format: "esm",
|
|
1234
|
-
sourcemap: !!config.build.sourcemap,
|
|
1235
|
-
minify: !!config.build.minify,
|
|
1236
|
-
entryFileNames: "assets/[name].[hash].js",
|
|
1237
|
-
chunkFileNames: "assets/[name].[hash].js",
|
|
1238
|
-
assetFileNames: "assets/[name].[hash][extname]"
|
|
1239
|
-
});
|
|
1240
|
-
await bundle.close();
|
|
1241
|
-
await pluginContainer.buildEnd();
|
|
1242
|
-
for (const ef of pluginContainer.getEmittedFiles()) {
|
|
1243
|
-
const dest = import_node_path7.default.resolve(outDir, ef.fileName);
|
|
1244
|
-
import_node_fs6.default.mkdirSync(import_node_path7.default.dirname(dest), { recursive: true });
|
|
1245
|
-
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;
|
|
1246
1398
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
processedHtml = processHtml(processedHtml, result);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
for (const chunk of output) {
|
|
1261
|
-
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
1262
|
-
const originalEntry = import_node_path7.default.relative(config.root, chunk.facadeModuleId);
|
|
1263
|
-
processedHtml = processedHtml.replace(
|
|
1264
|
-
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
1265
|
-
`$1${config.base}${chunk.fileName}$3`
|
|
1266
|
-
);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
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);
|
|
1270
1409
|
}
|
|
1271
|
-
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
1272
|
-
const totalSize = output.reduce((sum, chunk) => {
|
|
1273
|
-
if (chunk.type === "chunk" && chunk.code) return sum + chunk.code.length;
|
|
1274
|
-
return sum;
|
|
1275
|
-
}, 0);
|
|
1276
|
-
console.log(import_picocolors.default.green(`
|
|
1277
|
-
\u2713 Built in ${elapsed}s`));
|
|
1278
|
-
console.log(import_picocolors.default.dim(` ${output.length} files, ${formatSize(totalSize)} total`));
|
|
1279
|
-
console.log(import_picocolors.default.dim(` output: ${config.build.outDir}/
|
|
1280
|
-
`));
|
|
1281
|
-
return { output };
|
|
1282
1410
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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
|
+
}
|
|
1287
1419
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
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);
|
|
1290
1438
|
}
|
|
1291
1439
|
|
|
1292
|
-
//
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
// src/core/module-graph.ts
|
|
1302
|
-
var ModuleGraph = class {
|
|
1303
|
-
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
1304
|
-
idToModuleMap = /* @__PURE__ */ new Map();
|
|
1305
|
-
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
1306
|
-
getModuleByUrl(url) {
|
|
1307
|
-
return this.urlToModuleMap.get(url);
|
|
1308
|
-
}
|
|
1309
|
-
getModuleById(id) {
|
|
1310
|
-
return this.idToModuleMap.get(id);
|
|
1311
|
-
}
|
|
1312
|
-
getModulesByFile(file) {
|
|
1313
|
-
return this.fileToModulesMap.get(file);
|
|
1314
|
-
}
|
|
1315
|
-
async ensureEntryFromUrl(url) {
|
|
1316
|
-
let mod = this.urlToModuleMap.get(url);
|
|
1317
|
-
if (mod) return mod;
|
|
1318
|
-
mod = this.createModule(url);
|
|
1319
|
-
this.urlToModuleMap.set(url, mod);
|
|
1320
|
-
return mod;
|
|
1321
|
-
}
|
|
1322
|
-
createModule(url, id) {
|
|
1323
|
-
const mod = {
|
|
1324
|
-
id: id ?? url,
|
|
1325
|
-
file: null,
|
|
1326
|
-
url,
|
|
1327
|
-
type: url.endsWith(".css") ? "css" : "js",
|
|
1328
|
-
importers: /* @__PURE__ */ new Set(),
|
|
1329
|
-
importedModules: /* @__PURE__ */ new Set(),
|
|
1330
|
-
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
1331
|
-
transformResult: null,
|
|
1332
|
-
lastHMRTimestamp: 0,
|
|
1333
|
-
isSelfAccepting: false
|
|
1334
|
-
};
|
|
1335
|
-
this.idToModuleMap.set(mod.id, mod);
|
|
1336
|
-
return mod;
|
|
1337
|
-
}
|
|
1338
|
-
/** 注册文件路径到模块的映射 */
|
|
1339
|
-
registerModule(mod, file) {
|
|
1340
|
-
mod.file = file;
|
|
1341
|
-
let mods = this.fileToModulesMap.get(file);
|
|
1342
|
-
if (!mods) {
|
|
1343
|
-
mods = /* @__PURE__ */ new Set();
|
|
1344
|
-
this.fileToModulesMap.set(file, mods);
|
|
1345
|
-
}
|
|
1346
|
-
mods.add(mod);
|
|
1347
|
-
}
|
|
1348
|
-
/** 更新模块依赖关系 */
|
|
1349
|
-
updateModuleImports(mod, importedIds) {
|
|
1350
|
-
for (const imported of mod.importedModules) {
|
|
1351
|
-
imported.importers.delete(mod);
|
|
1352
|
-
}
|
|
1353
|
-
mod.importedModules.clear();
|
|
1354
|
-
for (const id of importedIds) {
|
|
1355
|
-
const importedMod = this.idToModuleMap.get(id);
|
|
1356
|
-
if (importedMod) {
|
|
1357
|
-
mod.importedModules.add(importedMod);
|
|
1358
|
-
importedMod.importers.add(mod);
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
/** 使模块的转换缓存失效 */
|
|
1363
|
-
invalidateModule(mod) {
|
|
1364
|
-
mod.transformResult = null;
|
|
1365
|
-
mod.lastHMRTimestamp = Date.now();
|
|
1366
|
-
}
|
|
1367
|
-
/** 使所有模块缓存失效 */
|
|
1368
|
-
invalidateAll() {
|
|
1369
|
-
for (const mod of this.idToModuleMap.values()) {
|
|
1370
|
-
this.invalidateModule(mod);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
1374
|
-
getHmrBoundaries(mod) {
|
|
1375
|
-
const boundaries = [];
|
|
1376
|
-
const visited = /* @__PURE__ */ new Set();
|
|
1377
|
-
const propagate = (node, via) => {
|
|
1378
|
-
if (visited.has(node)) return true;
|
|
1379
|
-
visited.add(node);
|
|
1380
|
-
if (node.isSelfAccepting) {
|
|
1381
|
-
boundaries.push({ boundary: node, acceptedVia: via });
|
|
1382
|
-
return true;
|
|
1383
|
-
}
|
|
1384
|
-
if (node.acceptedHmrDeps.has(via)) {
|
|
1385
|
-
boundaries.push({ boundary: node, acceptedVia: via });
|
|
1386
|
-
return true;
|
|
1387
|
-
}
|
|
1388
|
-
if (node.importers.size === 0) return false;
|
|
1389
|
-
for (const importer of node.importers) {
|
|
1390
|
-
if (!propagate(importer, node)) return false;
|
|
1391
|
-
}
|
|
1392
|
-
return true;
|
|
1393
|
-
};
|
|
1394
|
-
if (mod.isSelfAccepting) {
|
|
1395
|
-
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
1396
|
-
return boundaries;
|
|
1397
|
-
}
|
|
1398
|
-
for (const importer of mod.importers) {
|
|
1399
|
-
if (!propagate(importer, mod)) {
|
|
1400
|
-
return [];
|
|
1401
|
-
}
|
|
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 });
|
|
1402
1448
|
}
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
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
|
+
});
|
|
1406
1461
|
|
|
1407
|
-
//
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
const clients = /* @__PURE__ */ new Set();
|
|
1412
|
-
server.on("upgrade", (req, socket, head) => {
|
|
1413
|
-
if (req.headers["sec-websocket-protocol"] === "nasti-hmr") {
|
|
1414
|
-
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
1415
|
-
wss.emit("connection", ws, req);
|
|
1416
|
-
});
|
|
1417
|
-
}
|
|
1418
|
-
});
|
|
1419
|
-
wss.on("connection", (ws) => {
|
|
1420
|
-
clients.add(ws);
|
|
1421
|
-
ws.send(JSON.stringify({ type: "connected" }));
|
|
1422
|
-
ws.on("close", () => {
|
|
1423
|
-
clients.delete(ws);
|
|
1424
|
-
});
|
|
1425
|
-
ws.on("error", (err) => {
|
|
1426
|
-
console.error("[nasti] WebSocket error:", err);
|
|
1427
|
-
clients.delete(ws);
|
|
1428
|
-
});
|
|
1429
|
-
});
|
|
1430
|
-
return {
|
|
1431
|
-
send(payload) {
|
|
1432
|
-
const data = JSON.stringify(payload);
|
|
1433
|
-
for (const client of clients) {
|
|
1434
|
-
if (client.readyState === 1) {
|
|
1435
|
-
client.send(data);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
},
|
|
1439
|
-
close() {
|
|
1440
|
-
clients.clear();
|
|
1441
|
-
wss.close();
|
|
1442
|
-
}
|
|
1443
|
-
};
|
|
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
|
+
`;
|
|
1444
1466
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
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
|
+
});
|
|
1448
1501
|
|
|
1449
1502
|
// src/server/hmr.ts
|
|
1450
|
-
var import_node_path9 = __toESM(require("path"), 1);
|
|
1451
|
-
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
1452
1503
|
async function handleFileChange(file, server) {
|
|
1453
1504
|
const { moduleGraph, ws, config } = server;
|
|
1454
|
-
const relativePath = "/" +
|
|
1505
|
+
const relativePath = "/" + import_node_path10.default.relative(config.root, file);
|
|
1455
1506
|
const mods = moduleGraph.getModulesByFile(file);
|
|
1456
1507
|
if (!mods || mods.size === 0) {
|
|
1457
1508
|
return;
|
|
@@ -1464,7 +1515,7 @@ async function handleFileChange(file, server) {
|
|
|
1464
1515
|
file,
|
|
1465
1516
|
timestamp,
|
|
1466
1517
|
modules: [mod],
|
|
1467
|
-
read: () =>
|
|
1518
|
+
read: () => import_node_fs9.default.readFileSync(file, "utf-8"),
|
|
1468
1519
|
server
|
|
1469
1520
|
};
|
|
1470
1521
|
let affectedModules = [mod];
|
|
@@ -1496,9 +1547,20 @@ async function handleFileChange(file, server) {
|
|
|
1496
1547
|
ws.send({ type: "update", updates });
|
|
1497
1548
|
}
|
|
1498
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
|
+
});
|
|
1499
1558
|
|
|
1500
1559
|
// src/server/index.ts
|
|
1501
|
-
|
|
1560
|
+
var server_exports = {};
|
|
1561
|
+
__export(server_exports, {
|
|
1562
|
+
createServer: () => createServer
|
|
1563
|
+
});
|
|
1502
1564
|
async function createServer(inlineConfig = {}) {
|
|
1503
1565
|
const config = await resolveConfig(inlineConfig, "serve");
|
|
1504
1566
|
const allPlugins = [
|
|
@@ -1517,7 +1579,7 @@ async function createServer(inlineConfig = {}) {
|
|
|
1517
1579
|
pluginContainer,
|
|
1518
1580
|
moduleGraph
|
|
1519
1581
|
}));
|
|
1520
|
-
const publicDir =
|
|
1582
|
+
const publicDir = import_node_path11.default.resolve(config.root, "public");
|
|
1521
1583
|
app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
|
|
1522
1584
|
app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
|
|
1523
1585
|
const httpServer = import_node_http.default.createServer(app);
|
|
@@ -1560,14 +1622,15 @@ async function createServer(inlineConfig = {}) {
|
|
|
1560
1622
|
let currentPort = finalPort;
|
|
1561
1623
|
const onListening = () => {
|
|
1562
1624
|
const actualPort = httpServer.address()?.port ?? currentPort;
|
|
1625
|
+
config.server.port = actualPort;
|
|
1563
1626
|
const localUrl = `http://localhost:${actualPort}`;
|
|
1564
1627
|
const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
|
|
1565
1628
|
console.log();
|
|
1566
|
-
console.log(
|
|
1629
|
+
console.log(import_picocolors3.default.cyan(" nasti dev server") + import_picocolors3.default.dim(` v${"1.4.0"}`));
|
|
1567
1630
|
console.log();
|
|
1568
|
-
console.log(` ${
|
|
1631
|
+
console.log(` ${import_picocolors3.default.green(">")} Local: ${import_picocolors3.default.cyan(localUrl)}`);
|
|
1569
1632
|
if (networkUrl) {
|
|
1570
|
-
console.log(` ${
|
|
1633
|
+
console.log(` ${import_picocolors3.default.green(">")} Network: ${import_picocolors3.default.cyan(networkUrl)}`);
|
|
1571
1634
|
}
|
|
1572
1635
|
console.log();
|
|
1573
1636
|
resolve(server);
|
|
@@ -1576,7 +1639,7 @@ async function createServer(inlineConfig = {}) {
|
|
|
1576
1639
|
httpServer.on("error", (err) => {
|
|
1577
1640
|
if (err.code === "EADDRINUSE") {
|
|
1578
1641
|
currentPort++;
|
|
1579
|
-
console.log(
|
|
1642
|
+
console.log(import_picocolors3.default.yellow(`Port ${currentPort - 1} is in use, trying ${currentPort}...`));
|
|
1580
1643
|
httpServer.listen(currentPort, host);
|
|
1581
1644
|
} else {
|
|
1582
1645
|
reject(err);
|
|
@@ -1609,11 +1672,411 @@ function getNetworkAddress() {
|
|
|
1609
1672
|
}
|
|
1610
1673
|
return "localhost";
|
|
1611
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
|
+
}
|
|
1612
2072
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1613
2073
|
0 && (module.exports = {
|
|
1614
2074
|
build,
|
|
2075
|
+
buildElectron,
|
|
1615
2076
|
createServer,
|
|
1616
2077
|
defineConfig,
|
|
1617
|
-
|
|
2078
|
+
electronPlugin,
|
|
2079
|
+
resolveConfig,
|
|
2080
|
+
startElectronDev
|
|
1618
2081
|
});
|
|
1619
2082
|
//# sourceMappingURL=index.cjs.map
|