@nasti-toolchain/nasti 1.6.1 → 1.6.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/index.d.cts CHANGED
@@ -99,6 +99,12 @@ interface NastiPlugin {
99
99
  }) => boolean);
100
100
  buildStart?: (this: PluginContext) => void | Promise<void>;
101
101
  buildEnd?: (this: PluginContext, error?: Error) => void | Promise<void>;
102
+ /**
103
+ * Called once after `bundle.close()` in production builds, mirroring Rollup/Vite semantics.
104
+ * Plugins use this to emit final-stage artifacts that depend on the bundle being fully written
105
+ * (PWA manifests, service workers, sitemaps, etc.). Not invoked in dev.
106
+ */
107
+ closeBundle?: (this: PluginContext, error?: Error) => void | Promise<void>;
102
108
  resolveId?: (this: PluginContext, source: string, importer: string | undefined, options: ResolveIdOptions) => ResolveIdResult | Promise<ResolveIdResult>;
103
109
  load?: (this: PluginContext, id: string) => LoadResult | Promise<LoadResult>;
104
110
  transform?: (this: PluginContext, code: string, id: string) => TransformResult | Promise<TransformResult>;
package/dist/index.d.ts CHANGED
@@ -99,6 +99,12 @@ interface NastiPlugin {
99
99
  }) => boolean);
100
100
  buildStart?: (this: PluginContext) => void | Promise<void>;
101
101
  buildEnd?: (this: PluginContext, error?: Error) => void | Promise<void>;
102
+ /**
103
+ * Called once after `bundle.close()` in production builds, mirroring Rollup/Vite semantics.
104
+ * Plugins use this to emit final-stage artifacts that depend on the bundle being fully written
105
+ * (PWA manifests, service workers, sitemaps, etc.). Not invoked in dev.
106
+ */
107
+ closeBundle?: (this: PluginContext, error?: Error) => void | Promise<void>;
102
108
  resolveId?: (this: PluginContext, source: string, importer: string | undefined, options: ResolveIdOptions) => ResolveIdResult | Promise<ResolveIdResult>;
103
109
  load?: (this: PluginContext, id: string) => LoadResult | Promise<LoadResult>;
104
110
  transform?: (this: PluginContext, code: string, id: string) => TransformResult | Promise<TransformResult>;
package/dist/index.js CHANGED
@@ -793,7 +793,7 @@ import pc from "picocolors";
793
793
  async function build(inlineConfig = {}) {
794
794
  const config = await resolveConfig(inlineConfig, "build");
795
795
  const startTime = performance.now();
796
- console.log(pc.cyan("\n\u{1F528} nasti build") + pc.dim(` v${"1.6.1"}`));
796
+ console.log(pc.cyan("\n\u{1F528} nasti build") + pc.dim(` v${"1.6.3"}`));
797
797
  console.log(pc.dim(` root: ${config.root}`));
798
798
  console.log(pc.dim(` mode: ${config.mode}`));
799
799
  const outDir = path7.resolve(config.root, config.build.outDir);
@@ -859,7 +859,11 @@ async function build(inlineConfig = {}) {
859
859
  load: p.load,
860
860
  transform: p.transform,
861
861
  buildStart: p.buildStart,
862
- buildEnd: p.buildEnd
862
+ buildEnd: p.buildEnd,
863
+ // Forward `closeBundle` to Rolldown — it invokes the hook during
864
+ // `bundle.close()` below. This is the hook Vite plugins (e.g. PWA
865
+ // manifest/SW writers) rely on for final-stage artifact emission.
866
+ closeBundle: p.closeBundle
863
867
  }))
864
868
  ],
865
869
  ...config.build.rolldownOptions
@@ -989,6 +993,19 @@ var init_module_graph = __esm({
989
993
  }
990
994
  mods.add(mod);
991
995
  }
996
+ /**
997
+ * Reindex a module under a plugin-provided canonical id (e.g. a `\0virtual:foo`
998
+ * id returned from `resolveId`). Plugins look up their own virtual modules via
999
+ * `getModuleById(RESOLVED_ID)` to invalidate them on watcher events; without
1000
+ * this remap they'd never find the node because `ensureEntryFromUrl` keys by
1001
+ * the public URL only.
1002
+ */
1003
+ setModuleId(mod, id) {
1004
+ if (mod.id === id) return;
1005
+ this.idToModuleMap.delete(mod.id);
1006
+ mod.id = id;
1007
+ this.idToModuleMap.set(id, mod);
1008
+ }
992
1009
  /** 更新模块依赖关系 */
