@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/cli.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
|
};
|
|
@@ -62,6 +56,27 @@ var init_defaults = __esm({
|
|
|
62
56
|
import { pathToFileURL } from "url";
|
|
63
57
|
import path from "path";
|
|
64
58
|
import fs from "fs";
|
|
59
|
+
function loadTsconfigPaths(root) {
|
|
60
|
+
const tsconfigPath = path.resolve(root, "tsconfig.json");
|
|
61
|
+
if (!fs.existsSync(tsconfigPath)) return {};
|
|
62
|
+
try {
|
|
63
|
+
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
64
|
+
const stripped = content.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
65
|
+
const tsconfig = JSON.parse(stripped);
|
|
66
|
+
const paths = tsconfig?.compilerOptions?.paths ?? {};
|
|
67
|
+
const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? ".";
|
|
68
|
+
const alias = {};
|
|
69
|
+
for (const [pattern, targets] of Object.entries(paths)) {
|
|
70
|
+
if (!targets.length) continue;
|
|
71
|
+
const cleanKey = pattern.replace(/\/\*$/, "");
|
|
72
|
+
const cleanTarget = targets[0].replace(/\/\*$/, "");
|
|
73
|
+
alias[cleanKey] = path.resolve(root, baseUrl, cleanTarget);
|
|
74
|
+
}
|
|
75
|
+
return alias;
|
|
76
|
+
} catch {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
65
80
|
async function loadConfigFromFile(root) {
|
|
66
81
|
for (const file of CONFIG_FILES) {
|
|
67
82
|
const filePath = path.resolve(root, file);
|
|
@@ -104,11 +119,6 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
104
119
|
if (result) Object.assign(merged, result);
|
|
105
120
|
}
|
|
106
121
|
}
|
|
107
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
108
|
-
if (!p.apply) return true;
|
|
109
|
-
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
110
|
-
return p.apply === command;
|
|
111
|
-
});
|
|
112
122
|
const resolved = {
|
|
113
123
|
root,
|
|
114
124
|
base: merged.base ?? defaults.base,
|
|
@@ -116,17 +126,24 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
116
126
|
framework: merged.framework ?? defaults.framework,
|
|
117
127
|
command,
|
|
118
128
|
resolve: {
|
|
119
|
-
|
|
129
|
+
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
130
|
+
alias: { ...loadTsconfigPaths(root), ...defaults.resolve.alias, ...merged.resolve?.alias },
|
|
120
131
|
extensions: merged.resolve?.extensions ?? defaults.resolve.extensions,
|
|
121
132
|
conditions: merged.resolve?.conditions ?? defaults.resolve.conditions,
|
|
122
133
|
mainFields: merged.resolve?.mainFields ?? defaults.resolve.mainFields
|
|
123
134
|
},
|
|
124
|
-
plugins:
|
|
135
|
+
plugins: [],
|
|
125
136
|
server: { ...defaults.server, ...merged.server },
|
|
126
137
|
build: { ...defaults.build, ...merged.build },
|
|
127
138
|
envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
|
|
128
139
|
logLevel: merged.logLevel ?? defaults.logLevel
|
|
129
140
|
};
|
|
141
|
+
const filteredPlugins = rawPlugins.filter((p) => {
|
|
142
|
+
if (!p.apply) return true;
|
|
143
|
+
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
144
|
+
return p.apply === command;
|
|
145
|
+
});
|
|
146
|
+
resolved.plugins = filteredPlugins;
|
|
130
147
|
for (const plugin of resolved.plugins) {
|
|
131
148
|
if (plugin.configResolved) {
|
|
132
149
|
await plugin.configResolved(resolved);
|
|
@@ -183,6 +200,7 @@ var init_plugin_container = __esm({
|
|
|
183
200
|
plugins;
|
|
184
201
|
config;
|
|
185
202
|
ctx;
|
|
203
|
+
emittedFiles = /* @__PURE__ */ new Map();
|
|
186
204
|
constructor(config) {
|
|
187
205
|
this.config = config;
|
|
188
206
|
this.plugins = sortPlugins(config.plugins);
|
|
@@ -194,14 +212,24 @@ var init_plugin_container = __esm({
|
|
|
194
212
|
async resolve(source, importer) {
|
|
195
213
|
return container.resolveId(source, importer);
|
|
196
214
|
},
|
|
197
|
-
emitFile(
|
|
198
|
-
|
|
215
|
+
emitFile(file) {
|
|
216
|
+
const fileName = file.fileName ?? file.name ?? `asset-${container.emittedFiles.size}`;
|
|
217
|
+
const id = `emitted:${fileName}`;
|
|
218
|
+
container.emittedFiles.set(id, {
|
|
219
|
+
fileName,
|
|
220
|
+
source: file.source ?? ""
|
|
221
|
+
});
|
|
222
|
+
return id;
|
|
199
223
|
},
|
|
200
224
|
getModuleInfo(_id) {
|
|
201
225
|
return null;
|
|
202
226
|
}
|
|
203
227
|
};
|
|
204
228
|
}
|
|
229
|
+
/** 返回所有通过 emitFile() 输出的文件 */
|
|
230
|
+
getEmittedFiles() {
|
|
231
|
+
return Array.from(this.emittedFiles.values());
|
|
232
|
+
}
|
|
205
233
|
async buildStart() {
|
|
206
234
|
for (const plugin of this.plugins) {
|
|
207
235
|
if (plugin.buildStart) {
|
|
@@ -445,6 +473,11 @@ function transformCode(filename, code, options = {}) {
|
|
|
445
473
|
} : void 0,
|
|
446
474
|
sourcemap: options.sourcemap ?? true
|
|
447
475
|
});
|
|
476
|
+
if (result.errors && result.errors.length > 0) {
|
|
477
|
+
const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
|
|
478
|
+
throw new Error(`OXC transform failed for ${filename}:
|
|
479
|
+
${msg}`);
|
|
480
|
+
}
|
|
448
481
|
return {
|
|
449
482
|
code: result.code,
|
|
450
483
|
map: result.map ? JSON.stringify(result.map) : null
|
|
@@ -526,17 +559,90 @@ var init_html = __esm({
|
|
|
526
559
|
}
|
|
527
560
|
});
|
|
528
561
|
|
|
562
|
+
// src/core/env.ts
|
|
563
|
+
import path3 from "path";
|
|
564
|
+
import fs3 from "fs";
|
|
565
|
+
function loadEnv(mode, root, prefixes) {
|
|
566
|
+
const envFiles = [
|
|
567
|
+
".env",
|
|
568
|
+
`.env.${mode}`,
|
|
569
|
+
".env.local",
|
|
570
|
+
`.env.${mode}.local`
|
|
571
|
+
];
|
|
572
|
+
const raw = {};
|
|
573
|
+
for (const file of envFiles) {
|
|
574
|
+
const filePath = path3.resolve(root, file);
|
|
575
|
+
if (!fs3.existsSync(filePath)) continue;
|
|
576
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
577
|
+
for (const line of content.split("\n")) {
|
|
578
|
+
const trimmed = line.trim();
|
|
579
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
580
|
+
const eqIdx = trimmed.indexOf("=");
|
|
581
|
+
if (eqIdx === -1) continue;
|
|
582
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
583
|
+
let value = trimmed.slice(eqIdx + 1).trim();
|
|
584
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
585
|
+
value = value.slice(1, -1);
|
|
586
|
+
}
|
|
587
|
+
raw[key] = value;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const filtered = {};
|
|
591
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
592
|
+
if (prefixes.some((prefix) => key.startsWith(prefix))) {
|
|
593
|
+
filtered[key] = value;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return filtered;
|
|
597
|
+
}
|
|
598
|
+
function buildEnvDefine(env, mode) {
|
|
599
|
+
const define = {};
|
|
600
|
+
for (const [key, value] of Object.entries(env)) {
|
|
601
|
+
define[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
602
|
+
}
|
|
603
|
+
define["import.meta.env.MODE"] = JSON.stringify(mode);
|
|
604
|
+
define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
|
|
605
|
+
define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
|
|
606
|
+
define["import.meta.env.SSR"] = "false";
|
|
607
|
+
return define;
|
|
608
|
+
}
|
|
609
|
+
function replaceEnvInCode(code, define) {
|
|
610
|
+
let result = code;
|
|
611
|
+
for (const [key, value] of Object.entries(define)) {
|
|
612
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
613
|
+
result = result.replace(new RegExp(escaped, "g"), value);
|
|
614
|
+
}
|
|
615
|
+
return result;
|
|
616
|
+
}
|
|
617
|
+
var init_env = __esm({
|
|
618
|
+
"src/core/env.ts"() {
|
|
619
|
+
"use strict";
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
|
|
529
623
|
// src/server/middleware.ts
|
|
530
624
|
var middleware_exports = {};
|
|
531
625
|
__export(middleware_exports, {
|
|
532
626
|
transformMiddleware: () => transformMiddleware,
|
|
533
627
|
transformRequest: () => transformRequest
|
|
534
628
|
});
|
|
535
|
-
import
|
|
536
|
-
import
|
|
629
|
+
import path4 from "path";
|
|
630
|
+
import fs4 from "fs";
|
|
631
|
+
import { createRequire } from "module";
|
|
537
632
|
function transformMiddleware(ctx) {
|
|
538
633
|
return async (req, res, next) => {
|
|
539
634
|
const url = req.url ?? "/";
|
|
635
|
+
if (ctx.config.server.cors) {
|
|
636
|
+
const origin = req.headers.origin ?? "*";
|
|
637
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
638
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
|
|
639
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
640
|
+
if (req.method === "OPTIONS") {
|
|
641
|
+
res.statusCode = 204;
|
|
642
|
+
res.end();
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
540
646
|
if (req.method !== "GET") return next();
|
|
541
647
|
if (url === "/@nasti/client") {
|
|
542
648
|
res.setHeader("Content-Type", "application/javascript");
|
|
@@ -559,10 +665,12 @@ function transformMiddleware(ctx) {
|
|
|
559
665
|
}
|
|
560
666
|
}
|
|
561
667
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
668
|
+
if (ctx.config.server.hmr !== false) {
|
|
669
|
+
processedHtml = processedHtml.replace(
|
|
670
|
+
"<head>",
|
|
671
|
+
'<head>\n <script type="module" src="/@nasti/client"></script>'
|
|
672
|
+
);
|
|
673
|
+
}
|
|
566
674
|
res.setHeader("Content-Type", "text/html");
|
|
567
675
|
res.end(processedHtml);
|
|
568
676
|
return;
|
|
@@ -595,10 +703,10 @@ async function transformRequest(url, ctx) {
|
|
|
595
703
|
return cached.transformResult;
|
|
596
704
|
}
|
|
597
705
|
const filePath = resolveUrlToFile(url, config.root);
|
|
598
|
-
if (!filePath || !
|
|
706
|
+
if (!filePath || !fs4.existsSync(filePath)) return null;
|
|
599
707
|
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
600
708
|
moduleGraph.registerModule(mod, filePath);
|
|
601
|
-
let code =
|
|
709
|
+
let code = fs4.readFileSync(filePath, "utf-8");
|
|
602
710
|
const pluginResult = await pluginContainer.transform(code, filePath);
|
|
603
711
|
if (pluginResult) {
|
|
604
712
|
code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
|
|
@@ -612,23 +720,31 @@ async function transformRequest(url, ctx) {
|
|
|
612
720
|
});
|
|
613
721
|
code = result.code;
|
|
614
722
|
}
|
|
723
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
724
|
+
const envDefine = buildEnvDefine(env, config.mode);
|
|
725
|
+
code = replaceEnvInCode(code, envDefine);
|
|
615
726
|
code = rewriteImports(code, config);
|
|
616
727
|
const transformResult = { code };
|
|
617
728
|
mod.transformResult = transformResult;
|
|
618
729
|
return transformResult;
|
|
619
730
|
}
|
|
620
|
-
function rewriteImports(code,
|
|
731
|
+
function rewriteImports(code, _config) {
|
|
621
732
|
return code.replace(
|
|
622
|
-
|
|
623
|
-
(match, specifier) => {
|
|
624
|
-
|
|
625
|
-
return `from "/@modules/${specifier}"`;
|
|
733
|
+
/\bfrom\s+(['"])([^'"./][^'"]*)\1/g,
|
|
734
|
+
(match, quote, specifier) => {
|
|
735
|
+
return `from ${quote}/@modules/${specifier}${quote}`;
|
|
626
736
|
}
|
|
627
737
|
).replace(
|
|
628
|
-
|
|
629
|
-
(
|
|
630
|
-
|
|
631
|
-
return `import
|
|
738
|
+
// 处理纯副作用导入: import 'bare-specifier'
|
|
739
|
+
/\bimport\s+(['"])([^'"./][^'"]*)\1/g,
|
|
740
|
+
(match, quote, specifier) => {
|
|
741
|
+
return `import ${quote}/@modules/${specifier}${quote}`;
|
|
742
|
+
}
|
|
743
|
+
).replace(
|
|
744
|
+
// 处理动态导入: import('bare-specifier')
|
|
745
|
+
/\bimport\s*\(\s*(['"])([^'"./][^'"]*)\1\s*\)/g,
|
|
746
|
+
(match, quote, specifier) => {
|
|
747
|
+
return `import(${quote}/@modules/${specifier}${quote})`;
|
|
632
748
|
}
|
|
633
749
|
);
|
|
634
750
|
}
|
|
@@ -637,14 +753,13 @@ function resolveUrlToFile(url, root) {
|
|
|
637
753
|
if (cleanUrl.startsWith("/@modules/")) {
|
|
638
754
|
const moduleName = cleanUrl.slice("/@modules/".length);
|
|
639
755
|
try {
|
|
640
|
-
const
|
|
641
|
-
const req = createRequire2(path3.resolve(root, "package.json"));
|
|
756
|
+
const req = createRequire(path4.resolve(root, "package.json"));
|
|
642
757
|
return req.resolve(moduleName);
|
|
643
758
|
} catch {
|
|
644
759
|
return null;
|
|
645
760
|
}
|
|
646
761
|
}
|
|
647
|
-
return
|
|
762
|
+
return path4.resolve(root, cleanUrl.replace(/^\//, ""));
|
|
648
763
|
}
|
|
649
764
|
function isModuleRequest(url) {
|
|
650
765
|
const cleanUrl = url.split("?")[0];
|
|
@@ -706,7 +821,18 @@ function showErrorOverlay(err) {
|
|
|
706
821
|
const overlay = document.createElement('div');
|
|
707
822
|
overlay.id = 'nasti-error-overlay';
|
|
708
823
|
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;';
|
|
709
|
-
|
|
824
|
+
const title = document.createElement('h2');
|
|
825
|
+
title.style.color = '#ff5555';
|
|
826
|
+
title.textContent = 'Build Error';
|
|
827
|
+
const pre = document.createElement('pre');
|
|
828
|
+
pre.textContent = err.message + '\\n' + (err.stack || '');
|
|
829
|
+
const btn = document.createElement('button');
|
|
830
|
+
btn.style.cssText = 'margin-top:1rem;padding:0.5rem 1rem;cursor:pointer';
|
|
831
|
+
btn.textContent = 'Close';
|
|
832
|
+
btn.onclick = () => overlay.remove();
|
|
833
|
+
overlay.appendChild(title);
|
|
834
|
+
overlay.appendChild(pre);
|
|
835
|
+
overlay.appendChild(btn);
|
|
710
836
|
document.body.appendChild(overlay);
|
|
711
837
|
}
|
|
712
838
|
|
|
@@ -742,15 +868,16 @@ var init_middleware = __esm({
|
|
|
742
868
|
"use strict";
|
|
743
869
|
init_transformer();
|
|
744
870
|
init_html();
|
|
871
|
+
init_env();
|
|
745
872
|
}
|
|
746
873
|
});
|
|
747
874
|
|
|
748
875
|
// src/server/hmr.ts
|
|
749
|
-
import
|
|
750
|
-
import
|
|
876
|
+
import path5 from "path";
|
|
877
|
+
import fs5 from "fs";
|
|
751
878
|
async function handleFileChange(file, server) {
|
|
752
879
|
const { moduleGraph, ws, config } = server;
|
|
753
|
-
const relativePath = "/" +
|
|
880
|
+
const relativePath = "/" + path5.relative(config.root, file);
|
|
754
881
|
const mods = moduleGraph.getModulesByFile(file);
|
|
755
882
|
if (!mods || mods.size === 0) {
|
|
756
883
|
return;
|
|
@@ -763,7 +890,7 @@ async function handleFileChange(file, server) {
|
|
|
763
890
|
file,
|
|
764
891
|
timestamp,
|
|
765
892
|
modules: [mod],
|
|
766
|
-
read: () =>
|
|
893
|
+
read: () => fs5.readFileSync(file, "utf-8"),
|
|
767
894
|
server
|
|
768
895
|
};
|
|
769
896
|
let affectedModules = [mod];
|
|
@@ -802,12 +929,12 @@ var init_hmr = __esm({
|
|
|
802
929
|
});
|
|
803
930
|
|
|
804
931
|
// src/plugins/resolve.ts
|
|
805
|
-
import
|
|
806
|
-
import
|
|
807
|
-
import { createRequire } from "module";
|
|
932
|
+
import path6 from "path";
|
|
933
|
+
import fs6 from "fs";
|
|
934
|
+
import { createRequire as createRequire2 } from "module";
|
|
808
935
|
function resolvePlugin(config) {
|
|
809
936
|
const { alias, extensions } = config.resolve;
|
|
810
|
-
const require2 =
|
|
937
|
+
const require2 = createRequire2(path6.resolve(config.root, "package.json"));
|
|
811
938
|
return {
|
|
812
939
|
name: "nasti:resolve",
|
|
813
940
|
enforce: "pre",
|
|
@@ -815,26 +942,26 @@ function resolvePlugin(config) {
|
|
|
815
942
|
for (const [key, value] of Object.entries(alias)) {
|
|
816
943
|
if (source === key || source.startsWith(key + "/")) {
|
|
817
944
|
source = source.replace(key, value);
|
|
818
|
-
if (!
|
|
819
|
-
source =
|
|
945
|
+
if (!path6.isAbsolute(source)) {
|
|
946
|
+
source = path6.resolve(config.root, source);
|
|
820
947
|
}
|
|
821
948
|
break;
|
|
822
949
|
}
|
|
823
950
|
}
|
|
824
|
-
if (
|
|
951
|
+
if (path6.isAbsolute(source)) {
|
|
825
952
|
const resolved = tryResolveFile(source, extensions);
|
|
826
953
|
if (resolved) return resolved;
|
|
827
954
|
}
|
|
828
955
|
if (source.startsWith(".")) {
|
|
829
|
-
const dir = importer ?
|
|
830
|
-
const absolute =
|
|
956
|
+
const dir = importer ? path6.dirname(importer) : config.root;
|
|
957
|
+
const absolute = path6.resolve(dir, source);
|
|
831
958
|
const resolved = tryResolveFile(absolute, extensions);
|
|
832
959
|
if (resolved) return resolved;
|
|
833
960
|
}
|
|
834
961
|
if (!source.startsWith("/") && !source.startsWith(".")) {
|
|
835
962
|
try {
|
|
836
963
|
const resolved = require2.resolve(source, {
|
|
837
|
-
paths: [importer ?
|
|
964
|
+
paths: [importer ? path6.dirname(importer) : config.root]
|
|
838
965
|
});
|
|
839
966
|
return resolved;
|
|
840
967
|
} catch {
|
|
@@ -844,27 +971,29 @@ function resolvePlugin(config) {
|
|
|
844
971
|
return null;
|
|
845
972
|
},
|
|
846
973
|
load(id) {
|
|
847
|
-
if (
|
|
848
|
-
|
|
974
|
+
if (!fs6.existsSync(id)) return null;
|
|
975
|
+
if (id.endsWith(".json")) {
|
|
976
|
+
const content = fs6.readFileSync(id, "utf-8");
|
|
977
|
+
return `export default ${content}`;
|
|
849
978
|
}
|
|
850
|
-
return
|
|
979
|
+
return fs6.readFileSync(id, "utf-8");
|
|
851
980
|
}
|
|
852
981
|
};
|
|
853
982
|
}
|
|
854
983
|
function tryResolveFile(file, extensions) {
|
|
855
|
-
if (
|
|
984
|
+
if (fs6.existsSync(file) && fs6.statSync(file).isFile()) {
|
|
856
985
|
return file;
|
|
857
986
|
}
|
|
858
987
|
for (const ext of extensions) {
|
|
859
988
|
const withExt = file + ext;
|
|
860
|
-
if (
|
|
989
|
+
if (fs6.existsSync(withExt) && fs6.statSync(withExt).isFile()) {
|
|
861
990
|
return withExt;
|
|
862
991
|
}
|
|
863
992
|
}
|
|
864
|
-
if (
|
|
993
|
+
if (fs6.existsSync(file) && fs6.statSync(file).isDirectory()) {
|
|
865
994
|
for (const ext of extensions) {
|
|
866
|
-
const indexFile =
|
|
867
|
-
if (
|
|
995
|
+
const indexFile = path6.join(file, "index" + ext);
|
|
996
|
+
if (fs6.existsSync(indexFile)) {
|
|
868
997
|
return indexFile;
|
|
869
998
|
}
|
|
870
999
|
}
|
|
@@ -878,7 +1007,7 @@ var init_resolve = __esm({
|
|
|
878
1007
|
});
|
|
879
1008
|
|
|
880
1009
|
// src/plugins/css.ts
|
|
881
|
-
import
|
|
1010
|
+
import path7 from "path";
|
|
882
1011
|
function cssPlugin(config) {
|
|
883
1012
|
return {
|
|
884
1013
|
name: "nasti:css",
|
|
@@ -888,13 +1017,17 @@ function cssPlugin(config) {
|
|
|
888
1017
|
},
|
|
889
1018
|
transform(code, id) {
|
|
890
1019
|
if (!id.endsWith(".css")) return null;
|
|
1020
|
+
const rewritten = rewriteCssUrls(code, id, config.root);
|
|
891
1021
|
if (config.command === "serve") {
|
|
892
|
-
const escaped = JSON.stringify(
|
|
1022
|
+
const escaped = JSON.stringify(rewritten);
|
|
893
1023
|
return {
|
|
894
1024
|
code: `
|
|
895
1025
|
const css = ${escaped};
|
|
1026
|
+
const __nasti_css_id__ = ${JSON.stringify(id)};
|
|
1027
|
+
const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
|
|
1028
|
+
if (__nasti_existing__) __nasti_existing__.remove();
|
|
896
1029
|
const style = document.createElement('style');
|
|
897
|
-
style.setAttribute('data-nasti-css',
|
|
1030
|
+
style.setAttribute('data-nasti-css', __nasti_css_id__);
|
|
898
1031
|
style.textContent = css;
|
|
899
1032
|
document.head.appendChild(style);
|
|
900
1033
|
|
|
@@ -910,10 +1043,20 @@ export default css;
|
|
|
910
1043
|
`
|
|
911
1044
|
};
|
|
912
1045
|
}
|
|
913
|
-
return null;
|
|
1046
|
+
return rewritten !== code ? { code: rewritten } : null;
|
|
914
1047
|
}
|
|
915
1048
|
};
|
|
916
1049
|
}
|
|
1050
|
+
function rewriteCssUrls(css, from, root) {
|
|
1051
|
+
return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
|
|
1052
|
+
if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
|
|
1053
|
+
return match;
|
|
1054
|
+
}
|
|
1055
|
+
const resolved = path7.resolve(path7.dirname(from), url);
|
|
1056
|
+
const relative = "/" + path7.relative(root, resolved);
|
|
1057
|
+
return `url(${relative})`;
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
917
1060
|
var init_css = __esm({
|
|
918
1061
|
"src/plugins/css.ts"() {
|
|
919
1062
|
"use strict";
|
|
@@ -921,8 +1064,8 @@ var init_css = __esm({
|
|
|
921
1064
|
});
|
|
922
1065
|
|
|
923
1066
|
// src/plugins/assets.ts
|
|
924
|
-
import
|
|
925
|
-
import
|
|
1067
|
+
import path8 from "path";
|
|
1068
|
+
import fs7 from "fs";
|
|
926
1069
|
import crypto from "crypto";
|
|
927
1070
|
function assetsPlugin(config) {
|
|
928
1071
|
return {
|
|
@@ -934,24 +1077,24 @@ function assetsPlugin(config) {
|
|
|
934
1077
|
return null;
|
|
935
1078
|
},
|
|
936
1079
|
load(id) {
|
|
937
|
-
const ext =
|
|
1080
|
+
const ext = path8.extname(id.replace(/\?.*$/, ""));
|
|
938
1081
|
if (id.endsWith("?raw")) {
|
|
939
1082
|
const file = id.slice(0, -4);
|
|
940
|
-
if (
|
|
941
|
-
const content =
|
|
1083
|
+
if (fs7.existsSync(file)) {
|
|
1084
|
+
const content = fs7.readFileSync(file, "utf-8");
|
|
942
1085
|
return `export default ${JSON.stringify(content)}`;
|
|
943
1086
|
}
|
|
944
1087
|
}
|
|
945
1088
|
if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
|
|
946
1089
|
const file = id.replace(/\?.*$/, "");
|
|
947
|
-
if (!
|
|
1090
|
+
if (!fs7.existsSync(file)) return null;
|
|
948
1091
|
if (config.command === "serve") {
|
|
949
|
-
const url = "/" +
|
|
1092
|
+
const url = "/" + path8.relative(config.root, file);
|
|
950
1093
|
return `export default ${JSON.stringify(url)}`;
|
|
951
1094
|
}
|
|
952
|
-
const content =
|
|
1095
|
+
const content = fs7.readFileSync(file);
|
|
953
1096
|
const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
954
|
-
const basename =
|
|
1097
|
+
const basename = path8.basename(file, ext);
|
|
955
1098
|
const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
|
|
956
1099
|
return `export default ${JSON.stringify(config.base + hashedName)}`;
|
|
957
1100
|
}
|
|
@@ -996,7 +1139,8 @@ __export(server_exports, {
|
|
|
996
1139
|
createServer: () => createServer
|
|
997
1140
|
});
|
|
998
1141
|
import http from "http";
|
|
999
|
-
import
|
|
1142
|
+
import path9 from "path";
|
|
1143
|
+
import os from "os";
|
|
1000
1144
|
import connect from "connect";
|
|
1001
1145
|
import sirv from "sirv";
|
|
1002
1146
|
import { watch } from "chokidar";
|
|
@@ -1019,7 +1163,7 @@ async function createServer(inlineConfig = {}) {
|
|
|
1019
1163
|
pluginContainer,
|
|
1020
1164
|
moduleGraph
|
|
1021
1165
|
}));
|
|
1022
|
-
const publicDir =
|
|
1166
|
+
const publicDir = path9.resolve(config.root, "public");
|
|
1023
1167
|
app.use(sirv(publicDir, { dev: true, etag: true }));
|
|
1024
1168
|
app.use(sirv(config.root, { dev: true, etag: true }));
|
|
1025
1169
|
const httpServer = http.createServer(app);
|
|
@@ -1096,7 +1240,6 @@ async function createServer(inlineConfig = {}) {
|
|
|
1096
1240
|
return server;
|
|
1097
1241
|
}
|
|
1098
1242
|
function getNetworkAddress() {
|
|
1099
|
-
const os = __require("os");
|
|
1100
1243
|
const interfaces = os.networkInterfaces();
|
|
1101
1244
|
for (const name of Object.keys(interfaces)) {
|
|
1102
1245
|
for (const iface of interfaces[name] ?? []) {
|
|
@@ -1128,8 +1271,8 @@ var build_exports = {};
|
|
|
1128
1271
|
__export(build_exports, {
|
|
1129
1272
|
build: () => build
|
|
1130
1273
|
});
|
|
1131
|
-
import
|
|
1132
|
-
import
|
|
1274
|
+
import path10 from "path";
|
|
1275
|
+
import fs8 from "fs";
|
|
1133
1276
|
import { rolldown } from "rolldown";
|
|
1134
1277
|
import pc2 from "picocolors";
|
|
1135
1278
|
async function build(inlineConfig = {}) {
|
|
@@ -1138,11 +1281,11 @@ async function build(inlineConfig = {}) {
|
|
|
1138
1281
|
console.log(pc2.cyan("\n\u{1F528} nasti build") + pc2.dim(` v${process.env.npm_package_version ?? "0.0.1"}`));
|
|
1139
1282
|
console.log(pc2.dim(` root: ${config.root}`));
|
|
1140
1283
|
console.log(pc2.dim(` mode: ${config.mode}`));
|
|
1141
|
-
const outDir =
|
|
1142
|
-
if (config.build.emptyOutDir &&
|
|
1143
|
-
|
|
1284
|
+
const outDir = path10.resolve(config.root, config.build.outDir);
|
|
1285
|
+
if (config.build.emptyOutDir && fs8.existsSync(outDir)) {
|
|
1286
|
+
fs8.rmSync(outDir, { recursive: true, force: true });
|
|
1144
1287
|
}
|
|
1145
|
-
|
|
1288
|
+
fs8.mkdirSync(outDir, { recursive: true });
|
|
1146
1289
|
const html = await readHtmlFile(config.root);
|
|
1147
1290
|
let entryPoints = [];
|
|
1148
1291
|
if (html) {
|
|
@@ -1150,15 +1293,15 @@ async function build(inlineConfig = {}) {
|
|
|
1150
1293
|
for (const match of scriptMatches) {
|
|
1151
1294
|
const src = match[1];
|
|
1152
1295
|
if (src && !src.startsWith("http")) {
|
|
1153
|
-
entryPoints.push(
|
|
1296
|
+
entryPoints.push(path10.resolve(config.root, src.replace(/^\//, "")));
|
|
1154
1297
|
}
|
|
1155
1298
|
}
|
|
1156
1299
|
}
|
|
1157
1300
|
if (entryPoints.length === 0) {
|
|
1158
1301
|
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
1159
1302
|
for (const entry of fallbackEntries) {
|
|
1160
|
-
const fullPath =
|
|
1161
|
-
if (
|
|
1303
|
+
const fullPath = path10.resolve(config.root, entry);
|
|
1304
|
+
if (fs8.existsSync(fullPath)) {
|
|
1162
1305
|
entryPoints.push(fullPath);
|
|
1163
1306
|
break;
|
|
1164
1307
|
}
|
|
@@ -1173,6 +1316,8 @@ async function build(inlineConfig = {}) {
|
|
|
1173
1316
|
assetsPlugin(config)
|
|
1174
1317
|
];
|
|
1175
1318
|
const allPlugins = [...builtinPlugins, ...config.plugins];
|
|
1319
|
+
const pluginContainer = new PluginContainer(config);
|
|
1320
|
+
await pluginContainer.buildStart();
|
|
1176
1321
|
const oxcTransformPlugin = {
|
|
1177
1322
|
name: "nasti:oxc-transform",
|
|
1178
1323
|
transform(code, id) {
|
|
@@ -1185,8 +1330,11 @@ async function build(inlineConfig = {}) {
|
|
|
1185
1330
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
1186
1331
|
}
|
|
1187
1332
|
};
|
|
1333
|
+
const env = loadEnv(config.mode, config.root, config.envPrefix);
|
|
1334
|
+
const envDefine = buildEnvDefine(env, config.mode);
|
|
1188
1335
|
const bundle = await rolldown({
|
|
1189
1336
|
input: entryPoints,
|
|
1337
|
+
define: envDefine,
|
|
1190
1338
|
plugins: [
|
|
1191
1339
|
oxcTransformPlugin,
|
|
1192
1340
|
// 转换 Nasti 插件为 Rolldown 插件格式
|
|
@@ -1205,11 +1353,18 @@ async function build(inlineConfig = {}) {
|
|
|
1205
1353
|
dir: outDir,
|
|
1206
1354
|
format: "esm",
|
|
1207
1355
|
sourcemap: !!config.build.sourcemap,
|
|
1356
|
+
minify: !!config.build.minify,
|
|
1208
1357
|
entryFileNames: "assets/[name].[hash].js",
|
|
1209
1358
|
chunkFileNames: "assets/[name].[hash].js",
|
|
1210
1359
|
assetFileNames: "assets/[name].[hash][extname]"
|
|
1211
1360
|
});
|
|
1212
1361
|
await bundle.close();
|
|
1362
|
+
await pluginContainer.buildEnd();
|
|
1363
|
+
for (const ef of pluginContainer.getEmittedFiles()) {
|
|
1364
|
+
const dest = path10.resolve(outDir, ef.fileName);
|
|
1365
|
+
fs8.mkdirSync(path10.dirname(dest), { recursive: true });
|
|
1366
|
+
fs8.writeFileSync(dest, ef.source);
|
|
1367
|
+
}
|
|
1213
1368
|
if (html) {
|
|
1214
1369
|
let processedHtml = html;
|
|
1215
1370
|
const htmlPlugin_ = htmlPlugin(config);
|
|
@@ -1224,15 +1379,15 @@ async function build(inlineConfig = {}) {
|
|
|
1224
1379
|
}
|
|
1225
1380
|
}
|
|
1226
1381
|
for (const chunk of output) {
|
|
1227
|
-
if (chunk.type === "chunk" && chunk.isEntry) {
|
|
1228
|
-
const originalEntry =
|
|
1382
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
1383
|
+
const originalEntry = path10.relative(config.root, chunk.facadeModuleId);
|
|
1229
1384
|
processedHtml = processedHtml.replace(
|
|
1230
1385
|
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
1231
1386
|
`$1${config.base}${chunk.fileName}$3`
|
|
1232
1387
|
);
|
|
1233
1388
|
}
|
|
1234
1389
|
}
|
|
1235
|
-
|
|
1390
|
+
fs8.writeFileSync(path10.resolve(outDir, "index.html"), processedHtml);
|
|
1236
1391
|
}
|
|
1237
1392
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
1238
1393
|
const totalSize = output.reduce((sum, chunk) => {
|
|
@@ -1263,6 +1418,8 @@ var init_build = __esm({
|
|
|
1263
1418
|
init_assets();
|
|
1264
1419
|
init_html();
|
|
1265
1420
|
init_transformer();
|
|
1421
|
+
init_env();
|
|
1422
|
+
init_plugin_container();
|
|
1266
1423
|
}
|
|
1267
1424
|
});
|
|
1268
1425
|
|
|
@@ -1316,11 +1473,11 @@ cli.command("build [root]", "Build for production").option("--outDir <dir>", "Ou
|
|
|
1316
1473
|
cli.command("preview [root]", "Preview production build").option("--port <port>", "Port number", { default: 4173 }).option("--host [host]", "Hostname").option("--outDir <dir>", "Output directory to serve", { default: "dist" }).action(async (root, options) => {
|
|
1317
1474
|
try {
|
|
1318
1475
|
const http2 = await import("http");
|
|
1319
|
-
const
|
|
1476
|
+
const path11 = await import("path");
|
|
1320
1477
|
const sirv2 = (await import("sirv")).default;
|
|
1321
1478
|
const connect2 = (await import("connect")).default;
|
|
1322
|
-
const resolvedRoot =
|
|
1323
|
-
const outDir =
|
|
1479
|
+
const resolvedRoot = path11.resolve(root ?? ".");
|
|
1480
|
+
const outDir = path11.resolve(resolvedRoot, options.outDir);
|
|
1324
1481
|
const app = connect2();
|
|
1325
1482
|
app.use(sirv2(outDir, { single: true, etag: true, gzip: true, brotli: true }));
|
|
1326
1483
|
const port = options.port;
|