@nasti-toolchain/nasti 1.1.0 → 1.2.3
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/dist/cli.cjs +255 -91
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +246 -89
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +323 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +320 -162
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
-
}) : x)(function(x) {
|
|
6
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
3
|
var __esm = (fn, res) => function __init() {
|
|
10
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
5
|
};
|
|
@@ -97,6 +91,11 @@ function transformCode(filename, code, options = {}) {
|
|
|
97
91
|
} : void 0,
|
|
98
92
|
sourcemap: options.sourcemap ?? true
|
|
99
93
|
});
|
|
94
|
+
if (result.errors && result.errors.length > 0) {
|
|
95
|
+
const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
|
|
96
|
+
throw new Error(`OXC transform failed for ${filename}:
|
|
97
|
+
${msg}`);
|
|
98
|
+
}
|
|
100
99
|
return {
|
|
101
100
|
code: result.code,
|
|
102
101
|
map: result.map ? JSON.stringify(result.map) : null
|
|
@@ -112,17 +111,90 @@ var init_transformer = __esm({
|
|
|
112
111
|
}
|
|
113
112
|
});
|
|
114
113
|
|
|
114
|
+
// src/core/env.ts
|
|
115
|
+
import path6 from "path";
|
|
116
|
+
import fs5 from "fs";
|
|
117
|
+
function loadEnv(mode, root, prefixes) {
|
|
118
|
+
const envFiles = [
|
|
119
|
+
".env",
|
|
120
|
+
`.env.${mode}`,
|
|
121
|
+
".env.local",
|
|
122
|
+
`.env.${mode}.local`
|
|
123
|
+
];
|
|
124
|
+
const raw = {};
|
|
125
|
+
for (const file of envFiles) {
|
|
126
|
+
const filePath = path6.resolve(root, file);
|
|
127
|
+
if (!fs5.existsSync(filePath)) continue;
|
|
128
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
129
|
+
for (const line of content.split("\n")) {
|
|
130
|
+
const trimmed = line.trim();
|
|
131
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
132
|
+
const eqIdx = trimmed.indexOf("=");
|
|
133
|
+
if (eqIdx === -1) continue;
|
|
134
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
135
|
+
let value = trimmed.slice(eqIdx + 1).trim();
|
|
136
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
137
|
+
value = value.slice(1, -1);
|
|
138
|
+
}
|
|
139
|
+
raw[key] = value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const filtered = {};
|
|
143
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
144
|
+
if (prefixes.some((prefix) => key.startsWith(prefix))) {
|
|
145
|
+
filtered[key] = value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return filtered;
|
|
149
|
+
}
|
|
150
|
+
function buildEnvDefine(env, mode) {
|
|
151
|
+
const define = {};
|
|
152
|
+
for (const [key, value] of Object.entries(env)) {
|
|
153
|
+
define[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
154
|
+
}
|
|
155
|
+
define["import.meta.env.MODE"] = JSON.stringify(mode);
|
|
156
|
+
define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
|
|
157
|
+
define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
|
|
158
|
+
define["import.meta.env.SSR"] = "false";
|
|
159
|
+
return define;
|
|
160
|
+
}
|
|
161
|
+
function replaceEnvInCode(code, define) {
|
|
162
|
+
let result = code;
|
|
163
|
+
for (const [key, value] of Object.entries(define)) {
|
|
164
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
165
|
+
result = result.replace(new RegExp(escaped, "g"), value);
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
var init_env = __esm({
|
|
170
|
+
"src/core/env.ts"() {
|
|
171
|
+
"use strict";
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
115
175
|
// src/server/middleware.ts
|
|
116
176
|
var middleware_exports = {};
|
|
117
177
|
__export(middleware_exports, {
|
|
118
178
|
transformMiddleware: () => transformMiddleware,
|
|
119
179
|
transformRequest: () => transformRequest
|
|
120
180
|
});
|
|
121
|
-
import
|
|
122
|
-
import
|
|
181
|
+
import path8 from "path";
|
|
182
|
+
import fs7 from "fs";
|
|
183
|
+
import { createRequire as createRequire2 } from "module";
|
|
123
184
|
function transformMiddleware(ctx) {
|
|
124
185
|
return async (req, res, next) => {
|
|
125
186
|
const url = req.url ?? "/";
|
|
187
|
+
if (ctx.config.server.cors) {
|
|
188
|
+
const origin = req.headers.origin ?? "*";
|
|
189
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
190
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
|
|
191
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
192
|
+
if (req.method === "OPTIONS") {
|
|
193
|
+
res.statusCode = 204;
|
|
194
|
+
res.end();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
126
198
|
if (req.method !== "GET") return next();
|
|
127
199
|
if (url === "/@nasti/client") {
|
|
128
200
|
res.setHeader("Content-Type", "application/javascript");
|
|
@@ -145,10 +217,12 @@ function transformMiddleware(ctx) {
|
|
|
145
217
|
}
|
|
146
218
|
}
|
|
147
219
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
220
|
+
if (ctx.config.server.hmr !== false) {
|
|
221
|
+
processedHtml = processedHtml.replace(
|
|
222
|
+
"<head>",
|
|
223
|
+
'<head>\n <script type="module" src="/@nasti/client"></script>'
|
|
224
|
+
);
|
|
225
|
+
}
|
|
152
226
|
res.setHeader("Content-Type", "text/html");
|
|
153
227
|
res.end(processedHtml);
|
|
154
228
|
return;
|
|
@@ -181,10 +255,10 @@ async function transformRequest(url, ctx) {
|
|
|
181
255
|
return cached.transformResult;
|
|
182
256
|
}
|
|
183
257
|
const filePath = resolveUrlToFile(url, config.root);
|
|
184
|
-
if (!filePath || !
|
|
258
|
+
if (!filePath || !fs7.existsSync(filePath)) return null;
|
|
185
259
|
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
186
260
|
moduleGraph.registerModule(mod, filePath);
|
|
187
|
-
let code =
|
|
261
|
+
let code = fs7.readFileSync(filePath, "utf-8");
|
|
188
262
|
const pluginResult = await pluginContainer.transform(code, filePath);
|
|
189
263
|
if (pluginResult) {
|
|
190
264
|
code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
|
|
@@ -198,23 +272,31 @@ async function transformRequest(url, ctx) {
|
|
|
198
272
|
});
|
|
199
273
|
code = result.code;
|
|
200
274
|
}
|
|
275
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
276
|
+
const envDefine = buildEnvDefine(env, config.mode);
|
|
277
|
+
code = replaceEnvInCode(code, envDefine);
|
|
201
278
|
code = rewriteImports(code, config);
|
|
202
279
|
const transformResult = { code };
|
|
203
280
|
mod.transformResult = transformResult;
|
|
204
281
|
return transformResult;
|
|
205
282
|
}
|
|
206
|
-
function rewriteImports(code,
|
|
283
|
+
function rewriteImports(code, _config) {
|
|
207
284
|
return code.replace(
|
|
208
|
-
|
|
209
|
-
(match, specifier) => {
|
|
210
|
-
|
|
211
|
-
return `from "/@modules/${specifier}"`;
|
|
285
|
+
/\bfrom\s+(['"])([^'"./][^'"]*)\1/g,
|
|
286
|
+
(match, quote, specifier) => {
|
|
287
|
+
return `from ${quote}/@modules/${specifier}${quote}`;
|
|
212
288
|
}
|
|
213
289
|
).replace(
|
|
214
|
-
|
|
215
|
-
(
|
|
216
|
-
|
|
217
|
-
return `import
|
|
290
|
+
// 处理纯副作用导入: import 'bare-specifier'
|
|
291
|
+
/\bimport\s+(['"])([^'"./][^'"]*)\1/g,
|
|
292
|
+
(match, quote, specifier) => {
|
|
293
|
+
return `import ${quote}/@modules/${specifier}${quote}`;
|
|
294
|
+
}
|
|
295
|
+
).replace(
|
|
296
|
+
// 处理动态导入: import('bare-specifier')
|
|
297
|
+
/\bimport\s*\(\s*(['"])([^'"./][^'"]*)\1\s*\)/g,
|
|
298
|
+
(match, quote, specifier) => {
|
|
299
|
+
return `import(${quote}/@modules/${specifier}${quote})`;
|
|
218
300
|
}
|
|
219
301
|
);
|
|
220
302
|
}
|
|
@@ -223,14 +305,13 @@ function resolveUrlToFile(url, root) {
|
|
|
223
305
|
if (cleanUrl.startsWith("/@modules/")) {
|
|
224
306
|
const moduleName = cleanUrl.slice("/@modules/".length);
|
|
225
307
|
try {
|
|
226
|
-
const
|
|
227
|
-
const req = createRequire2(path7.resolve(root, "package.json"));
|
|
308
|
+
const req = createRequire2(path8.resolve(root, "package.json"));
|
|
228
309
|
return req.resolve(moduleName);
|
|
229
310
|
} catch {
|
|
230
311
|
return null;
|
|
231
312
|
}
|
|
232
313
|
}
|
|
233
|
-
return
|
|
314
|
+
return path8.resolve(root, cleanUrl.replace(/^\//, ""));
|
|
234
315
|
}
|
|
235
316
|
function isModuleRequest(url) {
|
|
236
317
|
const cleanUrl = url.split("?")[0];
|
|
@@ -292,7 +373,18 @@ function showErrorOverlay(err) {
|
|
|
292
373
|
const overlay = document.createElement('div');
|
|
293
374
|
overlay.id = 'nasti-error-overlay';
|
|
294
375
|
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;';
|
|
295
|
-
|
|
376
|
+
const title = document.createElement('h2');
|
|
377
|
+
title.style.color = '#ff5555';
|
|
378
|
+
title.textContent = 'Build Error';
|
|
379
|
+
const pre = document.createElement('pre');
|
|
380
|
+
pre.textContent = err.message + '\\n' + (err.stack || '');
|
|
381
|
+
const btn = document.createElement('button');
|
|
382
|
+
btn.style.cssText = 'margin-top:1rem;padding:0.5rem 1rem;cursor:pointer';
|
|
383
|
+
btn.textContent = 'Close';
|
|
384
|
+
btn.onclick = () => overlay.remove();
|
|
385
|
+
overlay.appendChild(title);
|
|
386
|
+
overlay.appendChild(pre);
|
|
387
|
+
overlay.appendChild(btn);
|
|
296
388
|
document.body.appendChild(overlay);
|
|
297
389
|
}
|
|
298
390
|
|
|
@@ -328,6 +420,7 @@ var init_middleware = __esm({
|
|
|
328
420
|
"use strict";
|
|
329
421
|
init_transformer();
|
|
330
422
|
init_html();
|
|
423
|
+
init_env();
|
|
331
424
|
}
|
|
332
425
|
});
|
|
333
426
|
|
|
@@ -375,6 +468,27 @@ var defaults = {
|
|
|
375
468
|
};
|
|
376
469
|
|
|
377
470
|
// src/config/index.ts
|
|
471
|
+
function loadTsconfigPaths(root) {
|
|
472
|
+
const tsconfigPath = path.resolve(root, "tsconfig.json");
|
|
473
|
+
if (!fs.existsSync(tsconfigPath)) return {};
|
|
474
|
+
try {
|
|
475
|
+
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
476
|
+
const stripped = content.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
477
|
+
const tsconfig = JSON.parse(stripped);
|
|
478
|
+
const paths = tsconfig?.compilerOptions?.paths ?? {};
|
|
479
|
+
const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? ".";
|
|
480
|
+
const alias = {};
|
|
481
|
+
for (const [pattern, targets] of Object.entries(paths)) {
|
|
482
|
+
if (!targets.length) continue;
|
|
483
|
+
const cleanKey = pattern.replace(/\/\*$/, "");
|
|
484
|
+
const cleanTarget = targets[0].replace(/\/\*$/, "");
|
|
485
|
+
alias[cleanKey] = path.resolve(root, baseUrl, cleanTarget);
|
|
486
|
+
}
|
|
487
|
+
return alias;
|
|
488
|
+
} catch {
|
|
489
|
+
return {};
|
|
490
|
+
}
|
|
491
|
+
}
|
|
378
492
|
function defineConfig(config) {
|
|
379
493
|
return config;
|
|
380
494
|
}
|
|
@@ -426,11 +540,6 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
426
540
|
if (result) Object.assign(merged, result);
|
|
427
541
|
}
|
|
428
542
|
}
|
|
429
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
430
|
-
if (!p.apply) return true;
|
|
431
|
-
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
432
|
-
return p.apply === command;
|
|
433
|
-
});
|
|
434
543
|
const resolved = {
|
|
435
544
|
root,
|
|
436
545
|
base: merged.base ?? defaults.base,
|
|
@@ -438,17 +547,24 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
438
547
|
framework: merged.framework ?? defaults.framework,
|
|
439
548
|
command,
|
|
440
549
|
resolve: {
|
|
441
|
-
|
|
550
|
+
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
551
|
+
alias: { ...loadTsconfigPaths(root), ...defaults.resolve.alias, ...merged.resolve?.alias },
|
|
442
552
|
extensions: merged.resolve?.extensions ?? defaults.resolve.extensions,
|
|
443
553
|
conditions: merged.resolve?.conditions ?? defaults.resolve.conditions,
|
|
444
554
|
mainFields: merged.resolve?.mainFields ?? defaults.resolve.mainFields
|
|
445
555
|
},
|
|
446
|
-
plugins:
|
|
556
|
+
plugins: [],
|
|
447
557
|
server: { ...defaults.server, ...merged.server },
|
|
448
558
|
build: { ...defaults.build, ...merged.build },
|
|
449
559
|
envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
|
|
450
560
|
logLevel: merged.logLevel ?? defaults.logLevel
|
|
451
561
|
};
|
|
562
|
+
const filteredPlugins = rawPlugins.filter((p) => {
|
|
563
|
+
if (!p.apply) return true;
|
|
564
|
+
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
565
|
+
return p.apply === command;
|
|
566
|
+
});
|
|
567
|
+
resolved.plugins = filteredPlugins;
|
|
452
568
|
for (const plugin of resolved.plugins) {
|
|
453
569
|
if (plugin.configResolved) {
|
|
454
570
|
await plugin.configResolved(resolved);
|
|
@@ -473,8 +589,8 @@ function deepMerge(target, source) {
|
|
|
473
589
|
}
|
|
474
590
|
|
|
475
591
|
// src/build/index.ts
|
|
476
|
-
import
|
|
477
|
-
import
|
|
592
|
+
import path7 from "path";
|
|
593
|
+
import fs6 from "fs";
|
|
478
594
|
import { rolldown } from "rolldown";
|
|
479
595
|
|
|
480
596
|
// src/plugins/resolve.ts
|
|
@@ -520,10 +636,12 @@ function resolvePlugin(config) {
|
|
|
520
636
|
return null;
|
|
521
637
|
},
|
|
522
638
|
load(id) {
|
|
523
|
-
if (fs2.existsSync(id))
|
|
524
|
-
|
|
639
|
+
if (!fs2.existsSync(id)) return null;
|
|
640
|
+
if (id.endsWith(".json")) {
|
|
641
|
+
const content = fs2.readFileSync(id, "utf-8");
|
|
642
|
+
return `export default ${content}`;
|
|
525
643
|
}
|
|
526
|
-
return
|
|
644
|
+
return fs2.readFileSync(id, "utf-8");
|
|
527
645
|
}
|
|
528
646
|
};
|
|
529
647
|
}
|
|
@@ -559,13 +677,17 @@ function cssPlugin(config) {
|
|
|
559
677
|
},
|
|
560
678
|
transform(code, id) {
|
|
561
679
|
if (!id.endsWith(".css")) return null;
|
|
680
|
+
const rewritten = rewriteCssUrls(code, id, config.root);
|
|
562
681
|
if (config.command === "serve") {
|
|
563
|
-
const escaped = JSON.stringify(
|
|
682
|
+
const escaped = JSON.stringify(rewritten);
|
|
564
683
|
return {
|
|
565
684
|
code: `
|
|
566
685
|
const css = ${escaped};
|
|
686
|
+
const __nasti_css_id__ = ${JSON.stringify(id)};
|
|
687
|
+
const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
|
|
688
|
+
if (__nasti_existing__) __nasti_existing__.remove();
|
|
567
689
|
const style = document.createElement('style');
|
|
568
|
-
style.setAttribute('data-nasti-css',
|
|
690
|
+
style.setAttribute('data-nasti-css', __nasti_css_id__);
|
|
569
691
|
style.textContent = css;
|
|
570
692
|
document.head.appendChild(style);
|
|
571
693
|
|
|
@@ -581,10 +703,20 @@ export default css;
|
|
|
581
703
|
`
|
|
582
704
|
};
|
|
583
705
|
}
|
|
584
|
-
return null;
|
|
706
|
+
return rewritten !== code ? { code: rewritten } : null;
|
|
585
707
|
}
|
|
586
708
|
};
|
|
587
709
|
}
|
|
710
|
+
function rewriteCssUrls(css, from, root) {
|
|
711
|
+
return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
|
|
712
|
+
if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
|
|
713
|
+
return match;
|
|
714
|
+
}
|
|
715
|
+
const resolved = path3.resolve(path3.dirname(from), url);
|
|
716
|
+
const relative = "/" + path3.relative(root, resolved);
|
|
717
|
+
return `url(${relative})`;
|
|
718
|
+
});
|
|
719
|
+
}
|
|
588
720
|
|
|
589
721
|
// src/plugins/assets.ts
|
|
590
722
|
import path4 from "path";
|
|
@@ -653,6 +785,123 @@ function assetsPlugin(config) {
|
|
|
653
785
|
// src/build/index.ts
|
|
654
786
|
init_html();
|
|
655
787
|
init_transformer();
|
|
788
|
+
init_env();
|
|
789
|
+
|
|
790
|
+
// src/core/plugin-container.ts
|
|
791
|
+
var PluginContainer = class {
|
|
792
|
+
plugins;
|
|
793
|
+
config;
|
|
794
|
+
ctx;
|
|
795
|
+
emittedFiles = /* @__PURE__ */ new Map();
|
|
796
|
+
constructor(config) {
|
|
797
|
+
this.config = config;
|
|
798
|
+
this.plugins = sortPlugins(config.plugins);
|
|
799
|
+
this.ctx = this.createContext();
|
|
800
|
+
}
|
|
801
|
+
createContext() {
|
|
802
|
+
const container = this;
|
|
803
|
+
return {
|
|
804
|
+
async resolve(source, importer) {
|
|
805
|
+
return container.resolveId(source, importer);
|
|
806
|
+
},
|
|
807
|
+
emitFile(file) {
|
|
808
|
+
const fileName = file.fileName ?? file.name ?? `asset-${container.emittedFiles.size}`;
|
|
809
|
+
const id = `emitted:${fileName}`;
|
|
810
|
+
container.emittedFiles.set(id, {
|
|
811
|
+
fileName,
|
|
812
|
+
source: file.source ?? ""
|
|
813
|
+
});
|
|
814
|
+
return id;
|
|
815
|
+
},
|
|
816
|
+
getModuleInfo(_id) {
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
/** 返回所有通过 emitFile() 输出的文件 */
|
|
822
|
+
getEmittedFiles() {
|
|
823
|
+
return Array.from(this.emittedFiles.values());
|
|
824
|
+
}
|
|
825
|
+
async buildStart() {
|
|
826
|
+
for (const plugin of this.plugins) {
|
|
827
|
+
if (plugin.buildStart) {
|
|
828
|
+
await plugin.buildStart.call(this.ctx);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
async buildEnd(error) {
|
|
833
|
+
for (const plugin of this.plugins) {
|
|
834
|
+
if (plugin.buildEnd) {
|
|
835
|
+
await plugin.buildEnd.call(this.ctx, error);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
async resolveId(source, importer, options = {}) {
|
|
840
|
+
for (const plugin of this.plugins) {
|
|
841
|
+
if (!plugin.resolveId) continue;
|
|
842
|
+
const result = await plugin.resolveId.call(
|
|
843
|
+
this.ctx,
|
|
844
|
+
source,
|
|
845
|
+
importer ?? void 0,
|
|
846
|
+
{ isEntry: options.isEntry ?? false, ssr: false }
|
|
847
|
+
);
|
|
848
|
+
if (result != null) return result;
|
|
849
|
+
}
|
|
850
|
+
return null;
|
|
851
|
+
}
|
|
852
|
+
async load(id) {
|
|
853
|
+
for (const plugin of this.plugins) {
|
|
854
|
+
if (!plugin.load) continue;
|
|
855
|
+
const result = await plugin.load.call(this.ctx, id);
|
|
856
|
+
if (result != null) return result;
|
|
857
|
+
}
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
860
|
+
async transform(code, id) {
|
|
861
|
+
let currentCode = code;
|
|
862
|
+
for (const plugin of this.plugins) {
|
|
863
|
+
if (!plugin.transform) continue;
|
|
864
|
+
const result = await plugin.transform.call(this.ctx, currentCode, id);
|
|
865
|
+
if (result == null) continue;
|
|
866
|
+
if (typeof result === "string") {
|
|
867
|
+
currentCode = result;
|
|
868
|
+
} else {
|
|
869
|
+
currentCode = result.code;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return currentCode === code ? null : { code: currentCode };
|
|
873
|
+
}
|
|
874
|
+
/** 完整的模块处理管道: resolveId → load → transform */
|
|
875
|
+
async processModule(source, importer) {
|
|
876
|
+
const resolveResult = await this.resolveId(source, importer, {
|
|
877
|
+
isEntry: !importer
|
|
878
|
+
});
|
|
879
|
+
if (resolveResult == null) return null;
|
|
880
|
+
const id = typeof resolveResult === "string" ? resolveResult : resolveResult.id;
|
|
881
|
+
const loadResult = await this.load(id);
|
|
882
|
+
if (loadResult == null) return null;
|
|
883
|
+
const loadedCode = typeof loadResult === "string" ? loadResult : loadResult.code;
|
|
884
|
+
const transformResult = await this.transform(loadedCode, id);
|
|
885
|
+
const finalCode = transformResult == null ? loadedCode : typeof transformResult === "string" ? transformResult : transformResult.code;
|
|
886
|
+
return { id, code: finalCode };
|
|
887
|
+
}
|
|
888
|
+
getPlugins() {
|
|
889
|
+
return this.plugins;
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
function sortPlugins(plugins) {
|
|
893
|
+
const pre = [];
|
|
894
|
+
const normal = [];
|
|
895
|
+
const post = [];
|
|
896
|
+
for (const plugin of plugins) {
|
|
897
|
+
if (plugin.enforce === "pre") pre.push(plugin);
|
|
898
|
+
else if (plugin.enforce === "post") post.push(plugin);
|
|
899
|
+
else normal.push(plugin);
|
|
900
|
+
}
|
|
901
|
+
return [...pre, ...normal, ...post];
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// src/build/index.ts
|
|
656
905
|
import pc from "picocolors";
|
|
657
906
|
async function build(inlineConfig = {}) {
|
|
658
907
|
const config = await resolveConfig(inlineConfig, "build");
|
|
@@ -660,11 +909,11 @@ async function build(inlineConfig = {}) {
|
|
|
660
909
|
console.log(pc.cyan("\n\u{1F528} nasti build") + pc.dim(` v${process.env.npm_package_version ?? "0.0.1"}`));
|
|
661
910
|
console.log(pc.dim(` root: ${config.root}`));
|
|
662
911
|
console.log(pc.dim(` mode: ${config.mode}`));
|
|
663
|
-
const outDir =
|
|
664
|
-
if (config.build.emptyOutDir &&
|
|
665
|
-
|
|
912
|
+
const outDir = path7.resolve(config.root, config.build.outDir);
|
|
913
|
+
if (config.build.emptyOutDir && fs6.existsSync(outDir)) {
|
|
914
|
+
fs6.rmSync(outDir, { recursive: true, force: true });
|
|
666
915
|
}
|
|
667
|
-
|
|
916
|
+
fs6.mkdirSync(outDir, { recursive: true });
|
|
668
917
|
const html = await readHtmlFile(config.root);
|
|
669
918
|
let entryPoints = [];
|
|
670
919
|
if (html) {
|
|
@@ -672,15 +921,15 @@ async function build(inlineConfig = {}) {
|
|
|
672
921
|
for (const match of scriptMatches) {
|
|
673
922
|
const src = match[1];
|
|
674
923
|
if (src && !src.startsWith("http")) {
|
|
675
|
-
entryPoints.push(
|
|
924
|
+
entryPoints.push(path7.resolve(config.root, src.replace(/^\//, "")));
|
|
676
925
|
}
|
|
677
926
|
}
|
|
678
927
|
}
|
|
679
928
|
if (entryPoints.length === 0) {
|
|
680
929
|
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
681
930
|
for (const entry of fallbackEntries) {
|
|
682
|
-
const fullPath =
|
|
683
|
-
if (
|
|
931
|
+
const fullPath = path7.resolve(config.root, entry);
|
|
932
|
+
if (fs6.existsSync(fullPath)) {
|
|
684
933
|
entryPoints.push(fullPath);
|
|
685
934
|
break;
|
|
686
935
|
}
|
|
@@ -695,6 +944,8 @@ async function build(inlineConfig = {}) {
|
|
|
695
944
|
assetsPlugin(config)
|
|
696
945
|
];
|
|
697
946
|
const allPlugins = [...builtinPlugins, ...config.plugins];
|
|
947
|
+
const pluginContainer = new PluginContainer(config);
|
|
948
|
+
await pluginContainer.buildStart();
|
|
698
949
|
const oxcTransformPlugin = {
|
|
699
950
|
name: "nasti:oxc-transform",
|
|
700
951
|
transform(code, id) {
|
|
@@ -707,8 +958,11 @@ async function build(inlineConfig = {}) {
|
|
|
707
958
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
708
959
|
}
|
|
709
960
|
};
|
|
961
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
962
|
+
const envDefine = buildEnvDefine(env, config.mode);
|
|
710
963
|
const bundle = await rolldown({
|
|
711
964
|
input: entryPoints,
|
|
965
|
+
define: envDefine,
|
|
712
966
|
plugins: [
|
|
713
967
|
oxcTransformPlugin,
|
|
714
968
|
// 转换 Nasti 插件为 Rolldown 插件格式
|
|
@@ -727,11 +981,18 @@ async function build(inlineConfig = {}) {
|
|
|
727
981
|
dir: outDir,
|
|
728
982
|
format: "esm",
|
|
729
983
|
sourcemap: !!config.build.sourcemap,
|
|
984
|
+
minify: !!config.build.minify,
|
|
730
985
|
entryFileNames: "assets/[name].[hash].js",
|
|
731
986
|
chunkFileNames: "assets/[name].[hash].js",
|
|
732
987
|
assetFileNames: "assets/[name].[hash][extname]"
|
|
733
988
|
});
|
|
734
989
|
await bundle.close();
|
|
990
|
+
await pluginContainer.buildEnd();
|
|
991
|
+
for (const ef of pluginContainer.getEmittedFiles()) {
|
|
992
|
+
const dest = path7.resolve(outDir, ef.fileName);
|
|
993
|
+
fs6.mkdirSync(path7.dirname(dest), { recursive: true });
|
|
994
|
+
fs6.writeFileSync(dest, ef.source);
|
|
995
|
+
}
|
|
735
996
|
if (html) {
|
|
736
997
|
let processedHtml = html;
|
|
737
998
|
const htmlPlugin_ = htmlPlugin(config);
|
|
@@ -746,15 +1007,15 @@ async function build(inlineConfig = {}) {
|
|
|
746
1007
|
}
|
|
747
1008
|
}
|
|
748
1009
|
for (const chunk of output) {
|
|
749
|
-
if (chunk.type === "chunk" && chunk.isEntry) {
|
|
750
|
-
const originalEntry =
|
|
1010
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
1011
|
+
const originalEntry = path7.relative(config.root, chunk.facadeModuleId);
|
|
751
1012
|
processedHtml = processedHtml.replace(
|
|
752
1013
|
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
753
1014
|
`$1${config.base}${chunk.fileName}$3`
|
|
754
1015
|
);
|
|
755
1016
|
}
|
|
756
1017
|
}
|
|
757
|
-
|
|
1018
|
+
fs6.writeFileSync(path7.resolve(outDir, "index.html"), processedHtml);
|
|
758
1019
|
}
|
|
759
1020
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
760
1021
|
const totalSize = output.reduce((sum, chunk) => {
|
|
@@ -779,115 +1040,13 @@ function escapeRegExp(string) {
|
|
|
779
1040
|
|
|
780
1041
|
// src/server/index.ts
|
|
781
1042
|
import http from "http";
|
|
782
|
-
import
|
|
1043
|
+
import path10 from "path";
|
|
1044
|
+
import os from "os";
|
|
783
1045
|
import connect from "connect";
|
|
784
1046
|
import sirv from "sirv";
|
|
785
1047
|
import { watch } from "chokidar";
|
|
786
1048
|
import pc2 from "picocolors";
|
|
787
1049
|
|
|
788
|
-
// src/core/plugin-container.ts
|
|
789
|
-
var PluginContainer = class {
|
|
790
|
-
plugins;
|
|
791
|
-
config;
|
|
792
|
-
ctx;
|
|
793
|
-
constructor(config) {
|
|
794
|
-
this.config = config;
|
|
795
|
-
this.plugins = sortPlugins(config.plugins);
|
|
796
|
-
this.ctx = this.createContext();
|
|
797
|
-
}
|
|
798
|
-
createContext() {
|
|
799
|
-
const container = this;
|
|
800
|
-
return {
|
|
801
|
-
async resolve(source, importer) {
|
|
802
|
-
return container.resolveId(source, importer);
|
|
803
|
-
},
|
|
804
|
-
emitFile(_file) {
|
|
805
|
-
return "";
|
|
806
|
-
},
|
|
807
|
-
getModuleInfo(_id) {
|
|
808
|
-
return null;
|
|
809
|
-
}
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
async buildStart() {
|
|
813
|
-
for (const plugin of this.plugins) {
|
|
814
|
-
if (plugin.buildStart) {
|
|
815
|
-
await plugin.buildStart.call(this.ctx);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
async buildEnd(error) {
|
|
820
|
-
for (const plugin of this.plugins) {
|
|
821
|
-
if (plugin.buildEnd) {
|
|
822
|
-
await plugin.buildEnd.call(this.ctx, error);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
async resolveId(source, importer, options = {}) {
|
|
827
|
-
for (const plugin of this.plugins) {
|
|
828
|
-
if (!plugin.resolveId) continue;
|
|
829
|
-
const result = await plugin.resolveId.call(
|
|
830
|
-
this.ctx,
|
|
831
|
-
source,
|
|
832
|
-
importer ?? void 0,
|
|
833
|
-
{ isEntry: options.isEntry ?? false, ssr: false }
|
|
834
|
-
);
|
|
835
|
-
if (result != null) return result;
|
|
836
|
-
}
|
|
837
|
-
return null;
|
|
838
|
-
}
|
|
839
|
-
async load(id) {
|
|
840
|
-
for (const plugin of this.plugins) {
|
|
841
|
-
if (!plugin.load) continue;
|
|
842
|
-
const result = await plugin.load.call(this.ctx, id);
|
|
843
|
-
if (result != null) return result;
|
|
844
|
-
}
|
|
845
|
-
return null;
|
|
846
|
-
}
|
|
847
|
-
async transform(code, id) {
|
|
848
|
-
let currentCode = code;
|
|
849
|
-
for (const plugin of this.plugins) {
|
|
850
|
-
if (!plugin.transform) continue;
|
|
851
|
-
const result = await plugin.transform.call(this.ctx, currentCode, id);
|
|
852
|
-
if (result == null) continue;
|
|
853
|
-
if (typeof result === "string") {
|
|
854
|
-
currentCode = result;
|
|
855
|
-
} else {
|
|
856
|
-
currentCode = result.code;
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
return currentCode === code ? null : { code: currentCode };
|
|
860
|
-
}
|
|
861
|
-
/** 完整的模块处理管道: resolveId → load → transform */
|
|
862
|
-
async processModule(source, importer) {
|
|
863
|
-
const resolveResult = await this.resolveId(source, importer, {
|
|
864
|
-
isEntry: !importer
|
|
865
|
-
});
|
|
866
|
-
if (resolveResult == null) return null;
|
|
867
|
-
const id = typeof resolveResult === "string" ? resolveResult : resolveResult.id;
|
|
868
|
-
const loadResult = await this.load(id);
|
|
869
|
-
if (loadResult == null) return null;
|
|
870
|
-
const loadedCode = typeof loadResult === "string" ? loadResult : loadResult.code;
|
|
871
|
-
const transformResult = await this.transform(loadedCode, id);
|
|
872
|
-
const finalCode = transformResult == null ? loadedCode : typeof transformResult === "string" ? transformResult : transformResult.code;
|
|
873
|
-
return { id, code: finalCode };
|
|
874
|
-
}
|
|
875
|
-
getPlugins() {
|
|
876
|
-
return this.plugins;
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
function sortPlugins(plugins) {
|
|
880
|
-
const pre = [];
|
|
881
|
-
const normal = [];
|
|
882
|
-
const post = [];
|
|
883
|
-
for (const plugin of plugins) {
|
|
884
|
-
if (plugin.enforce === "pre") pre.push(plugin);
|
|
885
|
-
else if (plugin.enforce === "post") post.push(plugin);
|
|
886
|
-
else normal.push(plugin);
|
|
887
|
-
}
|
|
888
|
-
return [...pre, ...normal, ...post];
|
|
889
|
-
}
|
|
890
|
-
|
|
891
1050
|
// src/core/module-graph.ts
|
|
892
1051
|
var ModuleGraph = class {
|
|
893
1052
|
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
@@ -1037,11 +1196,11 @@ function createWebSocketServer(server) {
|
|
|
1037
1196
|
init_middleware();
|
|
1038
1197
|
|
|
1039
1198
|
// src/server/hmr.ts
|
|
1040
|
-
import
|
|
1041
|
-
import
|
|
1199
|
+
import path9 from "path";
|
|
1200
|
+
import fs8 from "fs";
|
|
1042
1201
|
async function handleFileChange(file, server) {
|
|
1043
1202
|
const { moduleGraph, ws, config } = server;
|
|
1044
|
-
const relativePath = "/" +
|
|
1203
|
+
const relativePath = "/" + path9.relative(config.root, file);
|
|
1045
1204
|
const mods = moduleGraph.getModulesByFile(file);
|
|
1046
1205
|
if (!mods || mods.size === 0) {
|
|
1047
1206
|
return;
|
|
@@ -1054,7 +1213,7 @@ async function handleFileChange(file, server) {
|
|
|
1054
1213
|
file,
|
|
1055
1214
|
timestamp,
|
|
1056
1215
|
modules: [mod],
|
|
1057
|
-
read: () =>
|
|
1216
|
+
read: () => fs8.readFileSync(file, "utf-8"),
|
|
1058
1217
|
server
|
|
1059
1218
|
};
|
|
1060
1219
|
let affectedModules = [mod];
|
|
@@ -1107,7 +1266,7 @@ async function createServer(inlineConfig = {}) {
|
|
|
1107
1266
|
pluginContainer,
|
|
1108
1267
|
moduleGraph
|
|
1109
1268
|
}));
|
|
1110
|
-
const publicDir =
|
|
1269
|
+
const publicDir = path10.resolve(config.root, "public");
|
|
1111
1270
|
app.use(sirv(publicDir, { dev: true, etag: true }));
|
|
1112
1271
|
app.use(sirv(config.root, { dev: true, etag: true }));
|
|
1113
1272
|
const httpServer = http.createServer(app);
|
|
@@ -1184,7 +1343,6 @@ async function createServer(inlineConfig = {}) {
|
|
|
1184
1343
|
return server;
|
|
1185
1344
|
}
|
|
1186
1345
|
function getNetworkAddress() {
|
|
1187
|
-
const os = __require("os");
|
|
1188
1346
|
const interfaces = os.networkInterfaces();
|
|
1189
1347
|
for (const name of Object.keys(interfaces)) {
|
|
1190
1348
|
for (const iface of interfaces[name] ?? []) {
|