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

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.
@@ -45,7 +45,9 @@ var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_na
45
45
  const ASYNC_STORAGE_PATTERN = /universal[/\\]async_storage/;
46
46
  const SERVER_LOADER_ENTRY_PATTERN = /[/\\](?:server-loader-combined|route-server-loaders)\.js$/;
47
47
  const RENDER_RSC_SOURCE_PATTERN = /render[/\\].*[/\\]server[/\\]rsc/;
48
- const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc\.mjs$/;
48
+ const RENDER_RSC_RSLIB_ENTRY_PATTERN = /render[/\\]dist[/\\]esm[/\\]rsc(?:Worker)?\.mjs$/;
49
+ const RENDER_RSC_RUNTIME = '@modern-js/render/rsc';
50
+ const RENDER_RSC_WORKER_RUNTIME = '@modern-js/render/rsc-worker';
49
51
  const RSC_COMMON_LAYER = 'rsc-common';
50
52
  const ENTRY_NAME_VAR = '__MODERN_JS_ENTRY_NAME';
51
53
  const createVirtualModule = (content)=>`data:text/javascript,${encodeURIComponent(content)}`;
@@ -54,6 +56,38 @@ const isAsyncStorageExclude = (exclude)=>{
54
56
  if (exclude instanceof RegExp) return exclude.test('universal/async_storage') || exclude.test('universal\\async_storage');
55
57
  return false;
56
58
  };
