@nasti-toolchain/nasti 1.6.5 → 1.7.1

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/index.cjs CHANGED
@@ -305,6 +305,17 @@ function resolvePlugin(config) {
305
305
  const aliasEntries = Object.entries(alias).sort(
306
306
  ([a], [b]) => b.length - a.length
307
307
  );
308
+ let vueRuntimeEntry = null;
309
+ if (config.framework === "vue") {
310
+ try {
311
+ const vuePkgJson = require2.resolve("vue/package.json", { paths: [config.root] });
312
+ const vueDir = import_node_path2.default.dirname(vuePkgJson);
313
+ const mod = JSON.parse(import_node_fs2.default.readFileSync(vuePkgJson, "utf-8")).module;
314
+ const entry = import_node_path2.default.join(vueDir, mod ?? "dist/vue.runtime.esm-bundler.js");
315
+ if (import_node_fs2.default.existsSync(entry)) vueRuntimeEntry = entry;
316
+ } catch {
317
+ }
318
+ }
308
319
  return {
309
320
  name: "nasti:resolve",
310
321
  enforce: "pre",
@@ -335,6 +346,7 @@ function resolvePlugin(config) {
335
346
  if (resolved) return resolved;
336
347
  }
337
348
  if (!source.startsWith("/") && !source.startsWith(".")) {
349
+ if (vueRuntimeEntry && source === "vue") return vueRuntimeEntry;
338
350
  try {
339
351
  const resolved = require2.resolve(source, {
340
352
  paths: [importer ? import_node_path2.default.dirname(importer) : config.root]
@@ -420,15 +432,15 @@ async function loadTailwind(projectRoot) {
420
432
  async function compileTailwind(css, fromFile, projectRoot) {
421
433
  const { node, oxide } = await loadTailwind(projectRoot);
422
434
  const dependencies = [];
423
- const compiler = await node.compile(css, {
435
+ const compiler2 = await node.compile(css, {
424
436
  base: import_node_path3.default.dirname(fromFile),
425
437
  from: fromFile,
426
438
  onDependency: (p) => dependencies.push(p)
427
439
  });
428
- const scanner = new oxide.Scanner({ sources: compiler.sources });
440
+ const scanner = new oxide.Scanner({ sources: compiler2.sources });
429
441
  const candidates = scanner.scan();
430
442
  return {
431
- css: compiler.build(candidates),
443
+ css: compiler2.build(candidates),
432
444
  dependencies: [...dependencies, ...scanner.files]
433
445
  };
434
446
  }
@@ -614,6 +626,215 @@ var init_assets = __esm({
614
626
  }
615
627
  });
616
628
 
629
+ // src/core/transformer.ts
630
+ function shouldTransform(id) {
631
+ return TS_EXTENSIONS.test(id) || JSX_EXTENSIONS.test(id) || JS_EXTENSIONS.test(id) && false;
632
+ }
633
+ function transformCode(filename, code, options = {}) {
634
+ const isTS = TS_EXTENSIONS.test(filename) || /\.tsx$/.test(filename);
635
+ const isJSX = JSX_EXTENSIONS.test(filename);
636
+ const result = (0, import_oxc_transform.transformSync)(filename, code, {
637
+ typescript: isTS ? {} : void 0,
638
+ jsx: isJSX || /\.tsx$/.test(filename) ? {
639
+ runtime: options.jsxRuntime ?? "automatic",
640
+ importSource: options.jsxImportSource ?? "react",
641
+ refresh: options.reactRefresh ?? false
642
+ } : void 0,
643
+ sourcemap: options.sourcemap ?? true
644
+ });
645
+ if (result.errors && result.errors.length > 0) {
646
+ const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
647
+ throw new Error(`OXC transform failed for ${filename}:
648
+ ${msg}`);
649
+ }
650
+ return {
651
+ code: result.code,
652
+ map: result.map ? JSON.stringify(result.map) : null
653
+ };
654
+ }
655
+ var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
656
+ var init_transformer = __esm({
657
+ "src/core/transformer.ts"() {
658
+ "use strict";
659
+ import_oxc_transform = require("oxc-transform");
660
+ JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
661
+ TS_EXTENSIONS = /\.(ts|mts|cts)$/;
662
+ JSX_EXTENSIONS = /\.(jsx|tsx)$/;
663
+ }
664
+ });
665
+
666
+ // src/plugins/vue.ts
667
+ async function loadVueCompiler() {
668
+ if (compiler) return compiler;
669
+ try {
670
+ compiler = await import("@vue/compiler-sfc");
671
+ return compiler;
672
+ } catch {
673
+ return null;
674
+ }
675
+ }
676
+ function vuePlugin(config) {
677
+ const isDev = config.command === "serve";
678
+ const descriptorCache = /* @__PURE__ */ new Map();
679
+ return {
680
+ name: "nasti:vue",
681
+ enforce: "pre",
682
+ async resolveId(source) {
683
+ if (VUE_QUERY_RE.test(source)) {
684
+ return source;
685
+ }
686
+ return null;
687
+ },
688
+ async transform(code, id) {
689
+ if (!VUE_FILE_RE.test(id) && !VUE_QUERY_RE.test(id)) return null;
690
+ const sfc = await loadVueCompiler();
691
+ if (!sfc) {
692
+ console.warn("[nasti:vue] @vue/compiler-sfc not found. Install it: npm install @vue/compiler-sfc");
693
+ return null;
694
+ }
695
+ if (VUE_QUERY_RE.test(id)) {
696
+ return handleVueSubBlock(id, sfc, descriptorCache, config);
697
+ }
698
+ const { descriptor, errors } = sfc.parse(code, { filename: id });
699
+ if (errors.length) {
700
+ console.error(`[nasti:vue] Parse error in ${id}:`, errors[0].message);
701
+ return null;
702
+ }
703
+ descriptorCache.set(id, descriptor);
704
+ const scopeId = hashId(id);
705
+ let scriptCode = "";
706
+ if (descriptor.script || descriptor.scriptSetup) {
707
+ const compiled = sfc.compileScript(descriptor, {
708
+ id: scopeId,
709
+ isProd: !isDev,
710
+ inlineTemplate: true,
711
+ // 让 compileScript 产出 `const __sfc__ = ...`(而非默认的 `export default {...}`)。
712
+ // 否则下方追加的 `__sfc__.render` / `__sfc__.__scopeId` / HMR 记录会引用一个
713
+ // 不存在的 `__sfc__`,并与 compileScript 自带的 `export default` 形成双重默认导出。
714
+ genDefaultAs: "__sfc__"
715
+ });
716
+ scriptCode = compiled.content;
717
+ }
718
+ let templateCode = "";
719
+ if (descriptor.template && !descriptor.scriptSetup) {
720
+ const compiled = sfc.compileTemplate({
721
+ source: descriptor.template.content,
722
+ filename: id,
723
+ id: scopeId,
724
+ compilerOptions: { scopeId: `data-v-${scopeId}` }
725
+ });
726
+ templateCode = compiled.code;
727
+ }
728
+ let output = scriptCode || "const __sfc__ = {}";
729
+ if (templateCode) {
730
+ output += `
731
+ ${templateCode}
732
+ `;
733
+ output += `
734
+ __sfc__.render = render
735
+ `;
736
+ }
737
+ if (descriptor.styles.length > 0) {
738
+ for (let i = 0; i < descriptor.styles.length; i++) {
739
+ const style = descriptor.styles[i];
740
+ const lang2 = style.lang ?? "css";
741
+ output += `
742
+ import "${id}?vue&type=style&index=${i}&lang=${lang2}"
743
+ `;
744
+ }
745
+ }
746
+ output += `
747
+ __sfc__.__scopeId = "data-v-${scopeId}"
748
+ `;
749
+ if (isDev) {
750
+ output += `
751
+ __sfc__.__hmrId = ${JSON.stringify(scopeId)}
752
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
753
+ __VUE_HMR_RUNTIME__.createRecord(__sfc__.__hmrId, __sfc__)
754
+ }
755
+ if (import.meta.hot) {
756
+ import.meta.hot.accept((mod) => {
757
+ if (!mod) return
758
+ const { default: updated } = mod
759
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
760
+ __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render)
761
+ }
762
+ })
763
+ }
764
+ `;
765
+ }
766
+ output += `
767
+ export default __sfc__
768
+ `;
769
+ const lang = descriptor.scriptSetup?.lang ?? descriptor.script?.lang;
770
+ if (lang === "ts") {
771
+ const transpiled = transformCode(`${id}.ts`, output, { sourcemap: false });
772
+ return { code: transpiled.code };
773
+ }
774
+ return { code: output };
775
+ },
776
+ handleHotUpdate(ctx) {
777
+ const { file, modules } = ctx;
778
+ if (VUE_FILE_RE.test(file)) {
779
+ for (const mod of modules) {
780
+ mod.isSelfAccepting = true;
781
+ }
782
+ descriptorCache.delete(file);
783
+ }
784
+ return modules;
785
+ }
786
+ };
787
+ }
788
+ async function handleVueSubBlock(id, sfc, cache, config) {
789
+ const match = id.match(/(.+\.vue)\?vue&type=(\w+)(?:&index=(\d+))?(?:&lang=(\w+))?/);
790
+ if (!match) return null;
791
+ const [, filePath, type, indexStr, lang] = match;
792
+ const descriptor = cache.get(filePath);
793
+ if (!descriptor) return null;
794
+ if (type === "style") {
795
+ const index = parseInt(indexStr ?? "0", 10);
796
+ const style = descriptor.styles[index];
797
+ if (!style) return null;
798
+ const scopeId = hashId(filePath);
799
+ const result = await sfc.compileStyleAsync({
800
+ source: style.content,
801
+ filename: filePath,
802
+ id: `data-v-${scopeId}`,
803
+ scoped: style.scoped ?? false
804
+ });
805
+ const cssCode = JSON.stringify(result.code);
806
+ return {
807
+ code: `
808
+ const css = ${cssCode};
809
+ const style = document.createElement('style');
810
+ style.setAttribute('data-v-${scopeId}', '');
811
+ style.textContent = css;
812
+ document.head.appendChild(style);
813
+
814
+ if (import.meta.hot) {
815
+ import.meta.hot.accept();
816
+ import.meta.hot.prune(() => style.remove());
817
+ }
818
+ `
819
+ };
820
+ }
821
+ return null;
822
+ }
823
+ function hashId(filename) {
824
+ return import_node_crypto2.default.createHash("sha256").update(filename).digest("hex").slice(0, 8);
825
+ }
826
+ var import_node_crypto2, VUE_FILE_RE, VUE_QUERY_RE, compiler;
827
+ var init_vue = __esm({
828
+ "src/plugins/vue.ts"() {
829
+ "use strict";
830
+ import_node_crypto2 = __toESM(require("crypto"), 1);
831
+ init_transformer();
832
+ VUE_FILE_RE = /\.vue$/;
833
+ VUE_QUERY_RE = /\.vue\?vue&type=(script|template|style)(&index=\d+)?(&lang=\w+)?/;
834
+ compiler = null;
835
+ }
836
+ });
837
+
617
838
  // src/plugins/html.ts
618
839
  function htmlPlugin(config) {
619
840
  return {
@@ -697,43 +918,6 @@ window.__vite_plugin_react_preamble_installed__ = true;
697
918
  }
698
919
  });
699
920
 
700
- // src/core/transformer.ts
701
- function shouldTransform(id) {
702
- return TS_EXTENSIONS.test(id) || JSX_EXTENSIONS.test(id) || JS_EXTENSIONS.test(id) && false;
703
- }
704
- function transformCode(filename, code, options = {}) {
705
- const isTS = TS_EXTENSIONS.test(filename) || /\.tsx$/.test(filename);
706
- const isJSX = JSX_EXTENSIONS.test(filename);
707
- const result = (0, import_oxc_transform.transformSync)(filename, code, {
708
- typescript: isTS ? {} : void 0,
709
- jsx: isJSX || /\.tsx$/.test(filename) ? {
710
- runtime: options.jsxRuntime ?? "automatic",
711
- importSource: options.jsxImportSource ?? "react",
712
- refresh: options.reactRefresh ?? false
713
- } : void 0,
714
- sourcemap: options.sourcemap ?? true
715
- });
716
- if (result.errors && result.errors.length > 0) {
717
- const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
718
- throw new Error(`OXC transform failed for ${filename}:
719
- ${msg}`);
720
- }
721
- return {
722
- code: result.code,
723
- map: result.map ? JSON.stringify(result.map) : null
724
- };
725
- }
726
- var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
727
- var init_transformer = __esm({
728
- "src/core/transformer.ts"() {
729
- "use strict";
730
- import_oxc_transform = require("oxc-transform");
731
- JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
732
- TS_EXTENSIONS = /\.(ts|mts|cts)$/;
733
- JSX_EXTENSIONS = /\.(jsx|tsx)$/;
734
- }
735
- });
736
-
737
921
  // src/core/env.ts
738
922
  function loadEnv(mode, root, prefixes) {
739
923
  const envFiles = [
@@ -924,7 +1108,7 @@ __export(build_exports, {
924
1108
  async function build(inlineConfig = {}) {
925
1109
  const config = await resolveConfig(inlineConfig, "build");
926
1110
  const startTime = performance.now();
927
- console.log(import_picocolors.default.cyan("\n\u{1F528} nasti build") + import_picocolors.default.dim(` v${"1.6.5"}`));
1111
+ console.log(import_picocolors.default.cyan("\n\u{1F528} nasti build") + import_picocolors.default.dim(` v${"1.7.1"}`));
928
1112
  console.log(import_picocolors.default.dim(` root: ${config.root}`));
929
1113
  console.log(import_picocolors.default.dim(` mode: ${config.mode}`));
930
1114
  const outDir = import_node_path8.default.resolve(config.root, config.build.outDir);
@@ -957,6 +1141,7 @@ async function build(inlineConfig = {}) {
957
1141
  throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
958
1142
  }
959
1143
  const builtinPlugins = [
1144
+ ...config.framework === "vue" ? [vuePlugin(config)] : [],
960
1145
  resolvePlugin(config),
961
1146
  cssPlugin(config),
962
1147
  assetsPlugin(config)
@@ -978,11 +1163,17 @@ async function build(inlineConfig = {}) {
978
1163
  };
979
1164
  const env = loadEnv(config.mode, config.root, config.envPrefix);
980
1165
  const envDefine = buildEnvDefine(env, config.mode);
981
- const existingTransform = config.build.rolldownOptions?.transform;
982
- const mergedDefine = { ...existingTransform?.define ?? {}, ...envDefine };
1166
+ const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
1167
+ const vueDefine = config.framework === "vue" ? {
1168
+ __VUE_OPTIONS_API__: "true",
1169
+ __VUE_PROD_DEVTOOLS__: "false",
1170
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false"
1171
+ } : {};
1172
+ const mergedDefine = { ...vueDefine, ...userTransform?.define ?? {}, ...envDefine };
983
1173
  const bundle = await (0, import_rolldown.rolldown)({
1174
+ ...restInputOptions,
984
1175
  input: entryPoints,
985
- transform: { ...existingTransform, define: mergedDefine },
1176
+ transform: { ...userTransform, define: mergedDefine },
986
1177
  plugins: [
987
1178
  oxcTransformPlugin,
988
1179
  // 转换 Nasti 插件为 Rolldown 插件格式
@@ -998,17 +1189,19 @@ async function build(inlineConfig = {}) {
998
1189
  // manifest/SW writers) rely on for final-stage artifact emission.
999
1190
  closeBundle: p.closeBundle
1000
1191
  }))
1001
- ],
1002
- ...config.build.rolldownOptions
1192
+ ]
1003
1193
  });
1004
1194
  const { output } = await bundle.write({
1005
- dir: outDir,
1006
1195
  format: "esm",
1007
1196
  sourcemap: !!config.build.sourcemap,
1008
1197
  minify: !!config.build.minify,
1009
1198
  entryFileNames: "assets/[name].[hash].js",
1010
1199
  chunkFileNames: "assets/[name].[hash].js",
1011
- assetFileNames: "assets/[name].[hash][extname]"
1200
+ assetFileNames: "assets/[name].[hash][extname]",
1201
+ // 用户可覆盖默认输出:代码拆分(advancedChunks / codeSplitting)、chunk 命名等
1202
+ ...userOutput,
1203
+ // dir 始终由 Nasti 掌管 —— 下方 HTML 改写依赖固定的产物目录,故放在最后强制生效
1204
+ dir: outDir
1012
1205
  });
1013
1206
  await bundle.close();
1014
1207
  await pluginContainer.buildEnd();
@@ -1072,6 +1265,7 @@ var init_build = __esm({
1072
1265
  init_resolve();
1073
1266
  init_css();
1074
1267
  init_assets();
1268
+ init_vue();
1075
1269
  init_html();
1076
1270
  init_transformer();
1077
1271
  init_env();
@@ -2074,6 +2268,7 @@ __export(server_exports, {
2074
2268
  async function createServer(inlineConfig = {}) {
2075
2269
  const config = await resolveConfig(inlineConfig, "serve");
2076
2270
  const allPlugins = [
2271
+ ...config.framework === "vue" ? [vuePlugin(config)] : [],
2077
2272
  resolvePlugin(config),
2078
2273
  cssPlugin(config),
2079
2274
  assetsPlugin(config),
@@ -2134,7 +2329,7 @@ async function createServer(inlineConfig = {}) {
2134
2329
  const localUrl = `http://localhost:${actualPort}`;
2135
2330
  const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
2136
2331
  console.log();
2137
- console.log(import_picocolors3.default.cyan(" nasti dev server") + import_picocolors3.default.dim(` v${"1.6.5"}`));
2332
+ console.log(import_picocolors3.default.cyan(" nasti dev server") + import_picocolors3.default.dim(` v${"1.7.1"}`));
2138
2333
  console.log();
2139
2334
  console.log(` ${import_picocolors3.default.green(">")} Local: ${import_picocolors3.default.cyan(localUrl)}`);
2140
2335
  if (networkUrl) {
@@ -2210,6 +2405,7 @@ var init_server = __esm({
2210
2405
  init_resolve();
2211
2406
  init_css();
2212
2407
  init_assets();
2408
+ init_vue();
2213
2409
  init_html();
2214
2410
  }
2215
2411
  });
@@ -2278,7 +2474,7 @@ async function buildElectron(inlineConfig = {}) {
2278
2474
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
2279
2475
  const startTime = performance.now();
2280
2476
  assertElectronVersion(config);
2281
- console.log(import_picocolors2.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors2.default.dim(` v${"1.6.5"}`));
2477
+ console.log(import_picocolors2.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors2.default.dim(` v${"1.7.1"}`));
2282
2478
  console.log(import_picocolors2.default.dim(` root: ${config.root}`));
2283
2479
  console.log(import_picocolors2.default.dim(` mode: ${config.mode}`));
2284
2480
  console.log(import_picocolors2.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -2356,21 +2552,23 @@ async function bundleNode(config, entry, opts) {
2356
2552
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
2357
2553
  }
2358
2554
  };
2359
- const existingTransform = config.build.rolldownOptions?.transform;
2360
- const mergedDefine = { ...existingTransform?.define ?? {}, ...envDefine };
2555
+ const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
2556
+ const mergedDefine = { ...userTransform?.define ?? {}, ...envDefine };
2361
2557
  const bundle = await (0, import_rolldown2.rolldown)({
2558
+ ...restInputOptions,
2362
2559
  input: entry,
2363
- transform: { ...existingTransform, define: mergedDefine },
2364
2560
  platform: "node",
2365
- plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)],
2366
- ...config.build.rolldownOptions
2561
+ transform: { ...userTransform, define: mergedDefine },
2562
+ plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
2367
2563
  });
2368
2564
  import_node_fs7.default.mkdirSync(import_node_path9.default.dirname(opts.outFile), { recursive: true });
2369
2565
  await bundle.write({
2370
- file: opts.outFile,
2371
- format: opts.format === "cjs" ? "cjs" : "esm",
2372
2566
  sourcemap: !!config.build.sourcemap,
2373
2567
  minify: !!config.build.minify,
2568
+ // 允许用户微调 output;但主进程 / preload 的单文件约束由下方键强制保证
2569
+ ...userOutput,
2570
+ file: opts.outFile,
2571
+ format: opts.format === "cjs" ? "cjs" : "esm",
2374
2572
  codeSplitting: false
2375
2573
  });
2376
2574
  await bundle.close();
@@ -2427,7 +2625,7 @@ async function startElectronDev(inlineConfig = {}) {
2427
2625
  const { noSpawn, ...rest } = inlineConfig;
2428
2626
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
2429
2627
  warnElectronVersion(config);
2430
- console.log(import_picocolors4.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors4.default.dim(` v${"1.6.5"}`));
2628
+ console.log(import_picocolors4.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors4.default.dim(` v${"1.7.1"}`));
2431
2629
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2432
2630
  const server = await createServer2({ ...rest, target: "electron" });
2433
2631
  await server.listen();
@@ -2613,7 +2811,7 @@ function warnElectronVersion(config) {
2613
2811
  // src/plugins/monaco-editor.ts
2614
2812
  var import_node_path14 = __toESM(require("path"), 1);
2615
2813
  var import_node_fs11 = __toESM(require("fs"), 1);
2616
- var import_node_crypto2 = __toESM(require("crypto"), 1);
2814
+ var import_node_crypto3 = __toESM(require("crypto"), 1);
2617
2815
  var import_node_module6 = require("module");
2618
2816
  var DEFAULT_WORKERS = {
2619
2817
  editorWorkerService: "monaco-editor/esm/vs/editor/editor.worker",
@@ -2727,7 +2925,7 @@ function monacoEditorPlugin(options = {}) {
2727
2925
  configResolved(config) {
2728
2926
  resolvedConfig = config;
2729
2927
  const version = readMonacoVersion(config.root);
2730
- const key = import_node_crypto2.default.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
2928
+ const key = import_node_crypto3.default.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
2731
2929
  cacheDir = import_node_path14.default.resolve(config.root, "node_modules/.nasti/monaco", key);
2732
2930
  },
2733
2931
  async configureServer(server) {