@nasti-toolchain/nasti 1.1.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/LICENSE +21 -0
- package/README.md +169 -0
- package/bin/nasti.js +2 -0
- package/client/hmr.ts +19 -0
- package/dist/cli.cjs +1369 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1346 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/hmr.cjs +19 -0
- package/dist/client/hmr.cjs.map +1 -0
- package/dist/client/hmr.d.cts +15 -0
- package/dist/client/hmr.d.ts +15 -0
- package/dist/client/hmr.js +1 -0
- package/dist/client/hmr.js.map +1 -0
- package/dist/index.cjs +1233 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +216 -0
- package/dist/index.d.ts +216 -0
- package/dist/index.js +1204 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,1369 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
|
|
32
|
+
// src/config/defaults.ts
|
|
33
|
+
var defaultResolve, defaultServer, defaultBuild, defaults;
|
|
34
|
+
var init_defaults = __esm({
|
|
35
|
+
"src/config/defaults.ts"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
defaultResolve = {
|
|
38
|
+
alias: {},
|
|
39
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".json", ".vue"],
|
|
40
|
+
conditions: ["import", "module", "browser", "default"],
|
|
41
|
+
mainFields: ["module", "jsnext:main", "jsnext", "main"]
|
|
42
|
+
};
|
|
43
|
+
defaultServer = {
|
|
44
|
+
port: 3e3,
|
|
45
|
+
host: "localhost",
|
|
46
|
+
https: false,
|
|
47
|
+
open: false,
|
|
48
|
+
proxy: {},
|
|
49
|
+
cors: true,
|
|
50
|
+
hmr: true
|
|
51
|
+
};
|
|
52
|
+
defaultBuild = {
|
|
53
|
+
outDir: "dist",
|
|
54
|
+
assetsDir: "assets",
|
|
55
|
+
minify: true,
|
|
56
|
+
sourcemap: false,
|
|
57
|
+
target: "es2022",
|
|
58
|
+
rolldownOptions: {},
|
|
59
|
+
emptyOutDir: true
|
|
60
|
+
};
|
|
61
|
+
defaults = {
|
|
62
|
+
root: ".",
|
|
63
|
+
base: "/",
|
|
64
|
+
mode: "development",
|
|
65
|
+
framework: "auto",
|
|
66
|
+
resolve: defaultResolve,
|
|
67
|
+
server: defaultServer,
|
|
68
|
+
build: defaultBuild,
|
|
69
|
+
plugins: [],
|
|
70
|
+
envPrefix: ["NASTI_", "VITE_"],
|
|
71
|
+
logLevel: "info"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// src/config/index.ts
|
|
77
|
+
async function loadConfigFromFile(root) {
|
|
78
|
+
for (const file of CONFIG_FILES) {
|
|
79
|
+
const filePath = import_node_path.default.resolve(root, file);
|
|
80
|
+
if (!import_node_fs.default.existsSync(filePath)) continue;
|
|
81
|
+
if (file.endsWith(".ts") || file.endsWith(".mts")) {
|
|
82
|
+
return await loadTsConfig(filePath);
|
|
83
|
+
}
|
|
84
|
+
const mod = await import((0, import_node_url.pathToFileURL)(filePath).href);
|
|
85
|
+
return mod.default ?? mod;
|
|
86
|
+
}
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
async function loadTsConfig(filePath) {
|
|
90
|
+
const { transformSync: transformSync2 } = await import("oxc-transform");
|
|
91
|
+
const code = import_node_fs.default.readFileSync(filePath, "utf-8");
|
|
92
|
+
const result = transformSync2(filePath, code, {
|
|
93
|
+
typescript: {}
|
|
94
|
+
});
|
|
95
|
+
const tmpFile = filePath + ".timestamp-" + Date.now() + ".mjs";
|
|
96
|
+
try {
|
|
97
|
+
import_node_fs.default.writeFileSync(tmpFile, result.code);
|
|
98
|
+
const mod = await import((0, import_node_url.pathToFileURL)(tmpFile).href);
|
|
99
|
+
return mod.default ?? mod;
|
|
100
|
+
} finally {
|
|
101
|
+
import_node_fs.default.unlinkSync(tmpFile);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function resolveConfig(inlineConfig = {}, command) {
|
|
105
|
+
const root = import_node_path.default.resolve(inlineConfig.root ?? defaults.root);
|
|
106
|
+
const fileConfig = await loadConfigFromFile(root);
|
|
107
|
+
const merged = deepMerge(deepMerge({}, fileConfig), inlineConfig);
|
|
108
|
+
const rawPlugins = [
|
|
109
|
+
...fileConfig.plugins ?? [],
|
|
110
|
+
...inlineConfig.plugins ?? []
|
|
111
|
+
];
|
|
112
|
+
const env = { mode: merged.mode ?? defaults.mode, command };
|
|
113
|
+
for (const plugin of rawPlugins) {
|
|
114
|
+
if (plugin.config) {
|
|
115
|
+
const result = await plugin.config(merged, env);
|
|
116
|
+
if (result) Object.assign(merged, result);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const filteredPlugins = rawPlugins.filter((p) => {
|
|
120
|
+
if (!p.apply) return true;
|
|
121
|
+
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
122
|
+
return p.apply === command;
|
|
123
|
+
});
|
|
124
|
+
const resolved = {
|
|
125
|
+
root,
|
|
126
|
+
base: merged.base ?? defaults.base,
|
|
127
|
+
mode: command === "build" ? "production" : "development",
|
|
128
|
+
framework: merged.framework ?? defaults.framework,
|
|
129
|
+
command,
|
|
130
|
+
resolve: {
|
|
131
|
+
alias: { ...defaults.resolve.alias, ...merged.resolve?.alias },
|
|
132
|
+
extensions: merged.resolve?.extensions ?? defaults.resolve.extensions,
|
|
133
|
+
conditions: merged.resolve?.conditions ?? defaults.resolve.conditions,
|
|
134
|
+
mainFields: merged.resolve?.mainFields ?? defaults.resolve.mainFields
|
|
135
|
+
},
|
|
136
|
+
plugins: filteredPlugins,
|
|
137
|
+
server: { ...defaults.server, ...merged.server },
|
|
138
|
+
build: { ...defaults.build, ...merged.build },
|
|
139
|
+
envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
|
|
140
|
+
logLevel: merged.logLevel ?? defaults.logLevel
|
|
141
|
+
};
|
|
142
|
+
for (const plugin of resolved.plugins) {
|
|
143
|
+
if (plugin.configResolved) {
|
|
144
|
+
await plugin.configResolved(resolved);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return resolved;
|
|
148
|
+
}
|
|
149
|
+
function deepMerge(target, source) {
|
|
150
|
+
const result = { ...target };
|
|
151
|
+
for (const key of Object.keys(source)) {
|
|
152
|
+
const val = source[key];
|
|
153
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
154
|
+
result[key] = deepMerge(
|
|
155
|
+
result[key] ?? {},
|
|
156
|
+
val
|
|
157
|
+
);
|
|
158
|
+
} else if (val !== void 0) {
|
|
159
|
+
result[key] = val;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
var import_node_url, import_node_path, import_node_fs, CONFIG_FILES;
|
|
165
|
+
var init_config = __esm({
|
|
166
|
+
"src/config/index.ts"() {
|
|
167
|
+
"use strict";
|
|
168
|
+
import_node_url = require("url");
|
|
169
|
+
import_node_path = __toESM(require("path"), 1);
|
|
170
|
+
import_node_fs = __toESM(require("fs"), 1);
|
|
171
|
+
init_defaults();
|
|
172
|
+
CONFIG_FILES = [
|
|
173
|
+
"nasti.config.ts",
|
|
174
|
+
"nasti.config.js",
|
|
175
|
+
"nasti.config.mjs",
|
|
176
|
+
"nasti.config.mts"
|
|
177
|
+
];
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// src/core/plugin-container.ts
|
|
182
|
+
function sortPlugins(plugins) {
|
|
183
|
+
const pre = [];
|
|
184
|
+
const normal = [];
|
|
185
|
+
const post = [];
|
|
186
|
+
for (const plugin of plugins) {
|
|
187
|
+
if (plugin.enforce === "pre") pre.push(plugin);
|
|
188
|
+
else if (plugin.enforce === "post") post.push(plugin);
|
|
189
|
+
else normal.push(plugin);
|
|
190
|
+
}
|
|
191
|
+
return [...pre, ...normal, ...post];
|
|
192
|
+
}
|
|
193
|
+
var PluginContainer;
|
|
194
|
+
var init_plugin_container = __esm({
|
|
195
|
+
"src/core/plugin-container.ts"() {
|
|
196
|
+
"use strict";
|
|
197
|
+
PluginContainer = class {
|
|
198
|
+
plugins;
|
|
199
|
+
config;
|
|
200
|
+
ctx;
|
|
201
|
+
constructor(config) {
|
|
202
|
+
this.config = config;
|
|
203
|
+
this.plugins = sortPlugins(config.plugins);
|
|
204
|
+
this.ctx = this.createContext();
|
|
205
|
+
}
|
|
206
|
+
createContext() {
|
|
207
|
+
const container = this;
|
|
208
|
+
return {
|
|
209
|
+
async resolve(source, importer) {
|
|
210
|
+
return container.resolveId(source, importer);
|
|
211
|
+
},
|
|
212
|
+
emitFile(_file) {
|
|
213
|
+
return "";
|
|
214
|
+
},
|
|
215
|
+
getModuleInfo(_id) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async buildStart() {
|
|
221
|
+
for (const plugin of this.plugins) {
|
|
222
|
+
if (plugin.buildStart) {
|
|
223
|
+
await plugin.buildStart.call(this.ctx);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async buildEnd(error) {
|
|
228
|
+
for (const plugin of this.plugins) {
|
|
229
|
+
if (plugin.buildEnd) {
|
|
230
|
+
await plugin.buildEnd.call(this.ctx, error);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async resolveId(source, importer, options = {}) {
|
|
235
|
+
for (const plugin of this.plugins) {
|
|
236
|
+
if (!plugin.resolveId) continue;
|
|
237
|
+
const result = await plugin.resolveId.call(
|
|
238
|
+
this.ctx,
|
|
239
|
+
source,
|
|
240
|
+
importer ?? void 0,
|
|
241
|
+
{ isEntry: options.isEntry ?? false, ssr: false }
|
|
242
|
+
);
|
|
243
|
+
if (result != null) return result;
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
async load(id) {
|
|
248
|
+
for (const plugin of this.plugins) {
|
|
249
|
+
if (!plugin.load) continue;
|
|
250
|
+
const result = await plugin.load.call(this.ctx, id);
|
|
251
|
+
if (result != null) return result;
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
async transform(code, id) {
|
|
256
|
+
let currentCode = code;
|
|
257
|
+
for (const plugin of this.plugins) {
|
|
258
|
+
if (!plugin.transform) continue;
|
|
259
|
+
const result = await plugin.transform.call(this.ctx, currentCode, id);
|
|
260
|
+
if (result == null) continue;
|
|
261
|
+
if (typeof result === "string") {
|
|
262
|
+
currentCode = result;
|
|
263
|
+
} else {
|
|
264
|
+
currentCode = result.code;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return currentCode === code ? null : { code: currentCode };
|
|
268
|
+
}
|
|
269
|
+
/** 完整的模块处理管道: resolveId → load → transform */
|
|
270
|
+
async processModule(source, importer) {
|
|
271
|
+
const resolveResult = await this.resolveId(source, importer, {
|
|
272
|
+
isEntry: !importer
|
|
273
|
+
});
|
|
274
|
+
if (resolveResult == null) return null;
|
|
275
|
+
const id = typeof resolveResult === "string" ? resolveResult : resolveResult.id;
|
|
276
|
+
const loadResult = await this.load(id);
|
|
277
|
+
if (loadResult == null) return null;
|
|
278
|
+
const loadedCode = typeof loadResult === "string" ? loadResult : loadResult.code;
|
|
279
|
+
const transformResult = await this.transform(loadedCode, id);
|
|
280
|
+
const finalCode = transformResult == null ? loadedCode : typeof transformResult === "string" ? transformResult : transformResult.code;
|
|
281
|
+
return { id, code: finalCode };
|
|
282
|
+
}
|
|
283
|
+
getPlugins() {
|
|
284
|
+
return this.plugins;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// src/core/module-graph.ts
|
|
291
|
+
var ModuleGraph;
|
|
292
|
+
var init_module_graph = __esm({
|
|
293
|
+
"src/core/module-graph.ts"() {
|
|
294
|
+
"use strict";
|
|
295
|
+
ModuleGraph = class {
|
|
296
|
+
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
297
|
+
idToModuleMap = /* @__PURE__ */ new Map();
|
|
298
|
+
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
299
|
+
getModuleByUrl(url) {
|
|
300
|
+
return this.urlToModuleMap.get(url);
|
|
301
|
+
}
|
|
302
|
+
getModuleById(id) {
|
|
303
|
+
return this.idToModuleMap.get(id);
|
|
304
|
+
}
|
|
305
|
+
getModulesByFile(file) {
|
|
306
|
+
return this.fileToModulesMap.get(file);
|
|
307
|
+
}
|
|
308
|
+
async ensureEntryFromUrl(url) {
|
|
309
|
+
let mod = this.urlToModuleMap.get(url);
|
|
310
|
+
if (mod) return mod;
|
|
311
|
+
mod = this.createModule(url);
|
|
312
|
+
this.urlToModuleMap.set(url, mod);
|
|
313
|
+
return mod;
|
|
314
|
+
}
|
|
315
|
+
createModule(url, id) {
|
|
316
|
+
const mod = {
|
|
317
|
+
id: id ?? url,
|
|
318
|
+
file: null,
|
|
319
|
+
url,
|
|
320
|
+
type: url.endsWith(".css") ? "css" : "js",
|
|
321
|
+
importers: /* @__PURE__ */ new Set(),
|
|
322
|
+
importedModules: /* @__PURE__ */ new Set(),
|
|
323
|
+
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
324
|
+
transformResult: null,
|
|
325
|
+
lastHMRTimestamp: 0,
|
|
326
|
+
isSelfAccepting: false
|
|
327
|
+
};
|
|
328
|
+
this.idToModuleMap.set(mod.id, mod);
|
|
329
|
+
return mod;
|
|
330
|
+
}
|
|
331
|
+
/** 注册文件路径到模块的映射 */
|
|
332
|
+
registerModule(mod, file) {
|
|
333
|
+
mod.file = file;
|
|
334
|
+
let mods = this.fileToModulesMap.get(file);
|
|
335
|
+
if (!mods) {
|
|
336
|
+
mods = /* @__PURE__ */ new Set();
|
|
337
|
+
this.fileToModulesMap.set(file, mods);
|
|
338
|
+
}
|
|
339
|
+
mods.add(mod);
|
|
340
|
+
}
|
|
341
|
+
/** 更新模块依赖关系 */
|
|
342
|
+
updateModuleImports(mod, importedIds) {
|
|
343
|
+
for (const imported of mod.importedModules) {
|
|
344
|
+
imported.importers.delete(mod);
|
|
345
|
+
}
|
|
346
|
+
mod.importedModules.clear();
|
|
347
|
+
for (const id of importedIds) {
|
|
348
|
+
const importedMod = this.idToModuleMap.get(id);
|
|
349
|
+
if (importedMod) {
|
|
350
|
+
mod.importedModules.add(importedMod);
|
|
351
|
+
importedMod.importers.add(mod);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/** 使模块的转换缓存失效 */
|
|
356
|
+
invalidateModule(mod) {
|
|
357
|
+
mod.transformResult = null;
|
|
358
|
+
mod.lastHMRTimestamp = Date.now();
|
|
359
|
+
}
|
|
360
|
+
/** 使所有模块缓存失效 */
|
|
361
|
+
invalidateAll() {
|
|
362
|
+
for (const mod of this.idToModuleMap.values()) {
|
|
363
|
+
this.invalidateModule(mod);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
367
|
+
getHmrBoundaries(mod) {
|
|
368
|
+
const boundaries = [];
|
|
369
|
+
const visited = /* @__PURE__ */ new Set();
|
|
370
|
+
const propagate = (node, via) => {
|
|
371
|
+
if (visited.has(node)) return true;
|
|
372
|
+
visited.add(node);
|
|
373
|
+
if (node.isSelfAccepting) {
|
|
374
|
+
boundaries.push({ boundary: node, acceptedVia: via });
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
if (node.acceptedHmrDeps.has(via)) {
|
|
378
|
+
boundaries.push({ boundary: node, acceptedVia: via });
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
if (node.importers.size === 0) return false;
|
|
382
|
+
for (const importer of node.importers) {
|
|
383
|
+
if (!propagate(importer, node)) return false;
|
|
384
|
+
}
|
|
385
|
+
return true;
|
|
386
|
+
};
|
|
387
|
+
if (mod.isSelfAccepting) {
|
|
388
|
+
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
389
|
+
return boundaries;
|
|
390
|
+
}
|
|
391
|
+
for (const importer of mod.importers) {
|
|
392
|
+
if (!propagate(importer, mod)) {
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return boundaries;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// src/server/ws.ts
|
|
403
|
+
function createWebSocketServer(server) {
|
|
404
|
+
const wss = new import_ws.WebSocketServer({ noServer: true });
|
|
405
|
+
const clients = /* @__PURE__ */ new Set();
|
|
406
|
+
server.on("upgrade", (req, socket, head) => {
|
|
407
|
+
if (req.headers["sec-websocket-protocol"] === "nasti-hmr") {
|
|
408
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
409
|
+
wss.emit("connection", ws, req);
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
wss.on("connection", (ws) => {
|
|
414
|
+
clients.add(ws);
|
|
415
|
+
ws.send(JSON.stringify({ type: "connected" }));
|
|
416
|
+
ws.on("close", () => {
|
|
417
|
+
clients.delete(ws);
|
|
418
|
+
});
|
|
419
|
+
ws.on("error", (err) => {
|
|
420
|
+
console.error("[nasti] WebSocket error:", err);
|
|
421
|
+
clients.delete(ws);
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
return {
|
|
425
|
+
send(payload) {
|
|
426
|
+
const data = JSON.stringify(payload);
|
|
427
|
+
for (const client of clients) {
|
|
428
|
+
if (client.readyState === 1) {
|
|
429
|
+
client.send(data);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
close() {
|
|
434
|
+
clients.clear();
|
|
435
|
+
wss.close();
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
var import_ws;
|
|
440
|
+
var init_ws = __esm({
|
|
441
|
+
"src/server/ws.ts"() {
|
|
442
|
+
"use strict";
|
|
443
|
+
import_ws = require("ws");
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// src/core/transformer.ts
|
|
448
|
+
function shouldTransform(id) {
|
|
449
|
+
return TS_EXTENSIONS.test(id) || JSX_EXTENSIONS.test(id) || JS_EXTENSIONS.test(id) && false;
|
|
450
|
+
}
|
|
451
|
+
function transformCode(filename, code, options = {}) {
|
|
452
|
+
const isTS = TS_EXTENSIONS.test(filename) || /\.tsx$/.test(filename);
|
|
453
|
+
const isJSX = JSX_EXTENSIONS.test(filename);
|
|
454
|
+
const result = (0, import_oxc_transform.transformSync)(filename, code, {
|
|
455
|
+
typescript: isTS ? {} : void 0,
|
|
456
|
+
jsx: isJSX || /\.tsx$/.test(filename) ? {
|
|
457
|
+
runtime: options.jsxRuntime ?? "automatic",
|
|
458
|
+
importSource: options.jsxImportSource ?? "react",
|
|
459
|
+
refresh: options.reactRefresh ?? false
|
|
460
|
+
} : void 0,
|
|
461
|
+
sourcemap: options.sourcemap ?? true
|
|
462
|
+
});
|
|
463
|
+
return {
|
|
464
|
+
code: result.code,
|
|
465
|
+
map: result.map ? JSON.stringify(result.map) : null
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
|
|
469
|
+
var init_transformer = __esm({
|
|
470
|
+
"src/core/transformer.ts"() {
|
|
471
|
+
"use strict";
|
|
472
|
+
import_oxc_transform = require("oxc-transform");
|
|
473
|
+
JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
|
|
474
|
+
TS_EXTENSIONS = /\.(ts|mts|cts)$/;
|
|
475
|
+
JSX_EXTENSIONS = /\.(jsx|tsx)$/;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
// src/plugins/html.ts
|
|
480
|
+
function htmlPlugin(config) {
|
|
481
|
+
return {
|
|
482
|
+
name: "nasti:html",
|
|
483
|
+
enforce: "post",
|
|
484
|
+
transformIndexHtml(html) {
|
|
485
|
+
const tags = [];
|
|
486
|
+
if (config.command === "serve") {
|
|
487
|
+
tags.push({
|
|
488
|
+
tag: "script",
|
|
489
|
+
attrs: { type: "module", src: "/@nasti/client" },
|
|
490
|
+
injectTo: "head-prepend"
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return { html, tags };
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function processHtml(html, tags) {
|
|
498
|
+
const headPrepend = tags.filter((t) => t.injectTo === "head-prepend");
|
|
499
|
+
const head = tags.filter((t) => t.injectTo === "head" || !t.injectTo);
|
|
500
|
+
const bodyPrepend = tags.filter((t) => t.injectTo === "body-prepend");
|
|
501
|
+
const body = tags.filter((t) => t.injectTo === "body");
|
|
502
|
+
if (headPrepend.length) {
|
|
503
|
+
html = html.replace(/<head([^>]*)>/i, `<head$1>
|
|
504
|
+
${serializeTags(headPrepend)}`);
|
|
505
|
+
}
|
|
506
|
+
if (head.length) {
|
|
507
|
+
html = html.replace(/<\/head>/i, `${serializeTags(head)}
|
|
508
|
+
</head>`);
|
|
509
|
+
}
|
|
510
|
+
if (bodyPrepend.length) {
|
|
511
|
+
html = html.replace(/<body([^>]*)>/i, `<body$1>
|
|
512
|
+
${serializeTags(bodyPrepend)}`);
|
|
513
|
+
}
|
|
514
|
+
if (body.length) {
|
|
515
|
+
html = html.replace(/<\/body>/i, `${serializeTags(body)}
|
|
516
|
+
</body>`);
|
|
517
|
+
}
|
|
518
|
+
return html;
|
|
519
|
+
}
|
|
520
|
+
function serializeTags(tags) {
|
|
521
|
+
return tags.map(serializeTag).join("\n");
|
|
522
|
+
}
|
|
523
|
+
function serializeTag(tag) {
|
|
524
|
+
const attrs = tag.attrs ? " " + Object.entries(tag.attrs).map(([k, v]) => v === true ? k : `${k}="${v}"`).join(" ") : "";
|
|
525
|
+
const children = typeof tag.children === "string" ? tag.children : tag.children ? serializeTags(tag.children) : "";
|
|
526
|
+
const selfClosing = ["link", "meta", "br", "hr", "img", "input"].includes(tag.tag);
|
|
527
|
+
if (selfClosing && !children) {
|
|
528
|
+
return ` <${tag.tag}${attrs} />`;
|
|
529
|
+
}
|
|
530
|
+
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
531
|
+
}
|
|
532
|
+
async function readHtmlFile(root) {
|
|
533
|
+
const htmlPath = import_node_path2.default.resolve(root, "index.html");
|
|
534
|
+
if (!import_node_fs2.default.existsSync(htmlPath)) return null;
|
|
535
|
+
return import_node_fs2.default.readFileSync(htmlPath, "utf-8");
|
|
536
|
+
}
|
|
537
|
+
var import_node_path2, import_node_fs2;
|
|
538
|
+
var init_html = __esm({
|
|
539
|
+
"src/plugins/html.ts"() {
|
|
540
|
+
"use strict";
|
|
541
|
+
import_node_path2 = __toESM(require("path"), 1);
|
|
542
|
+
import_node_fs2 = __toESM(require("fs"), 1);
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// src/server/middleware.ts
|
|
547
|
+
var middleware_exports = {};
|
|
548
|
+
__export(middleware_exports, {
|
|
549
|
+
transformMiddleware: () => transformMiddleware,
|
|
550
|
+
transformRequest: () => transformRequest
|
|
551
|
+
});
|
|
552
|
+
function transformMiddleware(ctx) {
|
|
553
|
+
return async (req, res, next) => {
|
|
554
|
+
const url = req.url ?? "/";
|
|
555
|
+
if (req.method !== "GET") return next();
|
|
556
|
+
if (url === "/@nasti/client") {
|
|
557
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
558
|
+
res.end(getHmrClientCode());
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (url === "/" || url.endsWith(".html")) {
|
|
562
|
+
const html = await readHtmlFile(ctx.config.root);
|
|
563
|
+
if (html) {
|
|
564
|
+
let processedHtml = html;
|
|
565
|
+
for (const plugin of ctx.config.plugins) {
|
|
566
|
+
if (plugin.transformIndexHtml) {
|
|
567
|
+
const result = await plugin.transformIndexHtml(processedHtml);
|
|
568
|
+
if (typeof result === "string") {
|
|
569
|
+
processedHtml = result;
|
|
570
|
+
} else if (result && "html" in result) {
|
|
571
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
572
|
+
} else if (Array.isArray(result)) {
|
|
573
|
+
processedHtml = processHtml(processedHtml, result);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
processedHtml = processedHtml.replace(
|
|
578
|
+
"<head>",
|
|
579
|
+
'<head>\n <script type="module" src="/@nasti/client"></script>'
|
|
580
|
+
);
|
|
581
|
+
res.setHeader("Content-Type", "text/html");
|
|
582
|
+
res.end(processedHtml);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (isModuleRequest(url)) {
|
|
587
|
+
try {
|
|
588
|
+
const result = await transformRequest(url, ctx);
|
|
589
|
+
if (result) {
|
|
590
|
+
const contentType = url.endsWith(".css") ? "application/javascript" : "application/javascript";
|
|
591
|
+
res.setHeader("Content-Type", contentType);
|
|
592
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
593
|
+
res.end(typeof result === "string" ? result : result.code);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
} catch (err) {
|
|
597
|
+
console.error(`[nasti] Transform error: ${url}`, err.message);
|
|
598
|
+
res.statusCode = 500;
|
|
599
|
+
res.end(`Transform error: ${err.message}`);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
next();
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
async function transformRequest(url, ctx) {
|
|
607
|
+
const { config, pluginContainer, moduleGraph } = ctx;
|
|
608
|
+
const cached = moduleGraph.getModuleByUrl(url);
|
|
609
|
+
if (cached?.transformResult) {
|
|
610
|
+
return cached.transformResult;
|
|
611
|
+
}
|
|
612
|
+
const filePath = resolveUrlToFile(url, config.root);
|
|
613
|
+
if (!filePath || !import_node_fs3.default.existsSync(filePath)) return null;
|
|
614
|
+
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
615
|
+
moduleGraph.registerModule(mod, filePath);
|
|
616
|
+
let code = import_node_fs3.default.readFileSync(filePath, "utf-8");
|
|
617
|
+
const pluginResult = await pluginContainer.transform(code, filePath);
|
|
618
|
+
if (pluginResult) {
|
|
619
|
+
code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
|
|
620
|
+
}
|
|
621
|
+
if (shouldTransform(filePath)) {
|
|
622
|
+
const result = transformCode(filePath, code, {
|
|
623
|
+
sourcemap: true,
|
|
624
|
+
jsxRuntime: "automatic",
|
|
625
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
626
|
+
reactRefresh: config.framework !== "vue"
|
|
627
|
+
});
|
|
628
|
+
code = result.code;
|
|
629
|
+
}
|
|
630
|
+
code = rewriteImports(code, config);
|
|
631
|
+
const transformResult = { code };
|
|
632
|
+
mod.transformResult = transformResult;
|
|
633
|
+
return transformResult;
|
|
634
|
+
}
|
|
635
|
+
function rewriteImports(code, config) {
|
|
636
|
+
return code.replace(
|
|
637
|
+
/from\s+['"]([^'"./][^'"]*)['"]/g,
|
|
638
|
+
(match, specifier) => {
|
|
639
|
+
if (specifier.startsWith("/") || specifier.startsWith(".")) return match;
|
|
640
|
+
return `from "/@modules/${specifier}"`;
|
|
641
|
+
}
|
|
642
|
+
).replace(
|
|
643
|
+
/import\s+['"]([^'"./][^'"]*)['"]/g,
|
|
644
|
+
(match, specifier) => {
|
|
645
|
+
if (specifier.startsWith("/") || specifier.startsWith(".")) return match;
|
|
646
|
+
return `import "/@modules/${specifier}"`;
|
|
647
|
+
}
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
function resolveUrlToFile(url, root) {
|
|
651
|
+
const cleanUrl = url.split("?")[0];
|
|
652
|
+
if (cleanUrl.startsWith("/@modules/")) {
|
|
653
|
+
const moduleName = cleanUrl.slice("/@modules/".length);
|
|
654
|
+
try {
|
|
655
|
+
const { createRequire: createRequire2 } = require("module");
|
|
656
|
+
const req = createRequire2(import_node_path3.default.resolve(root, "package.json"));
|
|
657
|
+
return req.resolve(moduleName);
|
|
658
|
+
} catch {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return import_node_path3.default.resolve(root, cleanUrl.replace(/^\//, ""));
|
|
663
|
+
}
|
|
664
|
+
function isModuleRequest(url) {
|
|
665
|
+
const cleanUrl = url.split("?")[0];
|
|
666
|
+
return /\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl) || cleanUrl.startsWith("/@modules/");
|
|
667
|
+
}
|
|
668
|
+
function getHmrClientCode() {
|
|
669
|
+
return `
|
|
670
|
+
// Nasti HMR Client
|
|
671
|
+
const socket = new WebSocket(\`ws://\${location.host}\`, 'nasti-hmr');
|
|
672
|
+
const hotModulesMap = new Map();
|
|
673
|
+
|
|
674
|
+
socket.addEventListener('message', ({ data }) => {
|
|
675
|
+
const payload = JSON.parse(data);
|
|
676
|
+
switch (payload.type) {
|
|
677
|
+
case 'connected':
|
|
678
|
+
console.log('[nasti] connected.');
|
|
679
|
+
break;
|
|
680
|
+
case 'update':
|
|
681
|
+
payload.updates.forEach((update) => {
|
|
682
|
+
if (update.type === 'js-update') {
|
|
683
|
+
fetchUpdate(update);
|
|
684
|
+
} else if (update.type === 'css-update') {
|
|
685
|
+
updateCss(update.path);
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
break;
|
|
689
|
+
case 'full-reload':
|
|
690
|
+
console.log('[nasti] full reload');
|
|
691
|
+
location.reload();
|
|
692
|
+
break;
|
|
693
|
+
case 'error':
|
|
694
|
+
console.error('[nasti] error:', payload.err.message);
|
|
695
|
+
showErrorOverlay(payload.err);
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
async function fetchUpdate(update) {
|
|
701
|
+
const mod = hotModulesMap.get(update.path);
|
|
702
|
+
if (mod) {
|
|
703
|
+
const newMod = await import(update.acceptedPath + '?t=' + update.timestamp);
|
|
704
|
+
mod.callbacks.forEach((cb) => cb(newMod));
|
|
705
|
+
} else {
|
|
706
|
+
// \u6CA1\u6709\u6CE8\u518C hot \u56DE\u8C03\uFF0C\u5C1D\u8BD5\u91CD\u65B0 import
|
|
707
|
+
await import(update.path + '?t=' + update.timestamp);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function updateCss(path) {
|
|
712
|
+
const el = document.querySelector(\`style[data-nasti-css="\${path}"]\`);
|
|
713
|
+
if (el) {
|
|
714
|
+
fetch(path + '?t=' + Date.now())
|
|
715
|
+
.then(r => r.text())
|
|
716
|
+
.then(css => { el.textContent = css; });
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function showErrorOverlay(err) {
|
|
721
|
+
const overlay = document.createElement('div');
|
|
722
|
+
overlay.id = 'nasti-error-overlay';
|
|
723
|
+
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;';
|
|
724
|
+
overlay.innerHTML = \`<h2 style="color:#ff5555">Build Error</h2><pre>\${err.message}\\n\${err.stack || ''}</pre><button onclick="this.parentElement.remove()" style="margin-top:1rem;padding:0.5rem 1rem;cursor:pointer">Close</button>\`;
|
|
725
|
+
document.body.appendChild(overlay);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// import.meta.hot API
|
|
729
|
+
const createHotContext = (ownerPath) => ({
|
|
730
|
+
accept(deps, callback) {
|
|
731
|
+
if (typeof deps === 'function' || !deps) {
|
|
732
|
+
// self-accepting
|
|
733
|
+
const callbacks = hotModulesMap.get(ownerPath)?.callbacks || [];
|
|
734
|
+
callbacks.push(deps || (() => {}));
|
|
735
|
+
hotModulesMap.set(ownerPath, { callbacks });
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
prune(callback) {
|
|
739
|
+
// \u6A21\u5757\u88AB\u79FB\u9664\u65F6\u6267\u884C
|
|
740
|
+
},
|
|
741
|
+
dispose(callback) {
|
|
742
|
+
// \u6A21\u5757\u66F4\u65B0\u524D\u6267\u884C\u6E05\u7406
|
|
743
|
+
},
|
|
744
|
+
invalidate() {
|
|
745
|
+
location.reload();
|
|
746
|
+
},
|
|
747
|
+
data: {},
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
// \u66B4\u9732\u7ED9\u6A21\u5757\u4F7F\u7528
|
|
751
|
+
if (!window.__nasti_hot_map) window.__nasti_hot_map = new Map();
|
|
752
|
+
window.__NASTI_HMR__ = { createHotContext };
|
|
753
|
+
`;
|
|
754
|
+
}
|
|
755
|
+
var import_node_path3, import_node_fs3;
|
|
756
|
+
var init_middleware = __esm({
|
|
757
|
+
"src/server/middleware.ts"() {
|
|
758
|
+
"use strict";
|
|
759
|
+
import_node_path3 = __toESM(require("path"), 1);
|
|
760
|
+
import_node_fs3 = __toESM(require("fs"), 1);
|
|
761
|
+
init_transformer();
|
|
762
|
+
init_html();
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
// src/server/hmr.ts
|
|
767
|
+
async function handleFileChange(file, server) {
|
|
768
|
+
const { moduleGraph, ws, config } = server;
|
|
769
|
+
const relativePath = "/" + import_node_path4.default.relative(config.root, file);
|
|
770
|
+
const mods = moduleGraph.getModulesByFile(file);
|
|
771
|
+
if (!mods || mods.size === 0) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
const updates = [];
|
|
775
|
+
const timestamp = Date.now();
|
|
776
|
+
for (const mod of mods) {
|
|
777
|
+
moduleGraph.invalidateModule(mod);
|
|
778
|
+
const ctx = {
|
|
779
|
+
file,
|
|
780
|
+
timestamp,
|
|
781
|
+
modules: [mod],
|
|
782
|
+
read: () => import_node_fs4.default.readFileSync(file, "utf-8"),
|
|
783
|
+
server
|
|
784
|
+
};
|
|
785
|
+
let affectedModules = [mod];
|
|
786
|
+
for (const plugin of config.plugins) {
|
|
787
|
+
if (plugin.handleHotUpdate) {
|
|
788
|
+
const result = await plugin.handleHotUpdate(ctx);
|
|
789
|
+
if (result) {
|
|
790
|
+
affectedModules = result;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
for (const affected of affectedModules) {
|
|
795
|
+
const boundaries = moduleGraph.getHmrBoundaries(affected);
|
|
796
|
+
if (boundaries.length === 0) {
|
|
797
|
+
ws.send({ type: "full-reload", path: relativePath });
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
for (const { boundary } of boundaries) {
|
|
801
|
+
updates.push({
|
|
802
|
+
type: boundary.type === "css" ? "css-update" : "js-update",
|
|
803
|
+
path: boundary.url,
|
|
804
|
+
acceptedPath: affected.url,
|
|
805
|
+
timestamp
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
if (updates.length > 0) {
|
|
811
|
+
ws.send({ type: "update", updates });
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
var import_node_path4, import_node_fs4;
|
|
815
|
+
var init_hmr = __esm({
|
|
816
|
+
"src/server/hmr.ts"() {
|
|
817
|
+
"use strict";
|
|
818
|
+
import_node_path4 = __toESM(require("path"), 1);
|
|
819
|
+
import_node_fs4 = __toESM(require("fs"), 1);
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
// src/plugins/resolve.ts
|
|
824
|
+
function resolvePlugin(config) {
|
|
825
|
+
const { alias, extensions } = config.resolve;
|
|
826
|
+
const require2 = (0, import_node_module.createRequire)(import_node_path5.default.resolve(config.root, "package.json"));
|
|
827
|
+
return {
|
|
828
|
+
name: "nasti:resolve",
|
|
829
|
+
enforce: "pre",
|
|
830
|
+
resolveId(source, importer) {
|
|
831
|
+
for (const [key, value] of Object.entries(alias)) {
|
|
832
|
+
if (source === key || source.startsWith(key + "/")) {
|
|
833
|
+
source = source.replace(key, value);
|
|
834
|
+
if (!import_node_path5.default.isAbsolute(source)) {
|
|
835
|
+
source = import_node_path5.default.resolve(config.root, source);
|
|
836
|
+
}
|
|
837
|
+
break;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (import_node_path5.default.isAbsolute(source)) {
|
|
841
|
+
const resolved = tryResolveFile(source, extensions);
|
|
842
|
+
if (resolved) return resolved;
|
|
843
|
+
}
|
|
844
|
+
if (source.startsWith(".")) {
|
|
845
|
+
const dir = importer ? import_node_path5.default.dirname(importer) : config.root;
|
|
846
|
+
const absolute = import_node_path5.default.resolve(dir, source);
|
|
847
|
+
const resolved = tryResolveFile(absolute, extensions);
|
|
848
|
+
if (resolved) return resolved;
|
|
849
|
+
}
|
|
850
|
+
if (!source.startsWith("/") && !source.startsWith(".")) {
|
|
851
|
+
try {
|
|
852
|
+
const resolved = require2.resolve(source, {
|
|
853
|
+
paths: [importer ? import_node_path5.default.dirname(importer) : config.root]
|
|
854
|
+
});
|
|
855
|
+
return resolved;
|
|
856
|
+
} catch {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
return null;
|
|
861
|
+
},
|
|
862
|
+
load(id) {
|
|
863
|
+
if (import_node_fs5.default.existsSync(id)) {
|
|
864
|
+
return import_node_fs5.default.readFileSync(id, "utf-8");
|
|
865
|
+
}
|
|
866
|
+
return null;
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
function tryResolveFile(file, extensions) {
|
|
871
|
+
if (import_node_fs5.default.existsSync(file) && import_node_fs5.default.statSync(file).isFile()) {
|
|
872
|
+
return file;
|
|
873
|
+
}
|
|
874
|
+
for (const ext of extensions) {
|
|
875
|
+
const withExt = file + ext;
|
|
876
|
+
if (import_node_fs5.default.existsSync(withExt) && import_node_fs5.default.statSync(withExt).isFile()) {
|
|
877
|
+
return withExt;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (import_node_fs5.default.existsSync(file) && import_node_fs5.default.statSync(file).isDirectory()) {
|
|
881
|
+
for (const ext of extensions) {
|
|
882
|
+
const indexFile = import_node_path5.default.join(file, "index" + ext);
|
|
883
|
+
if (import_node_fs5.default.existsSync(indexFile)) {
|
|
884
|
+
return indexFile;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
var import_node_path5, import_node_fs5, import_node_module;
|
|
891
|
+
var init_resolve = __esm({
|
|
892
|
+
"src/plugins/resolve.ts"() {
|
|
893
|
+
"use strict";
|
|
894
|
+
import_node_path5 = __toESM(require("path"), 1);
|
|
895
|
+
import_node_fs5 = __toESM(require("fs"), 1);
|
|
896
|
+
import_node_module = require("module");
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// src/plugins/css.ts
|
|
901
|
+
function cssPlugin(config) {
|
|
902
|
+
return {
|
|
903
|
+
name: "nasti:css",
|
|
904
|
+
resolveId(source) {
|
|
905
|
+
if (source.endsWith(".css")) return null;
|
|
906
|
+
return null;
|
|
907
|
+
},
|
|
908
|
+
transform(code, id) {
|
|
909
|
+
if (!id.endsWith(".css")) return null;
|
|
910
|
+
if (config.command === "serve") {
|
|
911
|
+
const escaped = JSON.stringify(code);
|
|
912
|
+
return {
|
|
913
|
+
code: `
|
|
914
|
+
const css = ${escaped};
|
|
915
|
+
const style = document.createElement('style');
|
|
916
|
+
style.setAttribute('data-nasti-css', ${JSON.stringify(id)});
|
|
917
|
+
style.textContent = css;
|
|
918
|
+
document.head.appendChild(style);
|
|
919
|
+
|
|
920
|
+
// HMR
|
|
921
|
+
if (import.meta.hot) {
|
|
922
|
+
import.meta.hot.accept();
|
|
923
|
+
import.meta.hot.prune(() => {
|
|
924
|
+
style.remove();
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
export default css;
|
|
929
|
+
`
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
var import_node_path6;
|
|
937
|
+
var init_css = __esm({
|
|
938
|
+
"src/plugins/css.ts"() {
|
|
939
|
+
"use strict";
|
|
940
|
+
import_node_path6 = __toESM(require("path"), 1);
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
// src/plugins/assets.ts
|
|
945
|
+
function assetsPlugin(config) {
|
|
946
|
+
return {
|
|
947
|
+
name: "nasti:assets",
|
|
948
|
+
resolveId(source) {
|
|
949
|
+
if (source.endsWith("?url") || source.endsWith("?raw")) {
|
|
950
|
+
return source;
|
|
951
|
+
}
|
|
952
|
+
return null;
|
|
953
|
+
},
|
|
954
|
+
load(id) {
|
|
955
|
+
const ext = import_node_path7.default.extname(id.replace(/\?.*$/, ""));
|
|
956
|
+
if (id.endsWith("?raw")) {
|
|
957
|
+
const file = id.slice(0, -4);
|
|
958
|
+
if (import_node_fs6.default.existsSync(file)) {
|
|
959
|
+
const content = import_node_fs6.default.readFileSync(file, "utf-8");
|
|
960
|
+
return `export default ${JSON.stringify(content)}`;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
|
|
964
|
+
const file = id.replace(/\?.*$/, "");
|
|
965
|
+
if (!import_node_fs6.default.existsSync(file)) return null;
|
|
966
|
+
if (config.command === "serve") {
|
|
967
|
+
const url = "/" + import_node_path7.default.relative(config.root, file);
|
|
968
|
+
return `export default ${JSON.stringify(url)}`;
|
|
969
|
+
}
|
|
970
|
+
const content = import_node_fs6.default.readFileSync(file);
|
|
971
|
+
const hash = import_node_crypto.default.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
972
|
+
const basename = import_node_path7.default.basename(file, ext);
|
|
973
|
+
const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
|
|
974
|
+
return `export default ${JSON.stringify(config.base + hashedName)}`;
|
|
975
|
+
}
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
var import_node_path7, import_node_fs6, import_node_crypto, ASSET_EXTENSIONS;
|
|
981
|
+
var init_assets = __esm({
|
|
982
|
+
"src/plugins/assets.ts"() {
|
|
983
|
+
"use strict";
|
|
984
|
+
import_node_path7 = __toESM(require("path"), 1);
|
|
985
|
+
import_node_fs6 = __toESM(require("fs"), 1);
|
|
986
|
+
import_node_crypto = __toESM(require("crypto"), 1);
|
|
987
|
+
ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
988
|
+
".png",
|
|
989
|
+
".jpg",
|
|
990
|
+
".jpeg",
|
|
991
|
+
".gif",
|
|
992
|
+
".svg",
|
|
993
|
+
".ico",
|
|
994
|
+
".webp",
|
|
995
|
+
".avif",
|
|
996
|
+
".mp4",
|
|
997
|
+
".webm",
|
|
998
|
+
".ogg",
|
|
999
|
+
".mp3",
|
|
1000
|
+
".wav",
|
|
1001
|
+
".flac",
|
|
1002
|
+
".aac",
|
|
1003
|
+
".woff",
|
|
1004
|
+
".woff2",
|
|
1005
|
+
".eot",
|
|
1006
|
+
".ttf",
|
|
1007
|
+
".otf",
|
|
1008
|
+
".pdf",
|
|
1009
|
+
".txt"
|
|
1010
|
+
]);
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
// src/server/index.ts
|
|
1015
|
+
var server_exports = {};
|
|
1016
|
+
__export(server_exports, {
|
|
1017
|
+
createServer: () => createServer
|
|
1018
|
+
});
|
|
1019
|
+
async function createServer(inlineConfig = {}) {
|
|
1020
|
+
const config = await resolveConfig(inlineConfig, "serve");
|
|
1021
|
+
const allPlugins = [
|
|
1022
|
+
resolvePlugin(config),
|
|
1023
|
+
cssPlugin(config),
|
|
1024
|
+
assetsPlugin(config),
|
|
1025
|
+
htmlPlugin(config),
|
|
1026
|
+
...config.plugins
|
|
1027
|
+
];
|
|
1028
|
+
const configWithPlugins = { ...config, plugins: allPlugins };
|
|
1029
|
+
const moduleGraph = new ModuleGraph();
|
|
1030
|
+
const pluginContainer = new PluginContainer(configWithPlugins);
|
|
1031
|
+
const app = (0, import_connect.default)();
|
|
1032
|
+
app.use(transformMiddleware({
|
|
1033
|
+
config: configWithPlugins,
|
|
1034
|
+
pluginContainer,
|
|
1035
|
+
moduleGraph
|
|
1036
|
+
}));
|
|
1037
|
+
const publicDir = import_node_path8.default.resolve(config.root, "public");
|
|
1038
|
+
app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
|
|
1039
|
+
app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
|
|
1040
|
+
const httpServer = import_node_http.default.createServer(app);
|
|
1041
|
+
const ws = createWebSocketServer(httpServer);
|
|
1042
|
+
const watcher = (0, import_chokidar.watch)(config.root, {
|
|
1043
|
+
ignored: [
|
|
1044
|
+
"**/node_modules/**",
|
|
1045
|
+
"**/.git/**",
|
|
1046
|
+
`**/${config.build.outDir}/**`
|
|
1047
|
+
],
|
|
1048
|
+
ignoreInitial: true
|
|
1049
|
+
});
|
|
1050
|
+
let server;
|
|
1051
|
+
watcher.on("change", (file) => {
|
|
1052
|
+
handleFileChange(file, server);
|
|
1053
|
+
});
|
|
1054
|
+
watcher.on("add", (file) => {
|
|
1055
|
+
handleFileChange(file, server);
|
|
1056
|
+
});
|
|
1057
|
+
const postMiddlewares = [];
|
|
1058
|
+
for (const plugin of allPlugins) {
|
|
1059
|
+
if (plugin.configureServer) {
|
|
1060
|
+
const result = await plugin.configureServer(server);
|
|
1061
|
+
if (typeof result === "function") {
|
|
1062
|
+
postMiddlewares.push(result);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
server = {
|
|
1067
|
+
config: configWithPlugins,
|
|
1068
|
+
middlewares: app,
|
|
1069
|
+
moduleGraph,
|
|
1070
|
+
watcher,
|
|
1071
|
+
ws,
|
|
1072
|
+
async listen(port) {
|
|
1073
|
+
const finalPort = port ?? config.server.port;
|
|
1074
|
+
const host = config.server.host === true ? "0.0.0.0" : config.server.host;
|
|
1075
|
+
await pluginContainer.buildStart();
|
|
1076
|
+
return new Promise((resolve, reject) => {
|
|
1077
|
+
httpServer.listen(finalPort, host, () => {
|
|
1078
|
+
const localUrl = `http://localhost:${finalPort}`;
|
|
1079
|
+
const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${finalPort}` : null;
|
|
1080
|
+
console.log();
|
|
1081
|
+
console.log(import_picocolors.default.cyan(" nasti dev server") + import_picocolors.default.dim(` v0.0.1`));
|
|
1082
|
+
console.log();
|
|
1083
|
+
console.log(` ${import_picocolors.default.green(">")} Local: ${import_picocolors.default.cyan(localUrl)}`);
|
|
1084
|
+
if (networkUrl) {
|
|
1085
|
+
console.log(` ${import_picocolors.default.green(">")} Network: ${import_picocolors.default.cyan(networkUrl)}`);
|
|
1086
|
+
}
|
|
1087
|
+
console.log();
|
|
1088
|
+
resolve(server);
|
|
1089
|
+
});
|
|
1090
|
+
httpServer.on("error", (err) => {
|
|
1091
|
+
if (err.code === "EADDRINUSE") {
|
|
1092
|
+
console.log(import_picocolors.default.yellow(`Port ${finalPort} is in use, trying ${finalPort + 1}...`));
|
|
1093
|
+
httpServer.listen(finalPort + 1, host);
|
|
1094
|
+
} else {
|
|
1095
|
+
reject(err);
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
});
|
|
1099
|
+
},
|
|
1100
|
+
async transformRequest(url) {
|
|
1101
|
+
const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
|
|
1102
|
+
return transformRequest2(url, { config: configWithPlugins, pluginContainer, moduleGraph });
|
|
1103
|
+
},
|
|
1104
|
+
async close() {
|
|
1105
|
+
await pluginContainer.buildEnd();
|
|
1106
|
+
watcher.close();
|
|
1107
|
+
ws.close();
|
|
1108
|
+
httpServer.close();
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
return server;
|
|
1112
|
+
}
|
|
1113
|
+
function getNetworkAddress() {
|
|
1114
|
+
const os = require("os");
|
|
1115
|
+
const interfaces = os.networkInterfaces();
|
|
1116
|
+
for (const name of Object.keys(interfaces)) {
|
|
1117
|
+
for (const iface of interfaces[name] ?? []) {
|
|
1118
|
+
if (iface.family === "IPv4" && !iface.internal) {
|
|
1119
|
+
return iface.address;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
return "localhost";
|
|
1124
|
+
}
|
|
1125
|
+
var import_node_http, import_node_path8, import_connect, import_sirv, import_chokidar, import_picocolors;
|
|
1126
|
+
var init_server = __esm({
|
|
1127
|
+
"src/server/index.ts"() {
|
|
1128
|
+
"use strict";
|
|
1129
|
+
import_node_http = __toESM(require("http"), 1);
|
|
1130
|
+
import_node_path8 = __toESM(require("path"), 1);
|
|
1131
|
+
import_connect = __toESM(require("connect"), 1);
|
|
1132
|
+
import_sirv = __toESM(require("sirv"), 1);
|
|
1133
|
+
import_chokidar = require("chokidar");
|
|
1134
|
+
import_picocolors = __toESM(require("picocolors"), 1);
|
|
1135
|
+
init_config();
|
|
1136
|
+
init_plugin_container();
|
|
1137
|
+
init_module_graph();
|
|
1138
|
+
init_ws();
|
|
1139
|
+
init_middleware();
|
|
1140
|
+
init_hmr();
|
|
1141
|
+
init_resolve();
|
|
1142
|
+
init_css();
|
|
1143
|
+
init_assets();
|
|
1144
|
+
init_html();
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
// src/build/index.ts
|
|
1149
|
+
var build_exports = {};
|
|
1150
|
+
__export(build_exports, {
|
|
1151
|
+
build: () => build
|
|
1152
|
+
});
|
|
1153
|
+
async function build(inlineConfig = {}) {
|
|
1154
|
+
const config = await resolveConfig(inlineConfig, "build");
|
|
1155
|
+
const startTime = performance.now();
|
|
1156
|
+
console.log(import_picocolors2.default.cyan("\n\u{1F528} nasti build") + import_picocolors2.default.dim(` v${process.env.npm_package_version ?? "0.0.1"}`));
|
|
1157
|
+
console.log(import_picocolors2.default.dim(` root: ${config.root}`));
|
|
1158
|
+
console.log(import_picocolors2.default.dim(` mode: ${config.mode}`));
|
|
1159
|
+
const outDir = import_node_path9.default.resolve(config.root, config.build.outDir);
|
|
1160
|
+
if (config.build.emptyOutDir && import_node_fs7.default.existsSync(outDir)) {
|
|
1161
|
+
import_node_fs7.default.rmSync(outDir, { recursive: true, force: true });
|
|
1162
|
+
}
|
|
1163
|
+
import_node_fs7.default.mkdirSync(outDir, { recursive: true });
|
|
1164
|
+
const html = await readHtmlFile(config.root);
|
|
1165
|
+
let entryPoints = [];
|
|
1166
|
+
if (html) {
|
|
1167
|
+
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
1168
|
+
for (const match of scriptMatches) {
|
|
1169
|
+
const src = match[1];
|
|
1170
|
+
if (src && !src.startsWith("http")) {
|
|
1171
|
+
entryPoints.push(import_node_path9.default.resolve(config.root, src.replace(/^\//, "")));
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
if (entryPoints.length === 0) {
|
|
1176
|
+
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
1177
|
+
for (const entry of fallbackEntries) {
|
|
1178
|
+
const fullPath = import_node_path9.default.resolve(config.root, entry);
|
|
1179
|
+
if (import_node_fs7.default.existsSync(fullPath)) {
|
|
1180
|
+
entryPoints.push(fullPath);
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
if (entryPoints.length === 0) {
|
|
1186
|
+
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
1187
|
+
}
|
|
1188
|
+
const builtinPlugins = [
|
|
1189
|
+
resolvePlugin(config),
|
|
1190
|
+
cssPlugin(config),
|
|
1191
|
+
assetsPlugin(config)
|
|
1192
|
+
];
|
|
1193
|
+
const allPlugins = [...builtinPlugins, ...config.plugins];
|
|
1194
|
+
const oxcTransformPlugin = {
|
|
1195
|
+
name: "nasti:oxc-transform",
|
|
1196
|
+
transform(code, id) {
|
|
1197
|
+
if (!shouldTransform(id)) return null;
|
|
1198
|
+
const result = transformCode(id, code, {
|
|
1199
|
+
sourcemap: !!config.build.sourcemap,
|
|
1200
|
+
jsxRuntime: "automatic",
|
|
1201
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
1202
|
+
});
|
|
1203
|
+
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
const bundle = await (0, import_rolldown.rolldown)({
|
|
1207
|
+
input: entryPoints,
|
|
1208
|
+
plugins: [
|
|
1209
|
+
oxcTransformPlugin,
|
|
1210
|
+
// 转换 Nasti 插件为 Rolldown 插件格式
|
|
1211
|
+
...allPlugins.map((p) => ({
|
|
1212
|
+
name: p.name,
|
|
1213
|
+
resolveId: p.resolveId,
|
|
1214
|
+
load: p.load,
|
|
1215
|
+
transform: p.transform,
|
|
1216
|
+
buildStart: p.buildStart,
|
|
1217
|
+
buildEnd: p.buildEnd
|
|
1218
|
+
}))
|
|
1219
|
+
],
|
|
1220
|
+
...config.build.rolldownOptions
|
|
1221
|
+
});
|
|
1222
|
+
const { output } = await bundle.write({
|
|
1223
|
+
dir: outDir,
|
|
1224
|
+
format: "esm",
|
|
1225
|
+
sourcemap: !!config.build.sourcemap,
|
|
1226
|
+
entryFileNames: "assets/[name].[hash].js",
|
|
1227
|
+
chunkFileNames: "assets/[name].[hash].js",
|
|
1228
|
+
assetFileNames: "assets/[name].[hash][extname]"
|
|
1229
|
+
});
|
|
1230
|
+
await bundle.close();
|
|
1231
|
+
if (html) {
|
|
1232
|
+
let processedHtml = html;
|
|
1233
|
+
const htmlPlugin_ = htmlPlugin(config);
|
|
1234
|
+
if (htmlPlugin_.transformIndexHtml) {
|
|
1235
|
+
const result = await htmlPlugin_.transformIndexHtml(processedHtml);
|
|
1236
|
+
if (typeof result === "string") {
|
|
1237
|
+
processedHtml = result;
|
|
1238
|
+
} else if (result && "html" in result) {
|
|
1239
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
1240
|
+
} else if (Array.isArray(result)) {
|
|
1241
|
+
processedHtml = processHtml(processedHtml, result);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
for (const chunk of output) {
|
|
1245
|
+
if (chunk.type === "chunk" && chunk.isEntry) {
|
|
1246
|
+
const originalEntry = import_node_path9.default.relative(config.root, entryPoints[0]);
|
|
1247
|
+
processedHtml = processedHtml.replace(
|
|
1248
|
+
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
1249
|
+
`$1${config.base}${chunk.fileName}$3`
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
import_node_fs7.default.writeFileSync(import_node_path9.default.resolve(outDir, "index.html"), processedHtml);
|
|
1254
|
+
}
|
|
1255
|
+
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
1256
|
+
const totalSize = output.reduce((sum, chunk) => {
|
|
1257
|
+
if (chunk.type === "chunk" && chunk.code) return sum + chunk.code.length;
|
|
1258
|
+
return sum;
|
|
1259
|
+
}, 0);
|
|
1260
|
+
console.log(import_picocolors2.default.green(`
|
|
1261
|
+
\u2713 Built in ${elapsed}s`));
|
|
1262
|
+
console.log(import_picocolors2.default.dim(` ${output.length} files, ${formatSize(totalSize)} total`));
|
|
1263
|
+
console.log(import_picocolors2.default.dim(` output: ${config.build.outDir}/
|
|
1264
|
+
`));
|
|
1265
|
+
return { output };
|
|
1266
|
+
}
|
|
1267
|
+
function formatSize(bytes) {
|
|
1268
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1269
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;
|
|
1270
|
+
return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
|
|
1271
|
+
}
|
|
1272
|
+
function escapeRegExp(string) {
|
|
1273
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1274
|
+
}
|
|
1275
|
+
var import_node_path9, import_node_fs7, import_rolldown, import_picocolors2;
|
|
1276
|
+
var init_build = __esm({
|
|
1277
|
+
"src/build/index.ts"() {
|
|
1278
|
+
"use strict";
|
|
1279
|
+
import_node_path9 = __toESM(require("path"), 1);
|
|
1280
|
+
import_node_fs7 = __toESM(require("fs"), 1);
|
|
1281
|
+
import_rolldown = require("rolldown");
|
|
1282
|
+
init_config();
|
|
1283
|
+
init_resolve();
|
|
1284
|
+
init_css();
|
|
1285
|
+
init_assets();
|
|
1286
|
+
init_html();
|
|
1287
|
+
init_transformer();
|
|
1288
|
+
import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
// src/cli.ts
|
|
1293
|
+
var import_cac = require("cac");
|
|
1294
|
+
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
1295
|
+
var cli = (0, import_cac.cac)("nasti");
|
|
1296
|
+
cli.command("[root]", "Start dev server").alias("dev").option("--port <port>", "Port number", { default: 3e3 }).option("--host [host]", "Hostname").option("--open [path]", "Open browser on startup").option("--mode <mode>", "Set env mode").action(async (root, options) => {
|
|
1297
|
+
try {
|
|
1298
|
+
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
1299
|
+
const server = await createServer2({
|
|
1300
|
+
root: root ?? ".",
|
|
1301
|
+
mode: options.mode ?? "development",
|
|
1302
|
+
server: {
|
|
1303
|
+
port: options.port,
|
|
1304
|
+
host: options.host,
|
|
1305
|
+
open: options.open
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
await server.listen();
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
console.error(import_picocolors3.default.red(`
|
|
1311
|
+
Error starting dev server:
|
|
1312
|
+
${err.message}
|
|
1313
|
+
`));
|
|
1314
|
+
if (err.stack) console.error(import_picocolors3.default.dim(err.stack));
|
|
1315
|
+
process.exit(1);
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1318
|
+
cli.command("build [root]", "Build for production").option("--outDir <dir>", "Output directory", { default: "dist" }).option("--sourcemap", "Generate source map").option("--minify", "Minify output", { default: true }).option("--mode <mode>", "Set env mode").action(async (root, options) => {
|
|
1319
|
+
try {
|
|
1320
|
+
const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
1321
|
+
await build2({
|
|
1322
|
+
root: root ?? ".",
|
|
1323
|
+
mode: options.mode ?? "production",
|
|
1324
|
+
build: {
|
|
1325
|
+
outDir: options.outDir,
|
|
1326
|
+
sourcemap: options.sourcemap,
|
|
1327
|
+
minify: options.minify
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
console.error(import_picocolors3.default.red(`
|
|
1332
|
+
Build failed:
|
|
1333
|
+
${err.message}
|
|
1334
|
+
`));
|
|
1335
|
+
if (err.stack) console.error(import_picocolors3.default.dim(err.stack));
|
|
1336
|
+
process.exit(1);
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1339
|
+
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) => {
|
|
1340
|
+
try {
|
|
1341
|
+
const http2 = await import("http");
|
|
1342
|
+
const path10 = await import("path");
|
|
1343
|
+
const sirv2 = (await import("sirv")).default;
|
|
1344
|
+
const connect2 = (await import("connect")).default;
|
|
1345
|
+
const resolvedRoot = path10.resolve(root ?? ".");
|
|
1346
|
+
const outDir = path10.resolve(resolvedRoot, options.outDir);
|
|
1347
|
+
const app = connect2();
|
|
1348
|
+
app.use(sirv2(outDir, { single: true, etag: true, gzip: true, brotli: true }));
|
|
1349
|
+
const port = options.port;
|
|
1350
|
+
const host = options.host === true ? "0.0.0.0" : options.host ?? "localhost";
|
|
1351
|
+
http2.createServer(app).listen(port, host, () => {
|
|
1352
|
+
console.log();
|
|
1353
|
+
console.log(import_picocolors3.default.cyan(" \u{1F50D} nasti preview"));
|
|
1354
|
+
console.log();
|
|
1355
|
+
console.log(` ${import_picocolors3.default.green("\u279C")} Local: ${import_picocolors3.default.cyan(`http://localhost:${port}`)}`);
|
|
1356
|
+
console.log();
|
|
1357
|
+
});
|
|
1358
|
+
} catch (err) {
|
|
1359
|
+
console.error(import_picocolors3.default.red(`
|
|
1360
|
+
Preview failed:
|
|
1361
|
+
${err.message}
|
|
1362
|
+
`));
|
|
1363
|
+
process.exit(1);
|
|
1364
|
+
}
|
|
1365
|
+
});
|
|
1366
|
+
cli.help();
|
|
1367
|
+
cli.version("0.0.1");
|
|
1368
|
+
cli.parse();
|
|
1369
|
+
//# sourceMappingURL=cli.cjs.map
|