59
+ const asRecord = (value)=>{
60
+ if (value && 'object' == typeof value && !Array.isArray(value)) return value;
61
+ };
62
+ const disableReactCompilerInSwcLoaders = (value, seen = new WeakSet())=>{
63
+ if (!value || 'object' != typeof value) return;
64
+ if (seen.has(value)) return;
65
+ seen.add(value);
66
+ if (Array.isArray(value)) {
67
+ for (const item of value)disableReactCompilerInSwcLoaders(item, seen);
68
+ return;
69
+ }
70
+ const record = value;
71
+ if ('builtin:swc-loader' === record.loader) {
72
+ let options = asRecord(record.options);
73
+ if (!options) {
74
+ options = {};
75
+ record.options = options;
76
+ }
77
+ let jsc = asRecord(options.jsc);
78
+ if (!jsc) {
79
+ jsc = {};
80
+ options.jsc = jsc;
81
+ }
82
+ let transform = asRecord(jsc.transform);
83
+ if (!transform) {
84
+ transform = {};
85
+ jsc.transform = transform;
86
+ }
87
+ transform.reactCompiler = false;
88
+ }
89
+ for (const item of Object.values(record))disableReactCompilerInSwcLoaders(item, seen);
90
+ };
57
91
  function pluginRscConfig() {
58
92
  return {
59
93
  name: 'builder:rsc-config',
@@ -69,6 +103,7 @@ function pluginRscConfig() {
69
103
  api.modifyBundlerChain({
70
104
  handler: (chain, { isServer })=>{
71
105
  if (isServer) {
106
+ chain.resolve.alias.set(`${RENDER_RSC_RUNTIME}$`, RENDER_RSC_WORKER_RUNTIME);
72
107
  const routeFilePattern = /[/\\]routes[/\\](?:.*[/\\])?(?:layout|page|\$)\.[tj]sx?$/;
73
108
  const appFilePattern = /[/\\]App\.[tj]sx?$/;
74
109
  const combinedPattern = new RegExp(`(${routeFilePattern.source}|${appFilePattern.source})`);
@@ -107,6 +142,7 @@ function pluginRscConfig() {
107
142
  }
108
143
  if (config.module?.rules) {
109
144
  const rules = config.module.rules;
145
+ disableReactCompilerInSwcLoaders(rules);
110
146
  for (const rule of rules)if (rule.layer === Layers.rsc) {
111
147
  if (rule.exclude) {
112
148
  if (!Array.isArray(rule.exclude)) rule.exclude = [
@@ -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,7 +2,9 @@ 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';
8
10
  const createVirtualModule = (content)=>`data:text/javascript,${encodeURIComponent(content)}`;
@@ -11,6 +13,38 @@ const isAsyncStorageExclude = (exclude)=>{
11
13
  if (exclude instanceof RegExp) return exclude.test('universal/async_storage') || exclude.test('universal\\async_storage');
12
14
  return false;
13
15
  };
16
+ const asRecord = (value)=>{
17
+ if (value && 'object' == typeof value && !Array.isArray(value)) return value;
18
+ };
19
+ const disableReactCompilerInSwcLoaders = (value, seen = new WeakSet())=>{
20
+ if (!value || 'object' != typeof value) return;
21
+ if (seen.has(value)) return;
22
+ seen.add(value);
23
+ if (Array.isArray(value)) {
24
+ for (const item of value)disableReactCompilerInSwcLoaders(item, seen);
25
+ return;
26
+ }
27
+ const record = value;
28
+ if ('builtin:swc-loader' === record.loader) {
29
+ let options = asRecord(record.options);
30
+ if (!options) {
31
+ options = {};
32
+ record.options = options;
33
+ }
34
+ let jsc = asRecord(options.jsc);
35
+ if (!jsc) {
36
+ jsc = {};
37
+ options.jsc = jsc;
38
+ }
39
+ let transform = asRecord(jsc.transform);
40
+ if (!transform) {
41
+ transform = {};
42
+ jsc.transform = transform;
43
+ }
44
+ transform.reactCompiler = false;
45
+ }
46
+ for (const item of Object.values(record))disableReactCompilerInSwcLoaders(item, seen);
47
+ };
14
48
  function pluginRscConfig() {
15
49
  return {
16
50
  name: 'builder:rsc-config',
@@ -26,6 +60,7 @@ function pluginRscConfig() {
26
60
  api.modifyBundlerChain({
27
61
  handler: (chain, { isServer })=>{
28
62
  if (isServer) {
63
+ chain.resolve.alias.set(`${RENDER_RSC_RUNTIME}$`, RENDER_RSC_WORKER_RUNTIME);
29
64
  const routeFilePattern = /[/\\]routes[/\\](?:.*[/\\])?(?:layout|page|\$)\.[tj]sx?$/;
30
65
  const appFilePattern = /[/\\]App\.[tj]sx?$/;
31
66
  const combinedPattern = new RegExp(`(${routeFilePattern.source}|${appFilePattern.source})`);
@@ -64,6 +99,7 @@ function pluginRscConfig() {
64
99
  }
65
100
  if (config.module?.rules) {
66
101
  const rules = config.module.rules;
102
+ disableReactCompilerInSwcLoaders(rules);
67
103
  for (const rule of rules)if (rule.layer === Layers.rsc) {
68
104
  if (rule.exclude) {
69
105
  if (!Array.isArray(rule.exclude)) rule.exclude = [
@@ -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,7 +7,9 @@ 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';
13
15
  const createVirtualModule = (content)=>`data:text/javascript,${encodeURIComponent(content)}`;
@@ -16,6 +18,38 @@ const isAsyncStorageExclude = (exclude)=>{
16
18
  if (exclude instanceof RegExp) return exclude.test('universal/async_storage') || exclude.test('universal\\async_storage');
17
19
  return false;
18
20
  };
21
+ const asRecord = (value)=>{
22
+ if (value && 'object' == typeof value && !Array.isArray(value)) return value;
23
+ };
24
+ const disableReactCompilerInSwcLoaders = (value, seen = new WeakSet())=>{
25
+ if (!value || 'object' != typeof value) return;
26
+ if (seen.has(value)) return;
27
+ seen.add(value);
28
+ if (Array.isArray(value)) {
29
+ for (const item of value)disableReactCompilerInSwcLoaders(item, seen);
30
+ return;
31
+ }
32
+ const record = value;
33
+ if ('builtin:swc-loader' === record.loader) {
34
+ let options = asRecord(record.options);
35
+ if (!options) {
36
+ options = {};
37
+ record.options = options;
38
+ }
39
+ let jsc = asRecord(options.jsc);
40
+ if (!jsc) {
41
+ jsc = {};
42
+ options.jsc = jsc;
43
+ }
44
+ let transform = asRecord(jsc.transform);
45
+ if (!transform) {
46
+ transform = {};
47
+ jsc.transform = transform;
48
+ }
49
+ transform.reactCompiler = false;
50
+ }
51
+ for (const item of Object.values(record))disableReactCompilerInSwcLoaders(item, seen);
52
+ };
19
53
  function pluginRscConfig() {
20
54
  return {
21
55
  name: 'builder:rsc-config',
@@ -31,6 +65,7 @@ function pluginRscConfig() {
31
65
  api.modifyBundlerChain({
32
66
  handler: (chain, { isServer })=>{
33
67
  if (isServer) {
68
+ chain.resolve.alias.set(`${RENDER_RSC_RUNTIME}$`, RENDER_RSC_WORKER_RUNTIME);
34
69
  const routeFilePattern = /[/\\]routes[/\\](?:.*[/\\])?(?:layout|page|\$)\.[tj]sx?$/;
35
70
  const appFilePattern = /[/\\]App\.[tj]sx?$/;
36
71
  const combinedPattern = new RegExp(`(${routeFilePattern.source}|${appFilePattern.source})`);
@@ -69,6 +104,7 @@ function pluginRscConfig() {
69
104
  }
70
105
  if (config.module?.rules) {
71
106
  const rules = config.module.rules;
107
+ disableReactCompilerInSwcLoaders(rules);
72
108
  for (const rule of rules)if (rule.layer === Layers.rsc) {
73
109
  if (rule.exclude) {
74
110
  if (!Array.isArray(rule.exclude)) rule.exclude = [
@@ -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
  };
@@ -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;
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.4",
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.4"
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.4"
73
73
  },
74
74
  "publishConfig": {
75
75
  "access": "public",