@bleedingdev/modern-js-builder 3.4.0-ultramodern.2 → 3.4.0-ultramodern.20

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.
@@ -37,6 +37,7 @@ var __webpack_require__ = {};
37
37
  var __webpack_exports__ = {};
38
38
  __webpack_require__.r(__webpack_exports__);
39
39
  __webpack_require__.d(__webpack_exports__, {
40
+ enrichServerOnlyDiagnostics: ()=>enrichServerOnlyDiagnostics,
40
41
  getRscPlugins: ()=>getRscPlugins,
41
42
  pluginRscConfig: ()=>pluginRscConfig
42
43
  });
@@ -45,15 +46,148 @@ var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_na
45
46
  const ASYNC_STORAGE_PATTERN = /universal[/\\]async_storage/;
46
47
  const SERVER_LOADER_ENTRY_PATTERN = /[/\\](?:server-loader-combined|route-server-loaders)\.js$/;
47
48
  const RENDER_RSC_SOURCE_PATTERN = /render[/\\].*[/\\]server[/\\]rsc/;
48
- const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc\.mjs$/;
49
+ const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc(?:Worker)?\.mjs$/;
50
+ const RENDER_RSC_RUNTIME = '@modern-js/render/rsc';
51
+ const RENDER_RSC_WORKER_RUNTIME = '@modern-js/render/rsc-worker';
49
52
  const RSC_COMMON_LAYER = 'rsc-common';
50
53
  const ENTRY_NAME_VAR = '__MODERN_JS_ENTRY_NAME';
54
+ const SERVER_ONLY_MARKER_PATTERN = /(?:^|[/\\])server-only[/\\]index\.js(?:\?|$)/;
55
+ const SERVER_ONLY_MESSAGE_PATTERN = /server-only|server only|only works in a Server Component|cannot be imported (?:directly )?(?:from|into) (?:a )?Client Component/i;
56
+ const SERVER_ONLY_DIAGNOSTIC_PREFIX = '[Modern.js RSC server-only diagnostic context]';
51
57
  const createVirtualModule = (content)=>`data:text/javascript,${encodeURIComponent(content)}`;
52
58
  const isAsyncStorageExclude = (exclude)=>{
53
59
  if ('string' == typeof exclude) return ASYNC_STORAGE_PATTERN.test(exclude);
54
60
  if (exclude instanceof RegExp) return exclude.test('universal/async_storage') || exclude.test('universal\\async_storage');
55
61
  return false;
56
62
  };
