@nasti-toolchain/nasti 1.6.4 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -88,6 +88,31 @@ export default defineConfig({
88
88
  })
89
89
  ```
90
90
 
91
+ ### 生产构建:手动代码拆分 & Tree-shaking
92
+
93
+ `build.rolldownOptions` 透传 Rolldown 底层选项:input 侧(如 `treeshake`、`resolve`、`external`)合并进打包,`output` 合并进产物写出阶段,用于手动控制 vendor 分包与 Tree-shaking。`input` / `plugins` 由 Nasti 接管,`output.dir` 始终由 `build.outDir` 决定。
94
+
95
+ ```ts
96
+ export default defineConfig({
97
+ build: {
98
+ rolldownOptions: {
99
+ // Tree-shaking(input 选项)
100
+ treeshake: { moduleSideEffects: [{ test: /\/barrel\//, sideEffects: false }] },
101
+ // 代码拆分(output 选项)
102
+ output: {
103
+ advancedChunks: {
104
+ groups: [
105
+ { name: 'react-vendor', test: /node_modules[\\/]react/, priority: 20 },
106
+ { name: 'vendor', test: /node_modules/, priority: 10 },
107
+ ],
108
+ },
109
+ chunkFileNames: 'assets/chunks/[name].[hash].js',
110
+ },
111
+ },
112
+ },
113
+ })
114
+ ```
115
+
91
116
  ## CLI
92
117
 
93
118
  ```bash
package/dist/cli.cjs CHANGED
@@ -56,7 +56,8 @@ var init_defaults = __esm({
56
56
  sourcemap: false,
57
57
  target: "es2022",
58
58
  rolldownOptions: {},
59
- emptyOutDir: true
59
+ emptyOutDir: true,
60
+ css: {}
60
61
  };
61
62
  defaultElectron = {
62
63
  main: "src/electron/main.ts",
@@ -1585,20 +1586,29 @@ var init_hmr = __esm({
1585
1586
  function resolvePlugin(config) {
1586
1587
  const { alias, extensions } = config.resolve;
1587
1588
  const require2 = (0, import_node_module2.createRequire)(import_node_path6.default.resolve(config.root, "package.json"));
1589
+ const aliasEntries = Object.entries(alias).sort(
1590
+ ([a], [b]) => b.length - a.length
1591
+ );
1588
1592
  return {
1589
1593
  name: "nasti:resolve",
1590
1594
  enforce: "pre",
1591
1595
  resolveId(source, importer) {
1592
- for (const [key, value] of Object.entries(alias)) {
1596
+ for (const [key, value] of aliasEntries) {
1593
1597
  if (source === key || source.startsWith(key + "/")) {
1594
- source = source.replace(key, value);
1595
- if (!import_node_path6.default.isAbsolute(source)) {
1596
- source = import_node_path6.default.resolve(config.root, source);
1597
- }
1598
+ const aliasBase = resolveAliasTarget2(value, config.root);
1599
+ const sub = source.slice(key.length).replace(/^\//, "");
1600
+ const target = sub ? import_node_path6.default.join(aliasBase, sub) : aliasBase;
1601
+ const resolved = tryResolveFile(target, extensions);
1602
+ if (resolved) return resolved;
1598
1603
  break;
1599
1604
  }
1600
1605
  }
1601
- if (import_node_path6.default.isAbsolute(source)) {
1606
+ if (source.startsWith("/") && !source.startsWith("//")) {
1607
+ const rootRelative = import_node_path6.default.join(config.root, source.slice(1));
1608
+ const resolved = tryResolveFile(rootRelative, extensions);
1609
+ if (resolved) return resolved;
1610
+ }
1611
+ if (import_node_path6.default.isAbsolute(source) && import_node_fs6.default.existsSync(source)) {
1602
1612
  const resolved = tryResolveFile(source, extensions);
1603
1613
  if (resolved) return resolved;
1604
1614
  }
@@ -1621,6 +1631,7 @@ function resolvePlugin(config) {
1621
1631
  return null;
1622
1632
  },
1623
1633
  load(id) {
1634
+ if (id.startsWith("\0")) return null;
1624
1635
  if (!import_node_fs6.default.existsSync(id)) return null;
1625
1636
  if (id.endsWith(".json")) {
1626
1637
  const content = import_node_fs6.default.readFileSync(id, "utf-8");
@@ -1630,6 +1641,11 @@ function resolvePlugin(config) {
1630
1641
  }
1631
1642
  };
1632
1643
  }
1644
+ function resolveAliasTarget2(value, root) {
1645
+ if (import_node_path6.default.isAbsolute(value) && import_node_fs6.default.existsSync(value)) return value;
1646
+ if (value.startsWith("/")) return import_node_path6.default.join(root, value.slice(1));
1647
+ return import_node_path6.default.resolve(root, value);
1648
+ }
1633
1649
  function tryResolveFile(file, extensions) {
1634
1650
  if (import_node_fs6.default.existsSync(file) && import_node_fs6.default.statSync(file).isFile()) {
1635
1651
  return file;
@@ -1729,8 +1745,8 @@ function cssPlugin(config) {
1729
1745
  cssSource = compiled.css;
1730
1746
  }
1731
1747
  const rewritten = rewriteCssUrls(cssSource, id, config.root);
1748
+ const escaped = JSON.stringify(rewritten);
1732
1749
  if (config.command === "serve") {
1733
- const escaped = JSON.stringify(rewritten);
1734
1750
  return {
1735
1751
  code: `
1736
1752
  const css = ${escaped};
@@ -1754,7 +1770,42 @@ export default css;
1754
1770
  `
1755
1771
  };
1756
1772
  }
1757
- return rewritten !== code ? { code: rewritten } : null;
1773
+ const cssConfig = config.build.css || {};
1774
+ const nonce = cssConfig.nonce;
1775
+ const emitCssFile = cssConfig.emitCssFile;
1776
+ if (emitCssFile) {
1777
+ const fileName = `assets/${import_node_path8.default.basename(id, ".css")}.css`;
1778
+ this.emitFile({
1779
+ type: "asset",
1780
+ fileName,
1781
+ source: rewritten
1782
+ });
1783
+ return {
1784
+ code: `
1785
+ const link = document.createElement('link');
1786
+ link.rel = 'stylesheet';
1787
+ link.href = ${JSON.stringify("/" + fileName)};
1788
+ document.head.appendChild(link);
1789
+
1790
+ export default ${escaped};
1791
+ `,
1792
+ moduleType: "js"
1793
+ };
1794
+ }
1795
+ const nonceAttr = nonce ? `style.setAttribute('nonce', ${JSON.stringify(nonce)});` : "";
1796
+ return {
1797
+ code: `
1798
+ const css = ${escaped};
1799
+ const style = document.createElement('style');
1800
+ style.setAttribute('data-nasti-css', ${JSON.stringify(id)});
1801
+ ${nonceAttr}
1802
+ style.textContent = css;
1803
+ document.head.appendChild(style);
1804
+
1805
+ export default css;
1806
+ `,
1807
+ moduleType: "js"
1808
+ };
1758
1809
  }
1759
1810
  };
1760
1811
  }
@@ -1915,7 +1966,7 @@ async function createServer(inlineConfig = {}) {
1915
1966
  const localUrl = `http://localhost:${actualPort}`;
1916
1967
  const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
1917
1968
  console.log();
1918
- console.log(import_picocolors.default.cyan(" nasti dev server") + import_picocolors.default.dim(` v${"1.6.4"}`));
1969
+ console.log(import_picocolors.default.cyan(" nasti dev server") + import_picocolors.default.dim(` v${"1.7.0"}`));
1919
1970
  console.log();
1920
1971
  console.log(` ${import_picocolors.default.green(">")} Local: ${import_picocolors.default.cyan(localUrl)}`);
1921
1972
  if (networkUrl) {
@@ -2042,7 +2093,7 @@ __export(build_exports, {
2042
2093
  async function build(inlineConfig = {}) {
2043
2094
  const config = await resolveConfig(inlineConfig, "build");
2044
2095
  const startTime = performance.now();
2045
- console.log(import_picocolors2.default.cyan("\n\u{1F528} nasti build") + import_picocolors2.default.dim(` v${"1.6.4"}`));
2096
+ console.log(import_picocolors2.default.cyan("\n\u{1F528} nasti build") + import_picocolors2.default.dim(` v${"1.7.0"}`));
2046
2097
  console.log(import_picocolors2.default.dim(` root: ${config.root}`));
2047
2098
  console.log(import_picocolors2.default.dim(` mode: ${config.mode}`));
2048
2099
  const outDir = import_node_path11.default.resolve(config.root, config.build.outDir);
@@ -2096,9 +2147,12 @@ async function build(inlineConfig = {}) {
2096
2147
  };
2097
2148
  const env = loadEnv(config.mode, config.root, config.envPrefix);
2098
2149
  const envDefine = buildEnvDefine(env, config.mode);
2150
+ const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
2151
+ const mergedDefine = { ...userTransform?.define ?? {}, ...envDefine };
2099
2152
  const bundle = await (0, import_rolldown.rolldown)({
2153
+ ...restInputOptions,
2100
2154
  input: entryPoints,
2101
- define: envDefine,
2155
+ transform: { ...userTransform, define: mergedDefine },
2102
2156
  plugins: [
2103
2157
  oxcTransformPlugin,
2104
2158
  // 转换 Nasti 插件为 Rolldown 插件格式
@@ -2114,17 +2168,19 @@ async function build(inlineConfig = {}) {
2114
2168
  // manifest/SW writers) rely on for final-stage artifact emission.
2115
2169
  closeBundle: p.closeBundle
2116
2170
  }))
2117
- ],
2118
- ...config.build.rolldownOptions
2171
+ ]
2119
2172
  });
2120
2173
  const { output } = await bundle.write({
2121
- dir: outDir,
2122
2174
  format: "esm",
2123
2175
  sourcemap: !!config.build.sourcemap,
2124
2176
  minify: !!config.build.minify,
2125
2177
  entryFileNames: "assets/[name].[hash].js",
2126
2178
  chunkFileNames: "assets/[name].[hash].js",
2127
- assetFileNames: "assets/[name].[hash][extname]"
2179
+ assetFileNames: "assets/[name].[hash][extname]",
2180
+ // 用户可覆盖默认输出:代码拆分(advancedChunks / codeSplitting)、chunk 命名等
2181
+ ...userOutput,
2182
+ // dir 始终由 Nasti 掌管 —— 下方 HTML 改写依赖固定的产物目录,故放在最后强制生效
2183
+ dir: outDir
2128
2184
  });
2129
2185
  await bundle.close();
2130
2186
  await pluginContainer.buildEnd();
@@ -2207,7 +2263,7 @@ async function buildElectron(inlineConfig = {}) {
2207
2263
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
2208
2264
  const startTime = performance.now();
2209
2265
  assertElectronVersion(config);
2210
- console.log(import_picocolors3.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors3.default.dim(` v${"1.6.4"}`));
2266
+ console.log(import_picocolors3.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors3.default.dim(` v${"1.7.0"}`));
2211
2267
  console.log(import_picocolors3.default.dim(` root: ${config.root}`));
2212
2268
  console.log(import_picocolors3.default.dim(` mode: ${config.mode}`));
2213
2269
  console.log(import_picocolors3.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -2285,19 +2341,23 @@ async function bundleNode(config, entry, opts) {
2285
2341
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
2286
2342
  }
2287
2343
  };
2344
+ const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
2345
+ const mergedDefine = { ...userTransform?.define ?? {}, ...envDefine };
2288
2346
  const bundle = await (0, import_rolldown2.rolldown)({
2347
+ ...restInputOptions,
2289
2348
  input: entry,
2290
- define: envDefine,
2291
2349
  platform: "node",
2292
- plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)],
2293
- ...config.build.rolldownOptions
2350
+ transform: { ...userTransform, define: mergedDefine },
2351
+ plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
2294
2352
  });
2295
2353
  import_node_fs9.default.mkdirSync(import_node_path12.default.dirname(opts.outFile), { recursive: true });
2296
2354
  await bundle.write({
2297
- file: opts.outFile,
2298
- format: opts.format === "cjs" ? "cjs" : "esm",
2299
2355
  sourcemap: !!config.build.sourcemap,
2300
2356
  minify: !!config.build.minify,
2357
+ // 允许用户微调 output;但主进程 / preload 的单文件约束由下方键强制保证
2358
+ ...userOutput,
2359
+ file: opts.outFile,
2360
+ format: opts.format === "cjs" ? "cjs" : "esm",
2301
2361
  codeSplitting: false
2302
2362
  });
2303
2363
  await bundle.close();
@@ -2359,7 +2419,7 @@ async function startElectronDev(inlineConfig = {}) {
2359
2419
  const { noSpawn, ...rest } = inlineConfig;
2360
2420
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
2361
2421
  warnElectronVersion(config);
2362
- console.log(import_picocolors4.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors4.default.dim(` v${"1.6.4"}`));
2422
+ console.log(import_picocolors4.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors4.default.dim(` v${"1.7.0"}`));
2363
2423
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2364
2424
  const server = await createServer2({ ...rest, target: "electron" });
2365
2425
  await server.listen();
@@ -2694,6 +2754,6 @@ cli.command("preview [root]", "Preview production build").option("--port <port>"
2694
2754
  }
2695
2755
  });
2696
2756
  cli.help();
2697
- cli.version("1.6.4");
2757
+ cli.version("1.7.0");
2698
2758
  cli.parse();
2699
2759
  //# sourceMappingURL=cli.cjs.map