993
1010
  updateModuleImports(mod, importedIds) {
994
1011
  for (const imported of mod.importedModules) {
@@ -1104,7 +1121,7 @@ __export(middleware_exports, {
1104
1121
  import path9 from "path";
1105
1122
  import fs8 from "fs";
1106
1123
  import { createRequire as createRequire2 } from "module";
1107
- import { fileURLToPath } from "url";
1124
+ import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
1108
1125
  function getReactRefreshRuntimeEsm() {
1109
1126
  if (__refreshRuntimeCache) return __refreshRuntimeCache;
1110
1127
  let cjsPath;
@@ -1259,6 +1276,16 @@ async function transformRequest(url, ctx) {
1259
1276
  if (cleanReqUrl === "/@react-refresh") {
1260
1277
  return { code: getReactRefreshRuntimeEsm() };
1261
1278
  }
1279
+ if (cleanReqUrl.startsWith("/@modules/")) {
1280
+ const spec = cleanReqUrl.slice("/@modules/".length);
1281
+ const virtual = await loadVirtualModule(spec, ctx);
1282
+ if (virtual) {
1283
+ const mod2 = await moduleGraph.ensureEntryFromUrl(url);
1284
+ moduleGraph.setModuleId(mod2, virtual.id);
1285
+ mod2.transformResult = virtual.result;
1286
+ return virtual.result;
1287
+ }
1288
+ }
1262
1289
  const filePath = resolveUrlToFile(url, config.root);
1263
1290
  if (!filePath || !fs8.existsSync(filePath)) return null;
1264
1291
  const mod = await moduleGraph.ensureEntryFromUrl(url);
@@ -1305,6 +1332,28 @@ async function transformRequest(url, ctx) {
1305
1332
  mod.transformResult = transformResult;
1306
1333
  return transformResult;
1307
1334
  }
1335
+ async function loadVirtualModule(spec, ctx) {
1336
+ const { config, pluginContainer } = ctx;
1337
+ const resolved = await pluginContainer.resolveId(spec);
1338
+ if (resolved == null) return null;
1339
+ const resolvedId = typeof resolved === "string" ? resolved : resolved.id;
1340
+ const looksVirtual = resolvedId.startsWith("\0") || !fs8.existsSync(resolvedId);
1341
+ if (!looksVirtual) return null;
1342
+ const loadResult = await pluginContainer.load(resolvedId);
1343
+ if (loadResult == null) return null;
1344
+ let code = typeof loadResult === "string" ? loadResult : loadResult.code;
1345
+ const transformed = await pluginContainer.transform(code, resolvedId);
1346
+ if (transformed != null) {
1347
+ code = typeof transformed === "string" ? transformed : transformed.code;
1348
+ }
1349
+ code = replaceEnvInCode(code, ctx.envDefine ?? buildEnvDefine(
1350
+ loadEnv(config.mode, config.root, config.envPrefix),
1351
+ config.mode
1352
+ ));
1353
+ const anchor = path9.join(config.root, "__nasti_virtual__.ts");
1354
+ code = rewriteImports(code, config, anchor);
1355
+ return { id: resolvedId, result: { code } };
1356
+ }
1308
1357
  async function bundlePackageAsEsm(entryFile) {
1309
1358
  if (!esmBundleCache.has(entryFile)) {
1310
1359
  esmBundleCache.set(entryFile, doBundlePackage(entryFile));
@@ -1312,6 +1361,8 @@ async function bundlePackageAsEsm(entryFile) {
1312
1361
  return esmBundleCache.get(entryFile);
1313
1362
  }
1314
1363
  async function doBundlePackage(entryFile) {
1364
+ const shim = await tryGenerateSubpathShim(entryFile);
1365
+ if (shim != null) return shim;
1315
1366
  const { rolldown: rolldown4 } = await import("rolldown");
1316
1367
  const bundle = await rolldown4({
1317
1368
  input: entryFile,
@@ -1341,6 +1392,103 @@ async function doBundlePackage(entryFile) {
1341
1392
  }
1342
1393
  return code;
1343
1394
  }
1395
+ async function tryGenerateSubpathShim(entryFile) {
1396
+ const NM = `${path9.sep}node_modules${path9.sep}`;
1397
+ if (!entryFile.includes(NM)) return null;
1398
+ let pkgDir = null;
1399
+ let pkgName = null;
1400
+ let dir = path9.dirname(entryFile);
1401
+ while (true) {
1402
+ const pkgJsonPath = path9.join(dir, "package.json");
1403
+ if (fs8.existsSync(pkgJsonPath)) {
1404
+ try {
1405
+ const pkg = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf-8"));
1406
+ if (typeof pkg?.name === "string" && pkg.name) {
1407
+ pkgDir = dir;
1408
+ pkgName = pkg.name;
1409
+ break;
1410
+ }
1411
+ } catch {
1412
+ }
1413
+ }
1414
+ const parent = path9.dirname(dir);
1415
+ if (parent === dir) return null;
1416
+ dir = parent;
1417
+ if (!dir.includes(NM)) return null;
1418
+ }
1419
+ if (!pkgDir || !pkgName) return null;
1420
+ const entryExt = path9.extname(entryFile);
1421
+ const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
1422
+ if (!mainEntry) return null;
1423
+ if (path9.resolve(mainEntry) === path9.resolve(entryFile)) return null;
1424
+ let mainNs;
1425
+ let subNs;
1426
+ try {
1427
+ mainNs = await import(pathToFileURL2(mainEntry).href);
1428
+ subNs = await import(pathToFileURL2(entryFile).href);
1429
+ } catch {
1430
+ return null;
1431
+ }
1432
+ if (!mainNs || typeof mainNs !== "object") return null;
1433
+ if (!subNs || typeof subNs !== "object") return null;
1434
+ const subKeys = Object.keys(subNs).filter(
1435
+ (k) => k !== "__esModule" && k !== "default" && VALID_IDENT.test(k)
1436
+ );
1437
+ if (subKeys.length === 0) return null;
1438
+ for (const k of subKeys) {
1439
+ if (!(k in mainNs)) return null;
1440
+ if (mainNs[k] !== subNs[k]) return null;
1441
+ }
1442
+ if ("default" in subNs) {
1443
+ if (!("default" in mainNs)) return null;
1444
+ if (mainNs["default"] !== subNs["default"]) return null;
1445
+ }
1446
+ const lines = [
1447
+ `// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
1448
+ `import * as __pkg from "/@modules/${pkgName}";`
1449
+ ];
1450
+ for (const k of subKeys) {
1451
+ lines.push(`export const ${k} = __pkg[${JSON.stringify(k)}];`);
1452
+ }
1453
+ if ("default" in subNs) {
1454
+ lines.push(`export default ("default" in __pkg ? __pkg["default"] : __pkg);`);
1455
+ }
1456
+ return lines.join("\n") + "\n";
1457
+ }
1458
+ function pickMainEntryByExtension(pkgDir, preferredExt) {
1459
+ const pkgJsonPath = path9.join(pkgDir, "package.json");
1460
+ let pkg;
1461
+ try {
1462
+ pkg = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf-8"));
1463
+ } catch {
1464
+ return null;
1465
+ }
1466
+ const candidates = [];
1467
+ const collectFromExportObject = (obj) => {
1468
+ if (!obj || typeof obj !== "object") return;
1469
+ for (const cond of ["import", "module", "default", "require", "node"]) {
1470
+ const v = obj[cond];
1471
+ if (typeof v === "string") candidates.push(v);
1472
+ else if (v && typeof v === "object") collectFromExportObject(v);
1473
+ }
1474
+ };
1475
+ const dot = pkg?.exports?.["."];
1476
+ if (typeof dot === "string") candidates.push(dot);
1477
+ else if (dot && typeof dot === "object") collectFromExportObject(dot);
1478
+ if (typeof pkg.module === "string") candidates.push(pkg.module);
1479
+ if (typeof pkg.main === "string") candidates.push(pkg.main);
1480
+ for (const cand of candidates) {
1481
+ if (path9.extname(cand) === preferredExt) {
1482
+ const full = path9.resolve(pkgDir, cand);
1483
+ if (fs8.existsSync(full)) return full;
1484
+ }
1485
+ }
1486
+ for (const cand of candidates) {
1487
+ const full = path9.resolve(pkgDir, cand);
1488
+ if (fs8.existsSync(full)) return full;
1489
+ }
1490
+ return null;
1491
+ }
1344
1492
  function rewriteExternalRequires(code) {
1345
1493
  const pkgs = /* @__PURE__ */ new Set();
1346
1494
  const re = /__require\(["']([^"']+)["']\)/g;
@@ -1851,7 +1999,7 @@ async function createServer(inlineConfig = {}) {
1851
1999
  const localUrl = `http://localhost:${actualPort}`;
1852
2000
  const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
1853
2001
  console.log();
1854
- console.log(pc3.cyan(" nasti dev server") + pc3.dim(` v${"1.6.1"}`));
2002
+ console.log(pc3.cyan(" nasti dev server") + pc3.dim(` v${"1.6.3"}`));
1855
2003
  console.log();
1856
2004
  console.log(` ${pc3.green(">")} Local: ${pc3.cyan(localUrl)}`);
1857
2005
  if (networkUrl) {
@@ -1975,7 +2123,7 @@ async function buildElectron(inlineConfig = {}) {
1975
2123
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
1976
2124
  const startTime = performance.now();
1977
2125
  assertElectronVersion(config);
1978
- console.log(pc2.cyan("\n\u26A1 nasti build (electron)") + pc2.dim(` v${"1.6.1"}`));
2126
+ console.log(pc2.cyan("\n\u26A1 nasti build (electron)") + pc2.dim(` v${"1.6.3"}`));
1979
2127
  console.log(pc2.dim(` root: ${config.root}`));
1980
2128
  console.log(pc2.dim(` mode: ${config.mode}`));
1981
2129
  console.log(pc2.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -2122,7 +2270,7 @@ async function startElectronDev(inlineConfig = {}) {
2122
2270
  const { noSpawn, ...rest } = inlineConfig;
2123
2271
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
2124
2272
  warnElectronVersion(config);
2125
- console.log(pc4.cyan("\n\u26A1 nasti electron dev") + pc4.dim(` v${"1.6.1"}`));
2273
+ console.log(pc4.cyan("\n\u26A1 nasti electron dev") + pc4.dim(` v${"1.6.3"}`));
2126
2274
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2127
2275
  const server = await createServer2({ ...rest, target: "electron" });
2128
2276
  await server.listen();