@nasti-toolchain/nasti 2.4.4 → 2.5.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/dist/index.cjs CHANGED
@@ -5,10 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __glob = (map) => (path20) => {
9
- var fn = map[path20];
8
+ var __glob = (map) => (path21) => {
9
+ var fn = map[path21];
10
10
  if (fn) return fn();
11
- throw new Error("Module not found in bundle: " + path20);
11
+ throw new Error("Module not found in bundle: " + path21);
12
12
  };
13
13
  var __esm = (fn, res) => function __init() {
14
14
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
40
 
41
41
  // src/config/defaults.ts
42
- var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaults;
42
+ var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaultReact, defaults;
43
43
  var init_defaults = __esm({
44
44
  "src/config/defaults.ts"() {
45
45
  "use strict";
@@ -92,12 +92,20 @@ var init_defaults = __esm({
92
92
  defaultExperimental = {
93
93
  bundledDev: false
94
94
  };
95
+ defaultReact = {
96
+ include: /\.[tj]sx?$/,
97
+ exclude: /node_modules/,
98
+ jsxImportSource: "react",
99
+ jsxRuntime: "automatic",
100
+ compiler: false
101
+ };
95
102
  defaults = {
96
103
  root: ".",
97
104
  base: "/",
98
105
  mode: "development",
99
106
  target: "web",
100
107
  framework: "auto",
108
+ react: defaultReact,
101
109
  resolve: defaultResolve,
102
110
  server: defaultServer,
103
111
  build: defaultBuild,
@@ -435,6 +443,13 @@ async function resolveConfig(inlineConfig = {}, command) {
435
443
  mode,
436
444
  target: merged.target ?? defaults.target,
437
445
  framework: (merged.framework ?? defaults.framework) === "auto" ? detectFramework(root) : merged.framework,
446
+ react: {
447
+ include: merged.react?.include ?? defaultReact.include,
448
+ exclude: merged.react?.exclude ?? defaultReact.exclude,
449
+ jsxImportSource: merged.react?.jsxImportSource ?? defaultReact.jsxImportSource,
450
+ jsxRuntime: merged.react?.jsxRuntime ?? defaultReact.jsxRuntime,
451
+ compiler: merged.react?.compiler === true ? {} : merged.react?.compiler ?? defaultReact.compiler
452
+ },
438
453
  command,
439
454
  resolve: {
440
455
  // tsconfig paths 优先级最低:tsconfig < defaults < user config
@@ -873,27 +888,27 @@ var require_process = __commonJS({
873
888
  var require_filesystem = __commonJS({
874
889
  "node_modules/detect-libc/lib/filesystem.js"(exports2, module2) {
875
890
  "use strict";
876
- var fs15 = require("fs");
891
+ var fs16 = require("fs");
877
892
  var LDD_PATH = "/usr/bin/ldd";
878
893
  var SELF_PATH = "/proc/self/exe";
879
894
  var MAX_LENGTH = 2048;
880
- var readFileSync = (path20) => {
881
- const fd = fs15.openSync(path20, "r");
895
+ var readFileSync = (path21) => {
896
+ const fd = fs16.openSync(path21, "r");
882
897
  const buffer = Buffer.alloc(MAX_LENGTH);
883
- const bytesRead = fs15.readSync(fd, buffer, 0, MAX_LENGTH, 0);
884
- fs15.close(fd, () => {
898
+ const bytesRead = fs16.readSync(fd, buffer, 0, MAX_LENGTH, 0);
899
+ fs16.close(fd, () => {
885
900
  });
886
901
  return buffer.subarray(0, bytesRead);
887
902
  };
888
- var readFile = (path20) => new Promise((resolve, reject) => {
889
- fs15.open(path20, "r", (err, fd) => {
903
+ var readFile = (path21) => new Promise((resolve, reject) => {
904
+ fs16.open(path21, "r", (err, fd) => {
890
905
  if (err) {
891
906
  reject(err);
892
907
  } else {
893
908
  const buffer = Buffer.alloc(MAX_LENGTH);
894
- fs15.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
909
+ fs16.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
895
910
  resolve(buffer.subarray(0, bytesRead));
896
- fs15.close(fd, () => {
911
+ fs16.close(fd, () => {
897
912
  });
898
913
  });
899
914
  }
@@ -1005,11 +1020,11 @@ var require_detect_libc = __commonJS({
1005
1020
  }
1006
1021
  return null;
1007
1022
  };
1008
- var familyFromInterpreterPath = (path20) => {
1009
- if (path20) {
1010
- if (path20.includes("/ld-musl-")) {
1023
+ var familyFromInterpreterPath = (path21) => {
1024
+ if (path21) {
1025
+ if (path21.includes("/ld-musl-")) {
1011
1026
  return MUSL;
1012
- } else if (path20.includes("/ld-linux-")) {
1027
+ } else if (path21.includes("/ld-linux-")) {
1013
1028
  return GLIBC;
1014
1029
  }
1015
1030
  }
@@ -1056,8 +1071,8 @@ var require_detect_libc = __commonJS({
1056
1071
  cachedFamilyInterpreter = null;
1057
1072
  try {
1058
1073
  const selfContent = await readFile(SELF_PATH);
1059
- const path20 = interpreterPath(selfContent);
1060
- cachedFamilyInterpreter = familyFromInterpreterPath(path20);
1074
+ const path21 = interpreterPath(selfContent);
1075
+ cachedFamilyInterpreter = familyFromInterpreterPath(path21);
1061
1076
  } catch (e) {
1062
1077
  }
1063
1078
  return cachedFamilyInterpreter;
@@ -1069,8 +1084,8 @@ var require_detect_libc = __commonJS({
1069
1084
  cachedFamilyInterpreter = null;
1070
1085
  try {
1071
1086
  const selfContent = readFileSync(SELF_PATH);
1072
- const path20 = interpreterPath(selfContent);
1073
- cachedFamilyInterpreter = familyFromInterpreterPath(path20);
1087
+ const path21 = interpreterPath(selfContent);
1088
+ cachedFamilyInterpreter = familyFromInterpreterPath(path21);
1074
1089
  } catch (e) {
1075
1090
  }
1076
1091
  return cachedFamilyInterpreter;
@@ -2171,7 +2186,81 @@ ${msg}`);
2171
2186
  map: result.map ? JSON.stringify(result.map) : null
2172
2187
  };
2173
2188
  }
2174
- var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
2189
+ async function transformReactCode(filename, code, options) {
2190
+ if (!matchesReactFilter(filename, options.react.include, options.react.exclude)) {
2191
+ return null;
2192
+ }
2193
+ if (!options.react.compiler) {
2194
+ if (!shouldTransform(filename)) return null;
2195
+ return transformCode(filename, code, {
2196
+ sourcemap: options.sourcemap,
2197
+ jsxRuntime: options.react.jsxRuntime,
2198
+ jsxImportSource: options.react.jsxImportSource,
2199
+ reactRefresh: options.reactRefresh,
2200
+ target: options.target
2201
+ });
2202
+ }
2203
+ if (!shouldTransform(filename)) return null;
2204
+ const compiler2 = await loadReactCompiler();
2205
+ const compilerOptions = options.react.compiler;
2206
+ const shouldCompile = options.consumer === "client" && (compilerOptions.compilationMode === "annotation" ? /['"]use memo['"]/.test(code) : defaultReactCompilerCodeFilter.test(code));
2207
+ const result = await compiler2.transform(cleanTransformId(filename), code, {
2208
+ jsx: {
2209
+ runtime: options.react.jsxRuntime,
2210
+ development: options.development,
2211
+ importSource: options.react.jsxImportSource,
2212
+ refresh: options.consumer === "client" && !!options.reactRefresh
2213
+ },
2214
+ reactCompiler: shouldCompile ? compilerOptions : false,
2215
+ sourcemap: options.sourcemap ?? true
2216
+ });
2217
+ const diagnostics = result.errors.map(
2218
+ (error) => `${error.message}${error.codeframe ? `
2219
+ ${error.codeframe}` : ""}`
2220
+ );
2221
+ if (result.fatal) {
2222
+ throw new Error(
2223
+ diagnostics.join("\n\n") || `React Compiler transform failed for ${filename}`
2224
+ );
2225
+ }
2226
+ for (const diagnostic of diagnostics) options.onWarning?.(diagnostic);
2227
+ return {
2228
+ code: result.code,
2229
+ map: result.map ? JSON.stringify(result.map) : null
2230
+ };
2231
+ }
2232
+ function matchesReactFilter(id, include, exclude) {
2233
+ const cleanId = cleanTransformId(id);
2234
+ return matchesFilter(cleanId, include) && !matchesFilter(cleanId, exclude);
2235
+ }
2236
+ function matchesFilter(id, filter2) {
2237
+ const patterns = Array.isArray(filter2) ? filter2 : [filter2];
2238
+ return patterns.some((pattern) => {
2239
+ if (pattern instanceof RegExp) {
2240
+ pattern.lastIndex = 0;
2241
+ return pattern.test(id);
2242
+ }
2243
+ if (!pattern.includes("*")) return id.includes(pattern);
2244
+ const expression = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, "[^/]*").replace(/\0/g, ".*");
2245
+ return new RegExp(`^${expression}$`).test(id);
2246
+ });
2247
+ }
2248
+ function cleanTransformId(id) {
2249
+ return id.split(/[?#]/, 1)[0];
2250
+ }
2251
+ async function loadReactCompiler() {
2252
+ if (reactCompilerImplementation) return reactCompilerImplementation;
2253
+ try {
2254
+ reactCompilerImplementation = await import("oxc-transform-react");
2255
+ return reactCompilerImplementation;
2256
+ } catch (error) {
2257
+ throw new Error(
2258
+ '[nasti] React Compiler requires the optional "oxc-transform-react" package. Install it before setting react.compiler.' + (error instanceof Error ? `
2259
+ ${error.message}` : "")
2260
+ );
2261
+ }
2262
+ }
2263
+ var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS, defaultReactCompilerCodeFilter, reactCompilerImplementation;
2175
2264
  var init_transformer = __esm({
2176
2265
  "src/core/transformer.ts"() {
2177
2266
  "use strict";
@@ -2179,6 +2268,7 @@ var init_transformer = __esm({
2179
2268
  JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
2180
2269
  TS_EXTENSIONS = /\.(ts|mts|cts)$/;
2181
2270
  JSX_EXTENSIONS = /\.(jsx|tsx)$/;
2271
+ defaultReactCompilerCodeFilter = /forwardRef|memo|\b(?:[A-Z]|use[A-Z0-9])/;
2182
2272
  }
2183
2273
  });
2184
2274
 
@@ -2218,8 +2308,8 @@ function vuePlugin(config, environmentName = "client") {
2218
2308
  let cached2 = descriptorCache.get(filePath);
2219
2309
  if (!cached2) {
2220
2310
  try {
2221
- const fs15 = await import("fs");
2222
- const rawSource = fs15.readFileSync(filePath, "utf-8");
2311
+ const fs16 = await import("fs");
2312
+ const rawSource = fs16.readFileSync(filePath, "utf-8");
2223
2313
  const transformedSfc = await applySourceTransform(
2224
2314
  vueOptions.transformSfc,
2225
2315
  rawSource,
@@ -3275,6 +3365,44 @@ var init_environment = __esm({
3275
3365
  }
3276
3366
  });
3277
3367
 
3368
+ // src/plugins/react.ts
3369
+ function reactPlugin(config, environment) {
3370
+ return {
3371
+ name: "nasti:oxc-transform",
3372
+ async transform(code, id) {
3373
+ const result = await transformReactCode(id, code, {
3374
+ react: config.react,
3375
+ consumer: environment.consumer,
3376
+ development: config.mode === "development",
3377
+ sourcemap: !!environment.options.build.sourcemap,
3378
+ target: environment.options.build.target,
3379
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
3380
+ });
3381
+ if (!result) return null;
3382
+ return {
3383
+ code: result.code,
3384
+ map: result.map ? JSON.parse(result.map) : void 0
3385
+ };
3386
+ },
3387
+ handleHotUpdate(ctx) {
3388
+ for (const mod of ctx.modules) {
3389
+ if (REACT_FILE_RE.test(mod.url) && matchesReactFilter(mod.url, config.react.include, config.react.exclude)) {
3390
+ mod.isSelfAccepting = true;
3391
+ }
3392
+ }
3393
+ return ctx.modules;
3394
+ }
3395
+ };
3396
+ }
3397
+ var REACT_FILE_RE;
3398
+ var init_react = __esm({
3399
+ "src/plugins/react.ts"() {
3400
+ "use strict";
3401
+ init_transformer();
3402
+ REACT_FILE_RE = /\.[jt]sx(?:[?#].*)?$/;
3403
+ }
3404
+ });
3405
+
3278
3406
  // src/core/env.ts
3279
3407
  function loadEnv(mode, root, prefixes) {
3280
3408
  const envFiles = [
@@ -3632,7 +3760,7 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
3632
3760
  // 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
3633
3761
  external: restInputOptions.external ?? ((id) => {
3634
3762
  if (NODE_BUILTINS.has(id)) return true;
3635
- return !id.startsWith(".") && !import_node_path10.default.isAbsolute(id) && !id.startsWith("\0");
3763
+ return !id.startsWith(".") && !import_node_path10.default.isAbsolute(id) && !id.startsWith("\0") && !id.startsWith("virtual:");
3636
3764
  })
3637
3765
  } : {}
3638
3766
  };
@@ -3855,6 +3983,7 @@ function resolveClientEntries(config, html) {
3855
3983
  return entryPoints;
3856
3984
  }
3857
3985
  function createOxcTransformPlugin(config, environment) {
3986
+ if (config.framework === "react") return reactPlugin(config, environment);
3858
3987
  return {
3859
3988
  name: "nasti:oxc-transform",
3860
3989
  transform(code, id) {
@@ -3875,7 +4004,7 @@ async function build(inlineConfig = {}) {
3875
4004
  const startTime = performance.now();
3876
4005
  logger.info(
3877
4006
  import_picocolors4.default.cyan(`
3878
- nasti v${"2.4.4"} `) + import_picocolors4.default.green(`building for ${config.mode}...`)
4007
+ nasti v${"2.5.0"} `) + import_picocolors4.default.green(`building for ${config.mode}...`)
3879
4008
  );
3880
4009
  debug5?.(`root: ${config.root}`);
3881
4010
  const buildableNames = Object.keys(config.environments).filter((name) => {
@@ -4161,6 +4290,7 @@ var init_build = __esm({
4161
4290
  init_environment();
4162
4291
  init_css_engine();
4163
4292
  init_html();
4293
+ init_react();
4164
4294
  init_transformer();
4165
4295
  init_env();
4166
4296
  init_reporter();
@@ -4610,22 +4740,35 @@ async function transformRequest(url, ctx) {
4610
4740
  }
4611
4741
  const stableUrl = cleanReqUrl;
4612
4742
  let wrappedWithRefresh = false;
4613
- if (shouldTransform(filePath)) {
4614
- const isJsx = /\.[jt]sx$/.test(filePath);
4615
- const useRefresh = isJsx && config.framework !== "vue";
4743
+ if (config.framework === "react") {
4744
+ const refreshEnabled = (ctx.environment?.consumer ?? "client") === "client" && config.server.hmr !== false;
4745
+ const useRefresh = refreshEnabled && (!!config.react.compiler || /\.[jt]sx$/.test(filePath));
4746
+ const result = await transformReactCode(filePath, code, {
4747
+ react: config.react,
4748
+ consumer: ctx.environment?.consumer ?? "client",
4749
+ development: true,
4750
+ reactRefresh: useRefresh,
4751
+ sourcemap: true,
4752
+ target: ctx.environment?.options.build.target ?? config.build.target,
4753
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
4754
+ });
4755
+ if (result) {
4756
+ code = result.code;
4757
+ if (result.map) map = JSON.parse(result.map);
4758
+ if (useRefresh) {
4759
+ code = buildReactRefreshWrapper(stableUrl, code);
4760
+ wrappedWithRefresh = true;
4761
+ }
4762
+ }
4763
+ } else if (shouldTransform(filePath)) {
4616
4764
  const result = transformCode(filePath, code, {
4617
4765
  sourcemap: true,
4618
4766
  jsxRuntime: "automatic",
4619
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
4620
- reactRefresh: useRefresh,
4767
+ jsxImportSource: "vue",
4621
4768
  target: ctx.environment?.options.build.target ?? config.build.target
4622
4769
  });
4623
4770
  code = result.code;
4624
4771
  if (result.map) map = JSON.parse(result.map);
4625
- if (useRefresh) {
4626
- code = buildReactRefreshWrapper(stableUrl, code);
4627
- wrappedWithRefresh = true;
4628
- }
4629
4772
  }
4630
4773
  const hotInfo = rewriteHotAcceptDeps(code, config, filePath);
4631
4774
  code = hotInfo.code;
@@ -5795,12 +5938,32 @@ var init_runnable_environment = __esm({
5795
5938
  if (transformed != null) {
5796
5939
  code = typeof transformed === "string" ? transformed : transformed.code;
5797
5940
  }
5798
- if (shouldTransform(cleanId)) {
5941
+ if (this.config.framework === "react") {
5942
+ const result = await transformReactCode(cleanId, code, {
5943
+ react: this.config.react,
5944
+ consumer: this.environment.consumer,
5945
+ development: true,
5946
+ sourcemap: false,
5947
+ target: this.environment.options.build.target,
5948
+ onWarning: (message) => this.config.logger.warn(`[nasti:react] ${message}`)
5949
+ });
5950
+ if (result) {
5951
+ code = result.code;
5952
+ } else if (shouldTransform(cleanId)) {
5953
+ const fallback = transformCode(cleanId, code, {
5954
+ sourcemap: false,
5955
+ jsxRuntime: this.config.react.jsxRuntime,
5956
+ jsxImportSource: this.config.react.jsxImportSource,
5957
+ target: this.environment.options.build.target
5958
+ });
5959
+ code = fallback.code;
5960
+ }
5961
+ } else if (shouldTransform(cleanId)) {
5799
5962
  const result = transformCode(cleanId, code, {
5800
5963
  sourcemap: false,
5801
5964
  target: this.environment.options.build.target,
5802
5965
  jsxRuntime: "automatic",
5803
- jsxImportSource: this.config.framework === "vue" ? "vue" : "react"
5966
+ jsxImportSource: "vue"
5804
5967
  });
5805
5968
  code = result.code;
5806
5969
  }
@@ -5947,11 +6110,11 @@ async function createBundledDevServer(opts) {
5947
6110
  const patches = new MemoryFiles();
5948
6111
  const entryFileNames = /* @__PURE__ */ new Map();
5949
6112
  const bundledClients = /* @__PURE__ */ new Map();
5950
- const useReactRefresh = config.framework !== "vue" && refreshWrapperFn != null;
6113
+ const useReactRefresh = config.framework === "react" && config.server.hmr !== false && refreshWrapperFn != null;
5951
6114
  const rolldownPlugins = [
5952
6115
  ...useReactRefresh ? [
5953
6116
  createReactRefreshRuntimePlugin(entryPoints),
5954
- createBundledOxcRefreshPlugin()
6117
+ createBundledOxcRefreshPlugin(config)
5955
6118
  ] : [],
5956
6119
  ...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins, clientEnv)),
5957
6120
  ...useReactRefresh ? [
@@ -6222,18 +6385,21 @@ ${code}`, map: null };
6222
6385
  }
6223
6386
  };
6224
6387
  }
6225
- function createBundledOxcRefreshPlugin() {
6388
+ function createBundledOxcRefreshPlugin(config) {
6226
6389
  return {
6227
6390
  name: "nasti:bundled-oxc-refresh",
6228
- transform(code, id) {
6391
+ async transform(code, id) {
6229
6392
  const clean = id.split("?")[0];
6230
- if (!/\.[jt]sx$/.test(clean) || clean.includes("/node_modules/")) return null;
6231
- const result = transformCode(clean, code, {
6393
+ const result = await transformReactCode(clean, code, {
6394
+ react: config.react,
6395
+ consumer: "client",
6396
+ development: true,
6397
+ reactRefresh: true,
6232
6398
  sourcemap: true,
6233
- jsxRuntime: "automatic",
6234
- jsxImportSource: "react",
6235
- reactRefresh: true
6399
+ target: config.build.target,
6400
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
6236
6401
  });
6402
+ if (!result) return null;
6237
6403
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6238
6404
  }
6239
6405
  };
@@ -6669,7 +6835,7 @@ async function createServer(inlineConfig = {}) {
6669
6835
  const readyIn = Math.ceil(performance.now() - startTime);
6670
6836
  logger.info(
6671
6837
  `
6672
- ${import_picocolors9.default.cyan(import_picocolors9.default.bold("NASTI"))} ${import_picocolors9.default.cyan(`v${"2.4.4"}`)} ${import_picocolors9.default.dim("ready in")} ${import_picocolors9.default.bold(readyIn)} ${import_picocolors9.default.dim("ms")}
6838
+ ${import_picocolors9.default.cyan(import_picocolors9.default.bold("NASTI"))} ${import_picocolors9.default.cyan(`v${"2.5.0"}`)} ${import_picocolors9.default.dim("ready in")} ${import_picocolors9.default.bold(readyIn)} ${import_picocolors9.default.dim("ms")}
6673
6839
  `
6674
6840
  );
6675
6841
  printServerUrls(
@@ -6840,6 +7006,7 @@ __export(src_exports, {
6840
7006
  printServerUrls: () => printServerUrls,
6841
7007
  resolveConfig: () => resolveConfig,
6842
7008
  resolveEnvironmentPlugins: () => resolveEnvironmentPlugins,
7009
+ rsc: () => rsc,
6843
7010
  ssrDefineOverrides: () => ssrDefineOverrides,
6844
7011
  startElectronDev: () => startElectronDev
6845
7012
  });
@@ -6896,7 +7063,7 @@ async function buildElectron(inlineConfig = {}) {
6896
7063
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
6897
7064
  const startTime = performance.now();
6898
7065
  assertElectronVersion(config);
6899
- console.log(import_picocolors5.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors5.default.dim(` v${"2.4.4"}`));
7066
+ console.log(import_picocolors5.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors5.default.dim(` v${"2.5.0"}`));
6900
7067
  console.log(import_picocolors5.default.dim(` root: ${config.root}`));
6901
7068
  console.log(import_picocolors5.default.dim(` mode: ${config.mode}`));
6902
7069
  console.log(import_picocolors5.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -6962,14 +7129,21 @@ async function bundleNode(config, entry, opts) {
6962
7129
  };
6963
7130
  const oxcTransformPlugin = {
6964
7131
  name: "nasti:oxc-transform",
6965
- transform(code, id) {
6966
- if (!shouldTransform(id)) return null;
6967
- const result = transformCode(id, code, {
7132
+ async transform(code, id) {
7133
+ const result = config.framework === "react" ? await transformReactCode(id, code, {
7134
+ react: config.react,
7135
+ consumer: "server",
7136
+ development: config.mode === "development",
7137
+ sourcemap: !!config.build.sourcemap,
7138
+ target: config.electron.nodeTarget,
7139
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
7140
+ }) : shouldTransform(id) ? transformCode(id, code, {
6968
7141
  sourcemap: !!config.build.sourcemap,
6969
7142
  jsxRuntime: "automatic",
6970
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
7143
+ jsxImportSource: "vue",
6971
7144
  target: config.electron.nodeTarget
6972
- });
7145
+ }) : null;
7146
+ if (!result) return null;
6973
7147
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6974
7148
  }
6975
7149
  };
@@ -7077,7 +7251,7 @@ async function startElectronDev(inlineConfig = {}) {
7077
7251
  const { noSpawn, ...rest } = inlineConfig;
7078
7252
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
7079
7253
  warnElectronVersion(config);
7080
- console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.4.4"}`));
7254
+ console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.5.0"}`));
7081
7255
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
7082
7256
  const server = await createServer2({
7083
7257
  ...rest,
@@ -7202,14 +7376,21 @@ async function compileNode(config, entry, opts) {
7202
7376
  };
7203
7377
  const oxcTransformPlugin = {
7204
7378
  name: "nasti:oxc-transform",
7205
- transform(code, id) {
7206
- if (!shouldTransform(id)) return null;
7207
- const result = transformCode(id, code, {
7379
+ async transform(code, id) {
7380
+ const result = config.framework === "react" ? await transformReactCode(id, code, {
7381
+ react: config.react,
7382
+ consumer: "server",
7383
+ development: true,
7384
+ sourcemap: true,
7385
+ target: config.electron.nodeTarget,
7386
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
7387
+ }) : shouldTransform(id) ? transformCode(id, code, {
7208
7388
  sourcemap: true,
7209
7389
  jsxRuntime: "automatic",
7210
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
7390
+ jsxImportSource: "vue",
7211
7391
  target: config.electron.nodeTarget
7212
- });
7392
+ }) : null;
7393
+ if (!result) return null;
7213
7394
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
7214
7395
  }
7215
7396
  };
@@ -7488,6 +7669,345 @@ ${e.stack || ""}`
7488
7669
  };
7489
7670
  }
7490
7671
 
7672
+ // src/plugins/rsc.ts
7673
+ var import_node_fs15 = __toESM(require("fs"), 1);
7674
+ var import_node_path20 = __toESM(require("path"), 1);
7675
+ var import_oxc_parser = require("oxc-parser");
7676
+ init_transformer();
7677
+ var SERVER_RUNTIME_ID = "virtual:nasti-rsc/server-runtime";
7678
+ var CLIENT_RUNTIME_ID = "virtual:nasti-rsc/client-runtime";
7679
+ var RESOLVED_SERVER_RUNTIME_ID = `\0${SERVER_RUNTIME_ID}`;
7680
+ var RESOLVED_CLIENT_RUNTIME_ID = `\0${CLIENT_RUNTIME_ID}`;
7681
+ function rsc(options = {}) {
7682
+ const names = {
7683
+ client: options.environment?.client ?? "client",
7684
+ ssr: options.environment?.ssr ?? "ssr",
7685
+ rsc: options.environment?.rsc ?? "rsc"
7686
+ };
7687
+ const clientReferences = /* @__PURE__ */ new Map();
7688
+ const serverReferences = /* @__PURE__ */ new Map();
7689
+ let resolvedConfig;
7690
+ return {
7691
+ name: "nasti:rsc",
7692
+ enforce: "post",
7693
+ config(config, env) {
7694
+ const root = import_node_path20.default.resolve(config.root ?? ".");
7695
+ const include = options.include ?? config.react?.include ?? /\.[tj]sx?$/;
7696
+ const exclude = options.exclude ?? config.react?.exclude ?? /node_modules/;
7697
+ const discoveredClients = env.command === "build" ? discoverDirectiveModules(root, options.scanDirectories, include, exclude) : [];
7698
+ for (const item of discoveredClients) {
7699
+ if (item.module.useClient) {
7700
+ clientReferences.set(
7701
+ item.id,
7702
+ new Set(item.module.exports.map((entry) => entry.exported))
7703
+ );
7704
+ }
7705
+ if (item.module.useServer) {
7706
+ serverReferences.set(
7707
+ item.id,
7708
+ new Set(item.module.exports.map((entry) => entry.exported))
7709
+ );
7710
+ }
7711
+ }
7712
+ const environments = { ...config.environments ?? {} };
7713
+ if (names.client !== "client") {
7714
+ environments.client = {
7715
+ ...environments.client ?? {},
7716
+ buildEnabled: false
7717
+ };
7718
+ }
7719
+ const client = { ...environments[names.client] ?? {} };
7720
+ const clientSeeds = collectClientSeeds(root, config, client, options.entries?.client);
7721
+ const generatedClientEntries = discoveredClients.filter((item) => item.module.useClient).map((item) => item.id);
7722
+ client.consumer = "client";
7723
+ client.entry = uniqueEntries([...clientSeeds, ...generatedClientEntries]);
7724
+ environments[names.client] = client;
7725
+ const rscEnvironment = { ...environments[names.rsc] ?? {} };
7726
+ rscEnvironment.consumer = "server";
7727
+ const rscEntries = normalizeEntries(options.entries?.rsc);
7728
+ if (rscEntries.length > 0) rscEnvironment.entry = rscEntries;
7729
+ environments[names.rsc] = rscEnvironment;
7730
+ const ssrEntries = normalizeEntries(options.entries?.ssr);
7731
+ if (ssrEntries.length > 0 || environments[names.ssr]) {
7732
+ environments[names.ssr] = {
7733
+ ...environments[names.ssr] ?? {},
7734
+ consumer: "server",
7735
+ ...ssrEntries.length > 0 ? { entry: ssrEntries } : {}
7736
+ };
7737
+ }
7738
+ return { environments };
7739
+ },
7740
+ configEnvironment(name, environment) {
7741
+ if (name !== names.rsc) return;
7742
+ const conditions = environment.resolve?.conditions ?? ["node", "import", "module", "default"];
7743
+ return {
7744
+ consumer: "server",
7745
+ resolve: {
7746
+ ...environment.resolve,
7747
+ conditions: ["react-server", ...conditions.filter((item) => item !== "react-server")]
7748
+ }
7749
+ };
7750
+ },
7751
+ configResolved(config) {
7752
+ if (config.framework !== "react") {
7753
+ throw new Error('[nasti:rsc] the RSC generator requires framework: "react"');
7754
+ }
7755
+ resolvedConfig = config;
7756
+ },
7757
+ resolveId(source) {
7758
+ if (source === SERVER_RUNTIME_ID) return RESOLVED_SERVER_RUNTIME_ID;
7759
+ if (source === CLIENT_RUNTIME_ID) return RESOLVED_CLIENT_RUNTIME_ID;
7760
+ return null;
7761
+ },
7762
+ load(id) {
7763
+ if (id === RESOLVED_SERVER_RUNTIME_ID) return createServerRuntimeModule();
7764
+ if (id === RESOLVED_CLIENT_RUNTIME_ID) {
7765
+ const browser = this.environment?.name === names.client;
7766
+ return createClientRuntimeModule(browser);
7767
+ }
7768
+ return null;
7769
+ },
7770
+ transform(code, id) {
7771
+ if (!resolvedConfig || !isSourceModule(id, resolvedConfig, options)) return null;
7772
+ const cleanId = cleanModuleId(id);
7773
+ const module2 = scanModule(cleanId, code);
7774
+ if (!module2) return null;
7775
+ if (module2.useClient && module2.useServer) {
7776
+ throw new Error(`[nasti:rsc] ${displayId(resolvedConfig.root, cleanId)} cannot contain both "use client" and "use server"`);
7777
+ }
7778
+ const moduleId = referenceModuleId(resolvedConfig.root, cleanId);
7779
+ if (module2.useClient) {
7780
+ clientReferences.set(cleanId, new Set(module2.exports.map((entry) => entry.exported)));
7781
+ if (this.environment?.name === names.rsc) {
7782
+ return {
7783
+ code: createClientReferenceProxy(moduleId, module2.exports),
7784
+ map: { mappings: "" }
7785
+ };
7786
+ }
7787
+ }
7788
+ if (module2.useServer) {
7789
+ serverReferences.set(cleanId, new Set(module2.exports.map((entry) => entry.exported)));
7790
+ if (this.environment?.name === names.rsc) {
7791
+ return {
7792
+ code: registerServerReferences(code, moduleId, module2.exports, cleanId),
7793
+ map: { mappings: "" }
7794
+ };
7795
+ }
7796
+ if (this.environment?.consumer === "client" || this.environment?.name === names.client || this.environment?.name === names.ssr) {
7797
+ return {
7798
+ code: createServerReferenceProxy(moduleId, module2.exports),
7799
+ map: { mappings: "" }
7800
+ };
7801
+ }
7802
+ }
7803
+ return null;
7804
+ },
7805
+ afterBuildApp(results, _api, context) {
7806
+ if (options.manifestFile === false) return;
7807
+ const manifest = createManifest(
7808
+ names,
7809
+ resolvedConfig?.root ?? "",
7810
+ results,
7811
+ clientReferences,
7812
+ serverReferences
7813
+ );
7814
+ const output = {
7815
+ type: "asset",
7816
+ fileName: options.manifestFile ?? "rsc-manifest.json",
7817
+ source: JSON.stringify(manifest, null, 2) + "\n"
7818
+ };
7819
+ context.emitFile(output);
7820
+ }
7821
+ };
7822
+ }
7823
+ function scanModule(filename, code) {
7824
+ if (!code.includes("use client") && !code.includes("use server")) return null;
7825
+ const parsed = (0, import_oxc_parser.parseSync)(filename, code);
7826
+ if (parsed.errors.length > 0) return null;
7827
+ const directives = new Set(
7828
+ parsed.program.body.filter((node) => node.type === "ExpressionStatement" && typeof node.directive === "string").map((node) => node.directive)
7829
+ );
7830
+ const useClient = directives.has("use client");
7831
+ const useServer = directives.has("use server");
7832
+ if (!useClient && !useServer) return null;
7833
+ const exports2 = [];
7834
+ for (const statement of parsed.module.staticExports) {
7835
+ for (const entry of statement.entries) {
7836
+ if (entry.isType) continue;
7837
+ const exported = entry.exportName.kind === "Default" ? "default" : entry.exportName.name;
7838
+ if (!exported) {
7839
+ throw new Error(
7840
+ `[nasti:rsc] ${filename} uses export * inside an RSC directive module; replace it with explicit named exports so reference identities are stable`
7841
+ );
7842
+ }
7843
+ exports2.push({
7844
+ exported,
7845
+ local: entry.localName.kind === "Name" ? entry.localName.name ?? void 0 : void 0,
7846
+ reexported: entry.moduleRequest !== null
7847
+ });
7848
+ }
7849
+ }
7850
+ return { useClient, useServer, exports: dedupeExports(exports2) };
7851
+ }
7852
+ function createClientReferenceProxy(moduleId, exports2) {
7853
+ const lines = [
7854
+ `import { registerClientReference as __nasti_register_client__ } from ${JSON.stringify(SERVER_RUNTIME_ID)};`
7855
+ ];
7856
+ exports2.forEach((entry, index2) => {
7857
+ const local = `__nasti_client_reference_${index2}__`;
7858
+ const message = `Cannot call client export ${moduleId}#${entry.exported} from the RSC server graph.`;
7859
+ lines.push(
7860
+ `const ${local} = __nasti_register_client__(function () { throw new Error(${JSON.stringify(message)}); }, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`,
7861
+ exportLocal(local, entry.exported)
7862
+ );
7863
+ });
7864
+ return lines.join("\n") + "\n";
7865
+ }
7866
+ function registerServerReferences(code, moduleId, exports2, filename) {
7867
+ const registrations = [];
7868
+ for (const entry of exports2) {
7869
+ if (entry.reexported || !entry.local) {
7870
+ throw new Error(
7871
+ `[nasti:rsc] ${filename} must use named local bindings for "use server" exports; ${entry.exported} cannot be registered safely`
7872
+ );
7873
+ }
7874
+ registrations.push(
7875
+ `__nasti_register_server__(${entry.local}, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`
7876
+ );
7877
+ }
7878
+ return [
7879
+ code,
7880
+ `import { registerServerReference as __nasti_register_server__ } from ${JSON.stringify(SERVER_RUNTIME_ID)};`,
7881
+ ...registrations,
7882
+ ""
7883
+ ].join("\n");
7884
+ }
7885
+ function createServerReferenceProxy(moduleId, exports2) {
7886
+ const lines = [
7887
+ `import { createServerReference as __nasti_create_server__ } from ${JSON.stringify(CLIENT_RUNTIME_ID)};`
7888
+ ];
7889
+ exports2.forEach((entry, index2) => {
7890
+ const local = `__nasti_server_reference_${index2}__`;
7891
+ lines.push(
7892
+ `const ${local} = __nasti_create_server__(${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`,
7893
+ exportLocal(local, entry.exported)
7894
+ );
7895
+ });
7896
+ return lines.join("\n") + "\n";
7897
+ }
7898
+ function exportLocal(local, exported) {
7899
+ if (exported === "default") return `export default ${local};`;
7900
+ const name = /^[A-Za-z_$][\w$]*$/.test(exported) ? exported : JSON.stringify(exported);
7901
+ return `export { ${local} as ${name} };`;
7902
+ }
7903
+ function createServerRuntimeModule() {
7904
+ return [
7905
+ `export { registerClientReference, registerServerReference } from "react-server-dom-webpack/server.edge";`,
7906
+ ""
7907
+ ].join("\n");
7908
+ }
7909
+ function createClientRuntimeModule(browser) {
7910
+ const source = browser ? "react-server-dom-webpack/client.browser" : "react-server-dom-webpack/client.edge";
7911
+ return `
7912
+ import { createServerReference as __createServerReference } from ${JSON.stringify(source)};
7913
+ const __callServer = (id, args) => {
7914
+ const handler = globalThis[Symbol.for("nasti.rsc.callServer")];
7915
+ if (typeof handler !== "function") {
7916
+ throw new Error("No RSC callServer handler is installed. Set globalThis[Symbol.for('nasti.rsc.callServer')].");
7917
+ }
7918
+ return handler(id, args);
7919
+ };
7920
+ export function createServerReference(moduleId, name) {
7921
+ return __createServerReference(moduleId + "#" + name, __callServer, undefined, undefined, name);
7922
+ }
7923
+ `.trimStart();
7924
+ }
7925
+ function createManifest(names, root, results, clients, servers) {
7926
+ return {
7927
+ version: 1,
7928
+ environments: names,
7929
+ clientReferences: manifestReferences(root, results[names.client], clients),
7930
+ serverReferences: manifestReferences(root, results[names.rsc], servers)
7931
+ };
7932
+ }
7933
+ function manifestReferences(root, result, references) {
7934
+ const output = {};
7935
+ for (const [id, names] of [...references].sort(([a], [b]) => a.localeCompare(b))) {
7936
+ const chunks = Object.values(result?.chunks ?? {}).filter((chunk) => chunk.moduleIds.some((moduleId) => cleanModuleId(moduleId) === id)).map((chunk) => chunk.fileName).sort();
7937
+ for (const name of [...names].sort()) {
7938
+ const moduleId = referenceModuleId(root, id);
7939
+ output[`${moduleId}#${name}`] = { id: moduleId, name, chunks };
7940
+ }
7941
+ }
7942
+ return output;
7943
+ }
7944
+ function discoverDirectiveModules(root, scanDirectories, include, exclude) {
7945
+ const requested = scanDirectories ?? ["app", "src"];
7946
+ const roots = requested.map((directory) => import_node_path20.default.resolve(root, directory)).filter((directory) => import_node_fs15.default.existsSync(directory));
7947
+ if (roots.length === 0) roots.push(root);
7948
+ const output = [];
7949
+ for (const directory of roots) walk(directory);
7950
+ return output;
7951
+ function walk(directory) {
7952
+ for (const entry of import_node_fs15.default.readdirSync(directory, { withFileTypes: true })) {
7953
+ if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".nasti") continue;
7954
+ const id = import_node_path20.default.join(directory, entry.name);
7955
+ if (entry.isDirectory()) {
7956
+ walk(id);
7957
+ continue;
7958
+ }
7959
+ if (!entry.isFile() || !matchesReactFilter(id, include, exclude)) continue;
7960
+ const module2 = scanModule(id, import_node_fs15.default.readFileSync(id, "utf-8"));
7961
+ if (module2) output.push({ id, module: module2 });
7962
+ }
7963
+ }
7964
+ }
7965
+ function collectClientSeeds(root, config, client, configured) {
7966
+ const explicit = [
7967
+ ...normalizeEntries(client.entry),
7968
+ ...normalizeEntries(configured)
7969
+ ];
7970
+ if (explicit.length > 0) return explicit;
7971
+ const htmlFile = import_node_path20.default.resolve(root, client.html ?? "index.html");
7972
+ if (import_node_fs15.default.existsSync(htmlFile)) {
7973
+ const html = import_node_fs15.default.readFileSync(htmlFile, "utf-8");
7974
+ const htmlDir = import_node_path20.default.dirname(htmlFile);
7975
+ const entries = [...html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi)].map((match) => match[1]?.split(/[?#]/, 1)[0]).filter((entry) => !!entry && !entry.startsWith("http")).map((entry) => entry.startsWith("/") ? import_node_path20.default.resolve(root, entry.slice(1)) : import_node_path20.default.resolve(htmlDir, entry));
7976
+ if (entries.length > 0) return entries;
7977
+ }
7978
+ for (const entry of ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"]) {
7979
+ if (import_node_fs15.default.existsSync(import_node_path20.default.resolve(root, entry))) return [entry];
7980
+ }
7981
+ return [];
7982
+ }
7983
+ function normalizeEntries(entries) {
7984
+ return entries == null ? [] : Array.isArray(entries) ? entries : [entries];
7985
+ }
7986
+ function uniqueEntries(entries) {
7987
+ return [...new Set(entries)];
7988
+ }
7989
+ function isSourceModule(id, config, options) {
7990
+ const cleanId = cleanModuleId(id);
7991
+ if (cleanId.startsWith("\0")) return false;
7992
+ const include = options.include ?? config.react.include;
7993
+ const exclude = options.exclude ?? config.react.exclude;
7994
+ return matchesReactFilter(cleanId, include, exclude);
7995
+ }
7996
+ function cleanModuleId(id) {
7997
+ return id.split(/[?#]/, 1)[0];
7998
+ }
7999
+ function referenceModuleId(root, id) {
8000
+ if (!root || !import_node_path20.default.isAbsolute(id)) return id.replaceAll(import_node_path20.default.sep, "/");
8001
+ const relative = import_node_path20.default.relative(root, id).replaceAll(import_node_path20.default.sep, "/");
8002
+ return relative.startsWith("../") ? id.replaceAll(import_node_path20.default.sep, "/") : `/${relative}`;
8003
+ }
8004
+ function displayId(root, id) {
8005
+ return referenceModuleId(root, id);
8006
+ }
8007
+ function dedupeExports(exports2) {
8008
+ return [...new Map(exports2.map((entry) => [entry.exported, entry])).values()];
8009
+ }
8010
+
7491
8011
  // src/index.ts
7492
8012
  init_environment();
7493
8013
  init_hot_channel();
@@ -7516,6 +8036,7 @@ init_env();
7516
8036
  printServerUrls,
7517
8037
  resolveConfig,
7518
8038
  resolveEnvironmentPlugins,
8039
+ rsc,
7519
8040
  ssrDefineOverrides,
7520
8041
  startElectronDev
7521
8042
  });