63
+ const asRecord = (value)=>{
64
+ if (value && 'object' == typeof value && !Array.isArray(value)) return value;
65
+ };
66
+ const disableReactCompilerInSwcLoaders = (value, seen = new WeakSet())=>{
67
+ if (!value || 'object' != typeof value) return;
68
+ if (seen.has(value)) return;
69
+ seen.add(value);
70
+ if (Array.isArray(value)) {
71
+ for (const item of value)disableReactCompilerInSwcLoaders(item, seen);
72
+ return;
73
+ }
74
+ const record = value;
75
+ if ('builtin:swc-loader' === record.loader) {
76
+ let options = asRecord(record.options);
77
+ if (!options) {
78
+ options = {};
79
+ record.options = options;
80
+ }
81
+ let jsc = asRecord(options.jsc);
82
+ if (!jsc) {
83
+ jsc = {};
84
+ options.jsc = jsc;
85
+ }
86
+ let transform = asRecord(jsc.transform);
87
+ if (!transform) {
88
+ transform = {};
89
+ jsc.transform = transform;
90
+ }
91
+ transform.reactCompiler = false;
92
+ }
93
+ for (const item of Object.values(record))disableReactCompilerInSwcLoaders(item, seen);
94
+ };
95
+ const normalizeDiagnosticText = (diagnostic)=>[
96
+ diagnostic.message,
97
+ diagnostic.details,
98
+ diagnostic.file,
99
+ getModulePath(diagnostic.module),
100
+ getModuleIdentifier(diagnostic.module)
101
+ ].filter((item)=>Boolean(item)).join('\n');
102
+ const isServerOnlyDiagnostic = (diagnostic)=>{
103
+ const text = normalizeDiagnosticText(diagnostic);
104
+ return SERVER_ONLY_MARKER_PATTERN.test(text) || SERVER_ONLY_MESSAGE_PATTERN.test(text);
105
+ };
106
+ const isEnrichedServerOnlyDiagnostic = (diagnostic)=>diagnostic.message.includes(SERVER_ONLY_DIAGNOSTIC_PREFIX) || diagnostic.details?.includes(SERVER_ONLY_DIAGNOSTIC_PREFIX);
107
+ const getModulePath = (module)=>{
108
+ if (!module) return;
109
+ return module.resource || module.nameForCondition?.() || module.userRequest;
110
+ };
111
+ const getModuleIdentifier = (module)=>{
112
+ if (!module) return;
113
+ return getModulePath(module) || module.readableIdentifier?.() || module.identifier?.() || module.request || module.rawRequest;
114
+ };
115
+ const formatModuleContext = (module)=>{
116
+ const id = getModuleIdentifier(module);
117
+ if (!id) return;
118
+ const layer = module?.layer ? ` [layer: ${module.layer}]` : '';
119
+ return `${id}${layer}`;
120
+ };
121
+ const getIssuerChain = (compilation, module)=>{
122
+ const chain = [];
123
+ const seen = new Set();
124
+ let current = module;
125
+ while(current && !seen.has(current) && chain.length < 8){
126
+ seen.add(current);
127
+ const issuer = compilation.moduleGraph?.getIssuer?.(current);
128
+ const formatted = formatModuleContext(issuer);
129
+ if (!issuer || !formatted) break;
130
+ chain.push(formatted);
131
+ current = issuer;
132
+ }
133
+ return chain;
134
+ };
135
+ const getModuleTraceChain = (diagnostic)=>{
136
+ const trace = diagnostic.moduleTrace || [];
137
+ const chain = [];
138
+ for (const item of trace){
139
+ const formatted = formatModuleContext(item.origin) || item.originName || formatModuleContext(item.module) || item.moduleName;
140
+ if (formatted && !chain.includes(formatted)) chain.push(formatted);
141
+ }
142
+ return chain.slice(0, 8);
143
+ };
144
+ const appendDiagnosticDetails = (diagnostic, lines)=>{
145
+ const context = `${SERVER_ONLY_DIAGNOSTIC_PREFIX}\n${lines.join('\n')}`;
146
+ diagnostic.details = diagnostic.details ? `${diagnostic.details}\n\n${context}` : context;
147
+ };
148
+ const enrichServerOnlyDiagnostics = (compilation, environmentName)=>{
149
+ const diagnostics = [
150
+ ...compilation.warnings,
151
+ ...compilation.errors
152
+ ];
153
+ for (const diagnostic of diagnostics){
154
+ if (!isServerOnlyDiagnostic(diagnostic) || isEnrichedServerOnlyDiagnostic(diagnostic)) continue;
155
+ const lines = [
156
+ `Environment: ${environmentName || compilation.name || 'unknown'}`
157
+ ];
158
+ const markerModule = formatModuleContext(diagnostic.module);
159
+ if (markerModule) lines.push(`Matched module: ${markerModule}`);
160
+ const issuerChain = getIssuerChain(compilation, diagnostic.module);
161
+ const moduleTraceChain = getModuleTraceChain(diagnostic);
162
+ const importerChain = issuerChain.length > 0 ? issuerChain : moduleTraceChain;
163
+ if (importerChain.length > 0) lines.push(`Importer chain: ${importerChain.join(' -> ')}`);
164
+ appendDiagnosticDetails(diagnostic, lines);
165
+ }
166
+ };
167
+ const applyServerOnlyDiagnosticPlugin = (compiler, environmentName)=>{
168
+ compiler.hooks.thisCompilation.tap('ModernJsServerOnlyDiagnosticContextPlugin', (compilation)=>{
169
+ compilation.hooks.processWarnings.tap('ModernJsServerOnlyDiagnosticContextPlugin', (warnings)=>{
170
+ enrichServerOnlyDiagnostics({
171
+ errors: compilation.errors,
172
+ moduleGraph: compilation.moduleGraph,
173
+ warnings
174
+ }, environmentName || compilation.name || compiler.name);
175
+ return warnings;
176
+ });
177
+ compilation.hooks.afterSeal.tapPromise('ModernJsServerOnlyDiagnosticContextPlugin', async ()=>{
178
+ enrichServerOnlyDiagnostics(compilation, environmentName || compilation.name || compiler.name);
179
+ });
180
+ });
181
+ };
182
+ const applyServerOnlyDiagnosticPlugins = (compiler, environments)=>{
183
+ const compilers = 'compilers' in compiler ? compiler.compilers : [
184
+ compiler
185
+ ];
186
+ compilers.forEach((childCompiler, index)=>{
187
+ const environmentName = childCompiler.name || Object.values(environments).find((environment)=>environment.index === index)?.name;
188
+ applyServerOnlyDiagnosticPlugin(childCompiler, environmentName);
189
+ });
190
+ };
57
191
  function pluginRscConfig() {
58
192
  return {
59
193
  name: 'builder:rsc-config',
@@ -69,6 +203,7 @@ function pluginRscConfig() {
69
203
  api.modifyBundlerChain({
70
204
  handler: (chain, { isServer })=>{
71
205
  if (isServer) {
206
+ chain.resolve.alias.set(`${RENDER_RSC_RUNTIME}$`, RENDER_RSC_WORKER_RUNTIME);
72
207
  const routeFilePattern = /[/\\]routes[/\\](?:.*[/\\])?(?:layout|page|\$)\.[tj]sx?$/;
73
208
  const appFilePattern = /[/\\]App\.[tj]sx?$/;
74
209
  const combinedPattern = new RegExp(`(${routeFilePattern.source}|${appFilePattern.source})`);
@@ -107,6 +242,7 @@ function pluginRscConfig() {
107
242
  }
108
243
  if (config.module?.rules) {
109
244
  const rules = config.module.rules;
245
+ disableReactCompilerInSwcLoaders(rules);
110
246
  for (const rule of rules)if (rule.layer === Layers.rsc) {
111
247
  if (rule.exclude) {
112
248
  if (!Array.isArray(rule.exclude)) rule.exclude = [
@@ -123,6 +259,9 @@ function pluginRscConfig() {
123
259
  });
124
260
  }
125
261
  });
262
+ api.onAfterCreateCompiler(({ compiler, environments })=>{
263
+ applyServerOnlyDiagnosticPlugins(compiler, environments);
264
+ });
126
265
  api.modifyBundlerChain((chain, { isServer, isWebWorker })=>{
127
266
  if (!isServer && !isWebWorker) {
128
267
  const entries = chain.entryPoints.entries();
@@ -160,9 +299,11 @@ async function getRscPlugins(enableRsc, internalDirectory, environments) {
160
299
  }
161
300
  return [];
162
301
  }
302
+ exports.enrichServerOnlyDiagnostics = __webpack_exports__.enrichServerOnlyDiagnostics;
163
303
  exports.getRscPlugins = __webpack_exports__.getRscPlugins;
164
304
  exports.pluginRscConfig = __webpack_exports__.pluginRscConfig;
165
305
  for(var __rspack_i in __webpack_exports__)if (-1 === [
306
+ "enrichServerOnlyDiagnostics",
166
307
  "getRscPlugins",
167
308
  "pluginRscConfig"
168
309
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
@@ -178,7 +178,7 @@ async function parseCommonConfig(builderConfig, options) {
178
178
  const { pluginSourceBuild } = await import("@rsbuild/plugin-source-build");
179
179
  rsbuildPlugins.push(pluginSourceBuild(true === sourceBuild ? {} : sourceBuild));
180
180
  }
181
- rsbuildPlugins.push((0, plugin_react_namespaceObject.pluginReact)({
181
+ rsbuildPlugins.push((0, plugin_react_namespaceObject.pluginReact)(options?.disableReactCompiler ? {} : {
182
182
  reactCompiler: reactCompiler ?? true
183
183
  }));
184
184
  if (!disableSvgr) {
@@ -3,6 +3,15 @@ const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
3
3
  return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
4
4
  }();
5
5
  var __webpack_require__ = {};
6
+ (()=>{
7
+ __webpack_require__.n = (module)=>{
8
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
9
+ __webpack_require__.d(getter, {
10
+ a: getter
11
+ });
12
+ return getter;
13
+ };
14
+ })();
6
15
  (()=>{
7
16
  __webpack_require__.d = (exports1, getters, values)=>{
8
17
  var define = (defs, kind)=>{
@@ -33,9 +42,16 @@ __webpack_require__.r(__webpack_exports__);
33
42
  __webpack_require__.d(__webpack_exports__, {
34
43
  withTsgoDefaults: ()=>withTsgoDefaults
35
44
  });
45
+ const external_node_crypto_namespaceObject = require("node:crypto");
46
+ const external_node_fs_namespaceObject = require("node:fs");
47
+ var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
36
48
  const external_node_module_namespaceObject = require("node:module");
49
+ const external_node_path_namespaceObject = require("node:path");
50
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
51
+ const utils_namespaceObject = require("@modern-js/utils");
37
52
  const builderRequire = (0, external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
38
53
  const TSGO_PACKAGE = "@typescript/native-preview/package.json";
54
+ const TSGO_CHECKER_DIR = external_node_path_default().join('.modern-js', 'tsgo');
39
55
  const tryResolve = (request, rootPath)=>{
40
56
  try {
41
57
  return builderRequire.resolve(request, {
@@ -47,6 +63,111 @@ const tryResolve = (request, rootPath)=>{
47
63
  return;
48
64
  }
49
65
  };
66
+ const toPosixPath = (input)=>input.replaceAll(external_node_path_default().sep, '/');
67
+ const asTsConfigPath = (request)=>{
68
+ if (external_node_path_default().extname(request)) return [
69
+ request
70
+ ];
71
+ return [
72
+ request,
73
+ `${request}.json`
74
+ ];
75
+ };
76
+ const resolveExtends = (request, configDirectory)=>{
77
+ const configRequire = (0, external_node_module_namespaceObject.createRequire)(external_node_path_default().join(configDirectory, 'tsconfig.json'));
78
+ for (const candidate of asTsConfigPath(request)){
79
+ if (candidate.startsWith('.') || external_node_path_default().isAbsolute(candidate)) {
80
+ const resolved = external_node_path_default().resolve(configDirectory, candidate);
81
+ if (external_node_fs_default().existsSync(resolved)) return resolved;
82
+ continue;
83
+ }
84
+ try {
85
+ return configRequire.resolve(candidate);
86
+ } catch {}
87
+ }
88
+ };
89
+ const readTsConfig = (configFile, visited = new Set())=>{
90
+ if (visited.has(configFile) || !external_node_fs_default().existsSync(configFile)) return {};
91
+ visited.add(configFile);
92
+ const config = utils_namespaceObject.json5.parse(external_node_fs_default().readFileSync(configFile, 'utf8'));
93
+ const configDirectory = external_node_path_default().dirname(configFile);
94
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [
95
+ config.extends
96
+ ] : [];
97
+ const baseConfig = extendsList.reduce((merged, request)=>{
98
+ const resolved = resolveExtends(request, configDirectory);
99
+ if (!resolved) return merged;
100
+ const parentConfig = readTsConfig(resolved, visited);
101
+ return {
102
+ ...merged,
103
+ compilerOptions: {
104
+ ...merged.compilerOptions ?? {},
105
+ ...parentConfig.compilerOptions ?? {}
106
+ }
107
+ };
108
+ }, {});
109
+ return {
110
+ ...baseConfig,
111
+ compilerOptions: {
112
+ ...baseConfig.compilerOptions ?? {},
113
+ ...config.compilerOptions ?? {}
114
+ }
115
+ };
116
+ };
117
+ const toRelativeConfigPath = (fromDirectory, target)=>{
118
+ const relative = toPosixPath(external_node_path_default().relative(fromDirectory, target));
119
+ if (relative.startsWith('.')) return relative;
120
+ return `./${relative}`;
121
+ };
122
+ const writeFileIfChanged = (file, content)=>{
123
+ if (external_node_fs_default().existsSync(file) && external_node_fs_default().readFileSync(file, 'utf8') === content) return;
124
+ external_node_fs_default().writeFileSync(file, content);
125
+ };
126
+ const createTsgoCheckerConfig = (configFile)=>{
127
+ const configDirectory = external_node_path_default().dirname(configFile);
128
+ const checkerConfigDirectory = external_node_path_default().join(configDirectory, TSGO_CHECKER_DIR);
129
+ const hash = (0, external_node_crypto_namespaceObject.createHash)('sha1').update(configFile).digest('hex').slice(0, 10);
130
+ const checkerConfigFile = external_node_path_default().join(checkerConfigDirectory, `tsconfig.${hash}.json`);
131
+ const tsConfig = readTsConfig(configFile);
132
+ const compilerOptions = {
133
+ baseUrl: null
134
+ };
135
+ const moduleResolution = String(tsConfig.compilerOptions?.moduleResolution).toLowerCase();
136
+ if ([
137
+ 'node',
138
+ 'node10'
139
+ ].includes(moduleResolution)) compilerOptions.moduleResolution = null;
140
+ const checkerConfig = {
141
+ extends: toRelativeConfigPath(checkerConfigDirectory, configFile),
142
+ compilerOptions
143
+ };
144
+ external_node_fs_default().mkdirSync(checkerConfigDirectory, {
145
+ recursive: true
146
+ });
147
+ writeFileIfChanged(checkerConfigFile, `${JSON.stringify(checkerConfig, null, 2)}\n`);
148
+ return checkerConfigFile;
149
+ };
150
+ const normalizeTsgoConfig = (config, rootPath)=>{
151
+ const { typescript } = config;
152
+ if (typescript?.tsgo === false) return config;
153
+ const compilerOptions = {
154
+ ...typescript?.configOverwrite?.compilerOptions ?? {},
155
+ baseUrl: null
156
+ };
157
+ if ([
158
+ 'node',
159
+ 'node10'
160
+ ].includes(String(compilerOptions.moduleResolution).toLowerCase())) compilerOptions.moduleResolution = null;
161
+ config.typescript = {
162
+ ...typescript,
163
+ configOverwrite: {
164
+ ...typescript?.configOverwrite ?? {},
165
+ compilerOptions
166
+ }
167
+ };
168
+ if (typescript?.configFile) config.typescript.configFile = createTsgoCheckerConfig(external_node_path_default().resolve(rootPath, typescript.configFile));
169
+ return config;
170
+ };
50
171
  const withTsgoDefaults = (userOptions, rootPath)=>{
51
172
  const tsgoPath = tryResolve(TSGO_PACKAGE, rootPath) ?? builderRequire.resolve(TSGO_PACKAGE);
52
173
  const userChain = userOptions ? Array.isArray(userOptions) ? userOptions : [
@@ -63,7 +184,7 @@ const withTsgoDefaults = (userOptions, rootPath)=>{
63
184
  (config)=>{
64
185
  const { typescript } = config;
65
186
  if (typescript?.tsgo === false && typescript.typescriptPath === tsgoPath) typescript.typescriptPath = tryResolve("typescript", rootPath);
66
- return config;
187
+ return normalizeTsgoConfig(config, rootPath);
67
188
  }
68
189
  ];
69
190
  };
@@ -2,15 +2,148 @@ import path from "path";
2
2
  const ASYNC_STORAGE_PATTERN = /universal[/\\]async_storage/;
3
3
  const SERVER_LOADER_ENTRY_PATTERN = /[/\\](?:server-loader-combined|route-server-loaders)\.js$/;
4
4
  const RENDER_RSC_SOURCE_PATTERN = /render[/\\].*[/\\]server[/\\]rsc/;
5
- const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc\.mjs$/;
5
+ const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc(?:Worker)?\.mjs$/;
6
+ const RENDER_RSC_RUNTIME = '@modern-js/render/rsc';
7
+ const RENDER_RSC_WORKER_RUNTIME = '@modern-js/render/rsc-worker';
6
8
  const RSC_COMMON_LAYER = 'rsc-common';
7
9
  const ENTRY_NAME_VAR = '__MODERN_JS_ENTRY_NAME';
10
+ const SERVER_ONLY_MARKER_PATTERN = /(?:^|[/\\])server-only[/\\]index\.js(?:\?|$)/;
11
+ const SERVER_ONLY_MESSAGE_PATTERN = /server-only|server only|only works in a Server Component|cannot be imported (?:directly )?(?:from|into) (?:a )?Client Component/i;
12
+ const SERVER_ONLY_DIAGNOSTIC_PREFIX = '[Modern.js RSC server-only diagnostic context]';
8
13
  const createVirtualModule = (content)=>`data:text/javascript,${encodeURIComponent(content)}`;
9
14
  const isAsyncStorageExclude = (exclude)=>{
10
15
  if ('string' == typeof exclude) return ASYNC_STORAGE_PATTERN.test(exclude);
11
16
  if (exclude instanceof RegExp) return exclude.test('universal/async_storage') || exclude.test('universal\\async_storage');
12
17
  return false;
13
18
  };
19
+ const asRecord = (value)=>{
20
+ if (value && 'object' == typeof value && !Array.isArray(value)) return value;
21
+ };
22
+ const disableReactCompilerInSwcLoaders = (value, seen = new WeakSet())=>{
23
+ if (!value || 'object' != typeof value) return;
24
+ if (seen.has(value)) return;
25
+ seen.add(value);
26
+ if (Array.isArray(value)) {
27
+ for (const item of value)disableReactCompilerInSwcLoaders(item, seen);
28
+ return;
29
+ }
30
+ const record = value;
31
+ if ('builtin:swc-loader' === record.loader) {
32
+ let options = asRecord(record.options);
33
+ if (!options) {
34
+ options = {};
35
+ record.options = options;
36
+ }
37
+ let jsc = asRecord(options.jsc);
38
+ if (!jsc) {
39
+ jsc = {};
40
+ options.jsc = jsc;
41
+ }
42
+ let transform = asRecord(jsc.transform);
43
+ if (!transform) {
44
+ transform = {};
45
+ jsc.transform = transform;
46
+ }
47
+ transform.reactCompiler = false;
48
+ }
49
+ for (const item of Object.values(record))disableReactCompilerInSwcLoaders(item, seen);
50
+ };
51
+ const normalizeDiagnosticText = (diagnostic)=>[
52
+ diagnostic.message,
53
+ diagnostic.details,
54
+ diagnostic.file,
55
+ getModulePath(diagnostic.module),
56
+ getModuleIdentifier(diagnostic.module)
57
+ ].filter((item)=>Boolean(item)).join('\n');
58
+ const isServerOnlyDiagnostic = (diagnostic)=>{
59
+ const text = normalizeDiagnosticText(diagnostic);
60
+ return SERVER_ONLY_MARKER_PATTERN.test(text) || SERVER_ONLY_MESSAGE_PATTERN.test(text);
61
+ };
62
+ const isEnrichedServerOnlyDiagnostic = (diagnostic)=>diagnostic.message.includes(SERVER_ONLY_DIAGNOSTIC_PREFIX) || diagnostic.details?.includes(SERVER_ONLY_DIAGNOSTIC_PREFIX);
63
+ const getModulePath = (module)=>{
64
+ if (!module) return;
65
+ return module.resource || module.nameForCondition?.() || module.userRequest;
66
+ };
67
+ const getModuleIdentifier = (module)=>{
68
+ if (!module) return;
69
+ return getModulePath(module) || module.readableIdentifier?.() || module.identifier?.() || module.request || module.rawRequest;
70
+ };
71
+ const formatModuleContext = (module)=>{
72
+ const id = getModuleIdentifier(module);
73
+ if (!id) return;
74
+ const layer = module?.layer ? ` [layer: ${module.layer}]` : '';
75
+ return `${id}${layer}`;
76
+ };
77
+ const getIssuerChain = (compilation, module)=>{
78
+ const chain = [];
79
+ const seen = new Set();
80
+ let current = module;
81
+ while(current && !seen.has(current) && chain.length < 8){
82
+ seen.add(current);
83
+ const issuer = compilation.moduleGraph?.getIssuer?.(current);
84
+ const formatted = formatModuleContext(issuer);
85
+ if (!issuer || !formatted) break;
86
+ chain.push(formatted);
87
+ current = issuer;
88
+ }
89
+ return chain;
90
+ };
91
+ const getModuleTraceChain = (diagnostic)=>{
92
+ const trace = diagnostic.moduleTrace || [];
93
+ const chain = [];
94
+ for (const item of trace){
95
+ const formatted = formatModuleContext(item.origin) || item.originName || formatModuleContext(item.module) || item.moduleName;
96
+ if (formatted && !chain.includes(formatted)) chain.push(formatted);
97
+ }
98
+ return chain.slice(0, 8);
99
+ };
100
+ const appendDiagnosticDetails = (diagnostic, lines)=>{
101
+ const context = `${SERVER_ONLY_DIAGNOSTIC_PREFIX}\n${lines.join('\n')}`;
102
+ diagnostic.details = diagnostic.details ? `${diagnostic.details}\n\n${context}` : context;
103
+ };
104
+ const enrichServerOnlyDiagnostics = (compilation, environmentName)=>{
105
+ const diagnostics = [
106
+ ...compilation.warnings,
107
+ ...compilation.errors
108
+ ];
109
+ for (const diagnostic of diagnostics){
110
+ if (!isServerOnlyDiagnostic(diagnostic) || isEnrichedServerOnlyDiagnostic(diagnostic)) continue;
111
+ const lines = [
112
+ `Environment: ${environmentName || compilation.name || 'unknown'}`
113
+ ];
114
+ const markerModule = formatModuleContext(diagnostic.module);
115
+ if (markerModule) lines.push(`Matched module: ${markerModule}`);
116
+ const issuerChain = getIssuerChain(compilation, diagnostic.module);
117
+ const moduleTraceChain = getModuleTraceChain(diagnostic);
118
+ const importerChain = issuerChain.length > 0 ? issuerChain : moduleTraceChain;
119
+ if (importerChain.length > 0) lines.push(`Importer chain: ${importerChain.join(' -> ')}`);
120
+ appendDiagnosticDetails(diagnostic, lines);
121
+ }
122
+ };
123
+ const applyServerOnlyDiagnosticPlugin = (compiler, environmentName)=>{
124
+ compiler.hooks.thisCompilation.tap('ModernJsServerOnlyDiagnosticContextPlugin', (compilation)=>{
125
+ compilation.hooks.processWarnings.tap('ModernJsServerOnlyDiagnosticContextPlugin', (warnings)=>{
126
+ enrichServerOnlyDiagnostics({
127
+ errors: compilation.errors,
128
+ moduleGraph: compilation.moduleGraph,
129
+ warnings
130
+ }, environmentName || compilation.name || compiler.name);
131
+ return warnings;
132
+ });
133
+ compilation.hooks.afterSeal.tapPromise('ModernJsServerOnlyDiagnosticContextPlugin', async ()=>{
134
+ enrichServerOnlyDiagnostics(compilation, environmentName || compilation.name || compiler.name);
135
+ });
136
+ });
137
+ };
138
+ const applyServerOnlyDiagnosticPlugins = (compiler, environments)=>{
139
+ const compilers = 'compilers' in compiler ? compiler.compilers : [
140
+ compiler
141
+ ];
142
+ compilers.forEach((childCompiler, index)=>{
143
+ const environmentName = childCompiler.name || Object.values(environments).find((environment)=>environment.index === index)?.name;
144
+ applyServerOnlyDiagnosticPlugin(childCompiler, environmentName);
145
+ });
146
+ };
14
147
  function pluginRscConfig() {
15
148
  return {
16
149
  name: 'builder:rsc-config',
@@ -26,6 +159,7 @@ function pluginRscConfig() {
26
159
  api.modifyBundlerChain({
27
160
  handler: (chain, { isServer })=>{
28
161
  if (isServer) {
162
+ chain.resolve.alias.set(`${RENDER_RSC_RUNTIME}$`, RENDER_RSC_WORKER_RUNTIME);
29
163
  const routeFilePattern = /[/\\]routes[/\\](?:.*[/\\])?(?:layout|page|\$)\.[tj]sx?$/;
30
164
  const appFilePattern = /[/\\]App\.[tj]sx?$/;
31
165
  const combinedPattern = new RegExp(`(${routeFilePattern.source}|${appFilePattern.source})`);
@@ -64,6 +198,7 @@ function pluginRscConfig() {
64
198
  }
65
199
  if (config.module?.rules) {
66
200
  const rules = config.module.rules;
201
+ disableReactCompilerInSwcLoaders(rules);
67
202
  for (const rule of rules)if (rule.layer === Layers.rsc) {
68
203
  if (rule.exclude) {
69
204
  if (!Array.isArray(rule.exclude)) rule.exclude = [
@@ -80,6 +215,9 @@ function pluginRscConfig() {
80
215
  });
81
216
  }
82
217
  });
218
+ api.onAfterCreateCompiler(({ compiler, environments })=>{
219
+ applyServerOnlyDiagnosticPlugins(compiler, environments);
220
+ });
83
221
  api.modifyBundlerChain((chain, { isServer, isWebWorker })=>{
84
222
  if (!isServer && !isWebWorker) {
85
223
  const entries = chain.entryPoints.entries();
@@ -117,4 +255,4 @@ async function getRscPlugins(enableRsc, internalDirectory, environments) {
117
255
  }
118
256
  return [];
119
257
  }
120
- export { getRscPlugins, pluginRscConfig };
258
+ export { enrichServerOnlyDiagnostics, getRscPlugins, pluginRscConfig };
@@ -145,7 +145,7 @@ async function parseCommonConfig(builderConfig, options) {
145
145
  const { pluginSourceBuild } = await import("@rsbuild/plugin-source-build");
146
146
  rsbuildPlugins.push(pluginSourceBuild(true === sourceBuild ? {} : sourceBuild));
147
147
  }
148
- rsbuildPlugins.push(pluginReact({
148
+ rsbuildPlugins.push(pluginReact(options?.disableReactCompiler ? {} : {
149
149
  reactCompiler: reactCompiler ?? true
150
150
  }));
151
151
  if (!disableSvgr) {
@@ -1,6 +1,11 @@
1
+ import { createHash } from "node:crypto";
2
+ import node_fs from "node:fs";
1
3
  import { createRequire } from "node:module";
4
+ import node_path from "node:path";
5
+ import { json5 } from "@modern-js/utils";
2
6
  const builderRequire = createRequire(import.meta.url);
3
7
  const TSGO_PACKAGE = "@typescript/native-preview/package.json";
8
+ const TSGO_CHECKER_DIR = node_path.join('.modern-js', 'tsgo');
4
9
  const tryResolve = (request, rootPath)=>{
5
10
  try {
6
11
  return builderRequire.resolve(request, {
@@ -12,6 +17,111 @@ const tryResolve = (request, rootPath)=>{
12
17
  return;
13
18
  }
14
19
  };
20
+ const toPosixPath = (input)=>input.replaceAll(node_path.sep, '/');
21
+ const asTsConfigPath = (request)=>{
22
+ if (node_path.extname(request)) return [
23
+ request
24
+ ];
25
+ return [
26
+ request,
27
+ `${request}.json`
28
+ ];
29
+ };
30
+ const resolveExtends = (request, configDirectory)=>{
31
+ const configRequire = createRequire(node_path.join(configDirectory, 'tsconfig.json'));
32
+ for (const candidate of asTsConfigPath(request)){
33
+ if (candidate.startsWith('.') || node_path.isAbsolute(candidate)) {
34
+ const resolved = node_path.resolve(configDirectory, candidate);
35
+ if (node_fs.existsSync(resolved)) return resolved;
36
+ continue;
37
+ }
38
+ try {
39
+ return configRequire.resolve(candidate);
40
+ } catch {}
41
+ }
42
+ };
43
+ const readTsConfig = (configFile, visited = new Set())=>{
44
+ if (visited.has(configFile) || !node_fs.existsSync(configFile)) return {};
45
+ visited.add(configFile);
46
+ const config = json5.parse(node_fs.readFileSync(configFile, 'utf8'));
47
+ const configDirectory = node_path.dirname(configFile);
48
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [
49
+ config.extends
50
+ ] : [];
51
+ const baseConfig = extendsList.reduce((merged, request)=>{
52
+ const resolved = resolveExtends(request, configDirectory);
53
+ if (!resolved) return merged;
54
+ const parentConfig = readTsConfig(resolved, visited);
55
+ return {
56
+ ...merged,
57
+ compilerOptions: {
58
+ ...merged.compilerOptions ?? {},
59
+ ...parentConfig.compilerOptions ?? {}
60
+ }
61
+ };
62
+ }, {});
63
+ return {
64
+ ...baseConfig,
65
+ compilerOptions: {
66
+ ...baseConfig.compilerOptions ?? {},
67
+ ...config.compilerOptions ?? {}
68
+ }
69
+ };
70
+ };
71
+ const toRelativeConfigPath = (fromDirectory, target)=>{
72
+ const relative = toPosixPath(node_path.relative(fromDirectory, target));
73
+ if (relative.startsWith('.')) return relative;
74
+ return `./${relative}`;
75
+ };
76
+ const writeFileIfChanged = (file, content)=>{
77
+ if (node_fs.existsSync(file) && node_fs.readFileSync(file, 'utf8') === content) return;
78
+ node_fs.writeFileSync(file, content);
79
+ };
80
+ const createTsgoCheckerConfig = (configFile)=>{
81
+ const configDirectory = node_path.dirname(configFile);
82
+ const checkerConfigDirectory = node_path.join(configDirectory, TSGO_CHECKER_DIR);
83
+ const hash = createHash('sha1').update(configFile).digest('hex').slice(0, 10);
84
+ const checkerConfigFile = node_path.join(checkerConfigDirectory, `tsconfig.${hash}.json`);
85
+ const tsConfig = readTsConfig(configFile);
86
+ const compilerOptions = {
87
+ baseUrl: null
88
+ };
89
+ const moduleResolution = String(tsConfig.compilerOptions?.moduleResolution).toLowerCase();
90
+ if ([
91
+ 'node',
92
+ 'node10'
93
+ ].includes(moduleResolution)) compilerOptions.moduleResolution = null;
94
+ const checkerConfig = {
95
+ extends: toRelativeConfigPath(checkerConfigDirectory, configFile),
96
+ compilerOptions
97
+ };
98
+ node_fs.mkdirSync(checkerConfigDirectory, {
99
+ recursive: true
100
+ });
101
+ writeFileIfChanged(checkerConfigFile, `${JSON.stringify(checkerConfig, null, 2)}\n`);
102
+ return checkerConfigFile;
103
+ };
104
+ const normalizeTsgoConfig = (config, rootPath)=>{
105
+ const { typescript } = config;
106
+ if (typescript?.tsgo === false) return config;
107
+ const compilerOptions = {
108
+ ...typescript?.configOverwrite?.compilerOptions ?? {},
109
+ baseUrl: null
110
+ };
111
+ if ([
112
+ 'node',
113
+ 'node10'
114
+ ].includes(String(compilerOptions.moduleResolution).toLowerCase())) compilerOptions.moduleResolution = null;
115
+ config.typescript = {
116
+ ...typescript,
117
+ configOverwrite: {
118
+ ...typescript?.configOverwrite ?? {},
119
+ compilerOptions
120
+ }
121
+ };
122
+ if (typescript?.configFile) config.typescript.configFile = createTsgoCheckerConfig(node_path.resolve(rootPath, typescript.configFile));
123
+ return config;
124
+ };
15
125
  const withTsgoDefaults = (userOptions, rootPath)=>{
16
126
  const tsgoPath = tryResolve(TSGO_PACKAGE, rootPath) ?? builderRequire.resolve(TSGO_PACKAGE);
17
127
  const userChain = userOptions ? Array.isArray(userOptions) ? userOptions : [
@@ -28,7 +138,7 @@ const withTsgoDefaults = (userOptions, rootPath)=>{
28
138
  (config)=>{
29
139
  const { typescript } = config;
30
140
  if (typescript?.tsgo === false && typescript.typescriptPath === tsgoPath) typescript.typescriptPath = tryResolve("typescript", rootPath);
31
- return config;
141
+ return normalizeTsgoConfig(config, rootPath);
32
142
  }
33
143
  ];
34
144
  };
@@ -7,15 +7,148 @@ var rscConfig_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)
7
7
  const ASYNC_STORAGE_PATTERN = /universal[/\\]async_storage/;
8
8
  const SERVER_LOADER_ENTRY_PATTERN = /[/\\](?:server-loader-combined|route-server-loaders)\.js$/;
9
9
  const RENDER_RSC_SOURCE_PATTERN = /render[/\\].*[/\\]server[/\\]rsc/;
10
- const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc\.mjs$/;
10
+ const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc(?:Worker)?\.mjs$/;
11
+ const RENDER_RSC_RUNTIME = '@modern-js/render/rsc';
12
+ const RENDER_RSC_WORKER_RUNTIME = '@modern-js/render/rsc-worker';
11
13
  const RSC_COMMON_LAYER = 'rsc-common';
12
14
  const ENTRY_NAME_VAR = '__MODERN_JS_ENTRY_NAME';
15
+ const SERVER_ONLY_MARKER_PATTERN = /(?:^|[/\\])server-only[/\\]index\.js(?:\?|$)/;
16
+ const SERVER_ONLY_MESSAGE_PATTERN = /server-only|server only|only works in a Server Component|cannot be imported (?:directly )?(?:from|into) (?:a )?Client Component/i;
17
+ const SERVER_ONLY_DIAGNOSTIC_PREFIX = '[Modern.js RSC server-only diagnostic context]';
13
18
  const createVirtualModule = (content)=>`data:text/javascript,${encodeURIComponent(content)}`;
14
19
  const isAsyncStorageExclude = (exclude)=>{
15
20
  if ('string' == typeof exclude) return ASYNC_STORAGE_PATTERN.test(exclude);
16
21
  if (exclude instanceof RegExp) return exclude.test('universal/async_storage') || exclude.test('universal\\async_storage');
17
22
  return false;
18
23
  };
24
+ const asRecord = (value)=>{
25
+ if (value && 'object' == typeof value && !Array.isArray(value)) return value;
26
+ };
27
+ const disableReactCompilerInSwcLoaders = (value, seen = new WeakSet())=>{
28
+ if (!value || 'object' != typeof value) return;
29
+ if (seen.has(value)) return;
30
+ seen.add(value);
31
+ if (Array.isArray(value)) {
32
+ for (const item of value)disableReactCompilerInSwcLoaders(item, seen);
33
+ return;
34
+ }
35
+ const record = value;
36
+ if ('builtin:swc-loader' === record.loader) {
37
+ let options = asRecord(record.options);
38
+ if (!options) {
39
+ options = {};
40
+ record.options = options;
41
+ }
42
+ let jsc = asRecord(options.jsc);
43
+ if (!jsc) {
44
+ jsc = {};
45
+ options.jsc = jsc;
46
+ }
47
+ let transform = asRecord(jsc.transform);
48
+ if (!transform) {
49
+ transform = {};
50
+ jsc.transform = transform;
51
+ }
52
+ transform.reactCompiler = false;
53
+ }
54
+ for (const item of Object.values(record))disableReactCompilerInSwcLoaders(item, seen);
55
+ };
56
+ const normalizeDiagnosticText = (diagnostic)=>[
57
+ diagnostic.message,
58
+ diagnostic.details,
59
+ diagnostic.file,
60
+ getModulePath(diagnostic.module),
61
+ getModuleIdentifier(diagnostic.module)
62
+ ].filter((item)=>Boolean(item)).join('\n');
63
+ const isServerOnlyDiagnostic = (diagnostic)=>{
64
+ const text = normalizeDiagnosticText(diagnostic);
65
+ return SERVER_ONLY_MARKER_PATTERN.test(text) || SERVER_ONLY_MESSAGE_PATTERN.test(text);
66
+ };
67
+ const isEnrichedServerOnlyDiagnostic = (diagnostic)=>diagnostic.message.includes(SERVER_ONLY_DIAGNOSTIC_PREFIX) || diagnostic.details?.includes(SERVER_ONLY_DIAGNOSTIC_PREFIX);
68
+ const getModulePath = (module)=>{
69
+ if (!module) return;
70
+ return module.resource || module.nameForCondition?.() || module.userRequest;
71
+ };
72
+ const getModuleIdentifier = (module)=>{
73
+ if (!module) return;
74
+ return getModulePath(module) || module.readableIdentifier?.() || module.identifier?.() || module.request || module.rawRequest;
75
+ };
76
+ const formatModuleContext = (module)=>{
77
+ const id = getModuleIdentifier(module);
78
+ if (!id) return;
79
+ const layer = module?.layer ? ` [layer: ${module.layer}]` : '';
80
+ return `${id}${layer}`;
81
+ };
82
+ const getIssuerChain = (compilation, module)=>{
83
+ const chain = [];
84
+ const seen = new Set();
85
+ let current = module;
86
+ while(current && !seen.has(current) && chain.length < 8){
87
+ seen.add(current);
88
+ const issuer = compilation.moduleGraph?.getIssuer?.(current);
89
+ const formatted = formatModuleContext(issuer);
90
+ if (!issuer || !formatted) break;
91
+ chain.push(formatted);
92
+ current = issuer;
93
+ }
94
+ return chain;
95
+ };
96
+ const getModuleTraceChain = (diagnostic)=>{
97
+ const trace = diagnostic.moduleTrace || [];
98
+ const chain = [];
99
+ for (const item of trace){
100
+ const formatted = formatModuleContext(item.origin) || item.originName || formatModuleContext(item.module) || item.moduleName;
101
+ if (formatted && !chain.includes(formatted)) chain.push(formatted);
102
+ }
103
+ return chain.slice(0, 8);
104
+ };
105
+ const appendDiagnosticDetails = (diagnostic, lines)=>{
106
+ const context = `${SERVER_ONLY_DIAGNOSTIC_PREFIX}\n${lines.join('\n')}`;
107
+ diagnostic.details = diagnostic.details ? `${diagnostic.details}\n\n${context}` : context;
108
+ };
109
+ const enrichServerOnlyDiagnostics = (compilation, environmentName)=>{
110
+ const diagnostics = [
111
+ ...compilation.warnings,
112
+ ...compilation.errors
113
+ ];
114
+ for (const diagnostic of diagnostics){
115
+ if (!isServerOnlyDiagnostic(diagnostic) || isEnrichedServerOnlyDiagnostic(diagnostic)) continue;
116
+ const lines = [
117
+ `Environment: ${environmentName || compilation.name || 'unknown'}`
118
+ ];
119
+ const markerModule = formatModuleContext(diagnostic.module);
120
+ if (markerModule) lines.push(`Matched module: ${markerModule}`);
121
+ const issuerChain = getIssuerChain(compilation, diagnostic.module);
122
+ const moduleTraceChain = getModuleTraceChain(diagnostic);
123
+ const importerChain = issuerChain.length > 0 ? issuerChain : moduleTraceChain;
124
+ if (importerChain.length > 0) lines.push(`Importer chain: ${importerChain.join(' -> ')}`);
125
+ appendDiagnosticDetails(diagnostic, lines);
126
+ }
127
+ };
128
+ const applyServerOnlyDiagnosticPlugin = (compiler, environmentName)=>{
129
+ compiler.hooks.thisCompilation.tap('ModernJsServerOnlyDiagnosticContextPlugin', (compilation)=>{
130
+ compilation.hooks.processWarnings.tap('ModernJsServerOnlyDiagnosticContextPlugin', (warnings)=>{
131
+ enrichServerOnlyDiagnostics({
132
+ errors: compilation.errors,
133
+ moduleGraph: compilation.moduleGraph,
134
+ warnings
135
+ }, environmentName || compilation.name || compiler.name);
136
+ return warnings;
137
+ });
138
+ compilation.hooks.afterSeal.tapPromise('ModernJsServerOnlyDiagnosticContextPlugin', async ()=>{
139
+ enrichServerOnlyDiagnostics(compilation, environmentName || compilation.name || compiler.name);
140
+ });
141
+ });
142
+ };
143
+ const applyServerOnlyDiagnosticPlugins = (compiler, environments)=>{
144
+ const compilers = 'compilers' in compiler ? compiler.compilers : [
145
+ compiler
146
+ ];
147
+ compilers.forEach((childCompiler, index)=>{
148
+ const environmentName = childCompiler.name || Object.values(environments).find((environment)=>environment.index === index)?.name;
149
+ applyServerOnlyDiagnosticPlugin(childCompiler, environmentName);
150
+ });
151
+ };
19
152
  function pluginRscConfig() {
20
153
  return {
21
154
  name: 'builder:rsc-config',
@@ -31,6 +164,7 @@ function pluginRscConfig() {
31
164
  api.modifyBundlerChain({
32
165
  handler: (chain, { isServer })=>{
33
166
  if (isServer) {
167
+ chain.resolve.alias.set(`${RENDER_RSC_RUNTIME}$`, RENDER_RSC_WORKER_RUNTIME);
34
168
  const routeFilePattern = /[/\\]routes[/\\](?:.*[/\\])?(?:layout|page|\$)\.[tj]sx?$/;
35
169
  const appFilePattern = /[/\\]App\.[tj]sx?$/;
36
170
  const combinedPattern = new RegExp(`(${routeFilePattern.source}|${appFilePattern.source})`);
@@ -69,6 +203,7 @@ function pluginRscConfig() {
69
203
  }
70
204
  if (config.module?.rules) {
71
205
  const rules = config.module.rules;
206
+ disableReactCompilerInSwcLoaders(rules);
72
207
  for (const rule of rules)if (rule.layer === Layers.rsc) {
73
208
  if (rule.exclude) {
74
209
  if (!Array.isArray(rule.exclude)) rule.exclude = [
@@ -85,6 +220,9 @@ function pluginRscConfig() {
85
220
  });
86
221
  }
87
222
  });
223
+ api.onAfterCreateCompiler(({ compiler, environments })=>{
224
+ applyServerOnlyDiagnosticPlugins(compiler, environments);
225
+ });
88
226
  api.modifyBundlerChain((chain, { isServer, isWebWorker })=>{
89
227
  if (!isServer && !isWebWorker) {
90
228
  const entries = chain.entryPoints.entries();
@@ -122,4 +260,4 @@ async function getRscPlugins(enableRsc, internalDirectory, environments) {
122
260
  }
123
261
  return [];
124
262
  }
125
- export { getRscPlugins, pluginRscConfig };
263
+ export { enrichServerOnlyDiagnostics, getRscPlugins, pluginRscConfig };
@@ -146,7 +146,7 @@ async function parseCommonConfig(builderConfig, options) {
146
146
  const { pluginSourceBuild } = await import("@rsbuild/plugin-source-build");
147
147
  rsbuildPlugins.push(pluginSourceBuild(true === sourceBuild ? {} : sourceBuild));
148
148
  }
149
- rsbuildPlugins.push(pluginReact({
149
+ rsbuildPlugins.push(pluginReact(options?.disableReactCompiler ? {} : {
150
150
  reactCompiler: reactCompiler ?? true
151
151
  }));
152
152
  if (!disableSvgr) {
@@ -1,7 +1,12 @@
1
1
  import "node:module";
2
+ import { createHash } from "node:crypto";
3
+ import node_fs from "node:fs";
2
4
  import { createRequire } from "node:module";
5
+ import node_path from "node:path";
6
+ import { json5 } from "@modern-js/utils";
3
7
  const builderRequire = createRequire(import.meta.url);
4
8
  const TSGO_PACKAGE = "@typescript/native-preview/package.json";
9
+ const TSGO_CHECKER_DIR = node_path.join('.modern-js', 'tsgo');
5
10
  const tryResolve = (request, rootPath)=>{
6
11
  try {
7
12
  return builderRequire.resolve(request, {
@@ -13,6 +18,111 @@ const tryResolve = (request, rootPath)=>{
13
18
  return;
14
19
  }
15
20
  };
21
+ const toPosixPath = (input)=>input.replaceAll(node_path.sep, '/');
22
+ const asTsConfigPath = (request)=>{
23
+ if (node_path.extname(request)) return [
24
+ request
25
+ ];
26
+ return [
27
+ request,
28
+ `${request}.json`
29
+ ];
30
+ };
31
+ const resolveExtends = (request, configDirectory)=>{
32
+ const configRequire = createRequire(node_path.join(configDirectory, 'tsconfig.json'));
33
+ for (const candidate of asTsConfigPath(request)){
34
+ if (candidate.startsWith('.') || node_path.isAbsolute(candidate)) {
35
+ const resolved = node_path.resolve(configDirectory, candidate);
36
+ if (node_fs.existsSync(resolved)) return resolved;
37
+ continue;
38
+ }
39
+ try {
40
+ return configRequire.resolve(candidate);
41
+ } catch {}
42
+ }
43
+ };
44
+ const readTsConfig = (configFile, visited = new Set())=>{
45
+ if (visited.has(configFile) || !node_fs.existsSync(configFile)) return {};
46
+ visited.add(configFile);
47
+ const config = json5.parse(node_fs.readFileSync(configFile, 'utf8'));
48
+ const configDirectory = node_path.dirname(configFile);
49
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [
50
+ config.extends
51
+ ] : [];
52
+ const baseConfig = extendsList.reduce((merged, request)=>{
53
+ const resolved = resolveExtends(request, configDirectory);
54
+ if (!resolved) return merged;
55
+ const parentConfig = readTsConfig(resolved, visited);
56
+ return {
57
+ ...merged,
58
+ compilerOptions: {
59
+ ...merged.compilerOptions ?? {},
60
+ ...parentConfig.compilerOptions ?? {}
61
+ }
62
+ };
63
+ }, {});
64
+ return {
65
+ ...baseConfig,
66
+ compilerOptions: {
67
+ ...baseConfig.compilerOptions ?? {},
68
+ ...config.compilerOptions ?? {}
69
+ }
70
+ };
71
+ };
72
+ const toRelativeConfigPath = (fromDirectory, target)=>{
73
+ const relative = toPosixPath(node_path.relative(fromDirectory, target));
74
+ if (relative.startsWith('.')) return relative;
75
+ return `./${relative}`;
76
+ };
77
+ const writeFileIfChanged = (file, content)=>{
78
+ if (node_fs.existsSync(file) && node_fs.readFileSync(file, 'utf8') === content) return;
79
+ node_fs.writeFileSync(file, content);
80
+ };
81
+ const createTsgoCheckerConfig = (configFile)=>{
82
+ const configDirectory = node_path.dirname(configFile);
83
+ const checkerConfigDirectory = node_path.join(configDirectory, TSGO_CHECKER_DIR);
84
+ const hash = createHash('sha1').update(configFile).digest('hex').slice(0, 10);
85
+ const checkerConfigFile = node_path.join(checkerConfigDirectory, `tsconfig.${hash}.json`);
86
+ const tsConfig = readTsConfig(configFile);
87
+ const compilerOptions = {
88
+ baseUrl: null
89
+ };
90
+ const moduleResolution = String(tsConfig.compilerOptions?.moduleResolution).toLowerCase();
91
+ if ([
92
+ 'node',
93
+ 'node10'
94
+ ].includes(moduleResolution)) compilerOptions.moduleResolution = null;
95
+ const checkerConfig = {
96
+ extends: toRelativeConfigPath(checkerConfigDirectory, configFile),
97
+ compilerOptions
98
+ };
99
+ node_fs.mkdirSync(checkerConfigDirectory, {
100
+ recursive: true
101
+ });
102
+ writeFileIfChanged(checkerConfigFile, `${JSON.stringify(checkerConfig, null, 2)}\n`);
103
+ return checkerConfigFile;
104
+ };
105
+ const normalizeTsgoConfig = (config, rootPath)=>{
106
+ const { typescript } = config;
107
+ if (typescript?.tsgo === false) return config;
108
+ const compilerOptions = {
109
+ ...typescript?.configOverwrite?.compilerOptions ?? {},
110
+ baseUrl: null
111
+ };
112
+ if ([
113
+ 'node',
114
+ 'node10'
115
+ ].includes(String(compilerOptions.moduleResolution).toLowerCase())) compilerOptions.moduleResolution = null;
116
+ config.typescript = {
117
+ ...typescript,
118
+ configOverwrite: {
119
+ ...typescript?.configOverwrite ?? {},
120
+ compilerOptions
121
+ }
122
+ };
123
+ if (typescript?.configFile) config.typescript.configFile = createTsgoCheckerConfig(node_path.resolve(rootPath, typescript.configFile));
124
+ return config;
125
+ };
16
126
  const withTsgoDefaults = (userOptions, rootPath)=>{
17
127
  const tsgoPath = tryResolve(TSGO_PACKAGE, rootPath) ?? builderRequire.resolve(TSGO_PACKAGE);
18
128
  const userChain = userOptions ? Array.isArray(userOptions) ? userOptions : [
@@ -29,7 +139,7 @@ const withTsgoDefaults = (userOptions, rootPath)=>{
29
139
  (config)=>{
30
140
  const { typescript } = config;
31
141
  if (typescript?.tsgo === false && typescript.typescriptPath === tsgoPath) typescript.typescriptPath = tryResolve("typescript", rootPath);
32
- return config;
142
+ return normalizeTsgoConfig(config, rootPath);
33
143
  }
34
144
  ];
35
145
  };
@@ -1,4 +1,35 @@
1
1
  import type { RsbuildPlugin } from '@rsbuild/core';
2
+ type RspackDiagnostic = Error & {
3
+ details?: string;
4
+ file?: string;
5
+ module?: DiagnosticModule | null;
6
+ moduleTrace?: Array<{
7
+ module?: DiagnosticModule | null;
8
+ moduleName?: string;
9
+ origin?: DiagnosticModule | null;
10
+ originName?: string;
11
+ }>;
12
+ };
13
+ type DiagnosticModule = {
14
+ resource?: string;
15
+ request?: string;
16
+ userRequest?: string;
17
+ rawRequest?: string;
18
+ layer?: string;
19
+ context?: string;
20
+ identifier?: () => string;
21
+ readableIdentifier?: (requestShortener?: unknown) => string;
22
+ nameForCondition?: () => string | undefined;
23
+ };
24
+ type DiagnosticCompilation = {
25
+ errors: RspackDiagnostic[];
26
+ name?: string;
27
+ moduleGraph?: {
28
+ getIssuer?: (module: DiagnosticModule) => DiagnosticModule | null;
29
+ };
30
+ warnings: RspackDiagnostic[];
31
+ };
32
+ export declare const enrichServerOnlyDiagnostics: (compilation: DiagnosticCompilation, environmentName?: string) => void;
2
33
  /**
3
34
  * Unified plugin for RSC (React Server Components) configuration
4
35
  * Handles:
@@ -25,3 +56,4 @@ export declare function getRscPlugins(enableRsc: boolean, internalDirectory: str
25
56
  server?: string;
26
57
  client?: string;
27
58
  }): Promise<RsbuildPlugin[]>;
59
+ export {};
@@ -33,6 +33,11 @@ export type MetaOptions = {
33
33
  };
34
34
  export type CreateBuilderCommonOptions = {
35
35
  frameworkConfigPath?: string;
36
+ /**
37
+ * Disable Modern's default React Compiler SWC option for consumers whose
38
+ * build pipeline does not support Rspack's `jsc.transform.reactCompiler`.
39
+ */
40
+ disableReactCompiler?: boolean;
36
41
  /** The root path of current project. */
37
42
  cwd: string;
38
43
  rscClientRuntimePath?: string;
@@ -94,7 +99,7 @@ export type BuilderExtraConfig = {
94
99
  */
95
100
  devServer?: ToolsDevServerConfig;
96
101
  /**
97
- * Modify the options of [fork-ts-checker-webpack-plugin](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin).
102
+ * Modify the options of [ts-checker-rspack-plugin](https://github.com/rstackjs/ts-checker-rspack-plugin).
98
103
  */
99
104
  tsChecker?: PluginTypeCheckerOptions['tsCheckerOptions'];
100
105
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bleedingdev/modern-js-builder",
3
- "version": "3.4.0-ultramodern.2",
3
+ "version": "3.4.0-ultramodern.20",
4
4
  "description": "A builder for Modern.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -59,7 +59,7 @@
59
59
  "rsbuild-plugin-rsc": "0.1.1",
60
60
  "rspack-manifest-plugin": "5.2.2",
61
61
  "ts-deepmerge": "8.0.0",
62
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.4.0-ultramodern.2"
62
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.4.0-ultramodern.20"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@rslib/core": "0.23.0",
@@ -68,8 +68,8 @@
68
68
  "react": "^19.2.7",
69
69
  "terser": "^5.48.0",
70
70
  "typescript": "^6.0.3",
71
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.4.0-ultramodern.2",
72
- "@scripts/rstest-config": "2.66.0"
71
+ "@scripts/rstest-config": "2.66.0",
72
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.4.0-ultramodern.20"
73
73
  },
74
74
  "publishConfig": {
75
75
  "access": "public",