@bleedingdev/modern-js-builder 3.9.0-ultramodern.8 → 3.9.0-ultramodern.9

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/cjs/index.js CHANGED
@@ -35,10 +35,12 @@ __webpack_require__.d(__webpack_exports__, {
35
35
  createBuilder: ()=>external_createBuilder_js_namespaceObject.createRspackBuilder,
36
36
  isHtmlDisabled: ()=>utils_js_namespaceObject.isHtmlDisabled,
37
37
  logger: ()=>core_namespaceObject.logger,
38
- parseRspackConfig: ()=>external_createBuilder_js_namespaceObject.parseConfig
38
+ parseRspackConfig: ()=>external_createBuilder_js_namespaceObject.parseConfig,
39
+ refreshTsgoCheckerConfig: ()=>tsgo_js_namespaceObject.refreshTsgoCheckerConfig
39
40
  });
40
41
  const external_createBuilder_js_namespaceObject = require("./createBuilder.js");
41
42
  const core_namespaceObject = require("@rsbuild/core");
43
+ const tsgo_js_namespaceObject = require("./shared/tsgo.js");
42
44
  const utils_js_namespaceObject = require("./shared/utils.js");
43
45
  exports.RUNTIME_CHUNK_NAME = __webpack_exports__.RUNTIME_CHUNK_NAME;
44
46
  exports.RUNTIME_CHUNK_REGEX = __webpack_exports__.RUNTIME_CHUNK_REGEX;
@@ -48,6 +50,7 @@ exports.createBuilder = __webpack_exports__.createBuilder;
48
50
  exports.isHtmlDisabled = __webpack_exports__.isHtmlDisabled;
49
51
  exports.logger = __webpack_exports__.logger;
50
52
  exports.parseRspackConfig = __webpack_exports__.parseRspackConfig;
53
+ exports.refreshTsgoCheckerConfig = __webpack_exports__.refreshTsgoCheckerConfig;
51
54
  for(var __rspack_i in __webpack_exports__)if (-1 === [
52
55
  "RUNTIME_CHUNK_NAME",
53
56
  "RUNTIME_CHUNK_REGEX",
@@ -56,7 +59,8 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
56
59
  "createBuilder",
57
60
  "isHtmlDisabled",
58
61
  "logger",
59
- "parseRspackConfig"
62
+ "parseRspackConfig",
63
+ "refreshTsgoCheckerConfig"
60
64
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
61
65
  Object.defineProperty(exports, '__esModule', {
62
66
  value: true
@@ -43,6 +43,7 @@ const globalVars_js_namespaceObject = require("../plugins/globalVars.js");
43
43
  const htmlMinify_js_namespaceObject = require("../plugins/htmlMinify.js");
44
44
  const runtimeChunk_js_namespaceObject = require("../plugins/runtimeChunk.js");
45
45
  const external_devServer_js_namespaceObject = require("./devServer.js");
46
+ const external_tsgo_js_namespaceObject = require("./tsgo.js");
46
47
  const external_utils_js_namespaceObject = require("./utils.js");
47
48
  const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
48
49
  const GLOBAL_CSS_REGEX = /\.global\.\w+$/;
@@ -168,7 +169,7 @@ async function parseCommonConfig(builderConfig, options) {
168
169
  if (!disableTsChecker) {
169
170
  const { pluginTypeCheck } = await import("@rsbuild/plugin-type-check");
170
171
  rsbuildPlugins.push(pluginTypeCheck({
171
- tsCheckerOptions: tsChecker
172
+ tsCheckerOptions: (0, external_tsgo_js_namespaceObject.withTsgoDefaults)(tsChecker, options?.cwd ?? process.cwd())
172
173
  }));
173
174
  }
174
175
  if (convertToRem) {
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
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
+ }();
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
+ })();
15
+ (()=>{
16
+ __webpack_require__.d = (exports1, getters, values)=>{
17
+ var define = (defs, kind)=>{
18
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
19
+ enumerable: true,
20
+ [kind]: defs[key]
21
+ });
22
+ };
23
+ define(getters, "get");
24
+ define(values, "value");
25
+ };
26
+ })();
27
+ (()=>{
28
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
29
+ })();
30
+ (()=>{
31
+ __webpack_require__.r = (exports1)=>{
32
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
33
+ value: 'Module'
34
+ });
35
+ Object.defineProperty(exports1, '__esModule', {
36
+ value: true
37
+ });
38
+ };
39
+ })();
40
+ var __webpack_exports__ = {};
41
+ __webpack_require__.r(__webpack_exports__);
42
+ __webpack_require__.d(__webpack_exports__, {
43
+ refreshTsgoCheckerConfig: ()=>refreshTsgoCheckerConfig,
44
+ withTsgoDefaults: ()=>withTsgoDefaults
45
+ });
46
+ const external_node_crypto_namespaceObject = require("node:crypto");
47
+ const external_node_fs_namespaceObject = require("node:fs");
48
+ var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
49
+ const external_node_module_namespaceObject = require("node:module");
50
+ const external_node_path_namespaceObject = require("node:path");
51
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
52
+ const utils_namespaceObject = require("@modern-js/utils");
53
+ const builderRequire = (0, external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
54
+ const STABLE_TSGO_PACKAGE = "typescript/package.json";
55
+ const NATIVE_PREVIEW_TSGO_PACKAGE = "@typescript/native-preview/package.json";
56
+ const TSGO_CHECKER_DIR = external_node_path_default().join('.modern-js', 'tsgo');
57
+ const tryResolve = (request, rootPath)=>{
58
+ try {
59
+ return builderRequire.resolve(request, {
60
+ paths: [
61
+ rootPath
62
+ ]
63
+ });
64
+ } catch {
65
+ return;
66
+ }
67
+ };
68
+ const readPackageMajorVersion = (packageJsonPath)=>{
69
+ try {
70
+ const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, 'utf8'));
71
+ const major = Number.parseInt(String(packageJson.version).split('.')[0], 10);
72
+ return Number.isFinite(major) ? major : void 0;
73
+ } catch {
74
+ return;
75
+ }
76
+ };
77
+ const resolveTsgoPackagePath = (rootPath)=>{
78
+ const stableTypeScriptPath = tryResolve(STABLE_TSGO_PACKAGE, rootPath);
79
+ if (stableTypeScriptPath && (readPackageMajorVersion(stableTypeScriptPath) ?? 0) >= 7) return stableTypeScriptPath;
80
+ const previewFromProject = tryResolve(NATIVE_PREVIEW_TSGO_PACKAGE, rootPath);
81
+ if (previewFromProject) return previewFromProject;
82
+ try {
83
+ return builderRequire.resolve(NATIVE_PREVIEW_TSGO_PACKAGE);
84
+ } catch {
85
+ return;
86
+ }
87
+ };
88
+ const toPosixPath = (input)=>input.replaceAll(external_node_path_default().sep, '/');
89
+ const asTsConfigPath = (request)=>{
90
+ if (external_node_path_default().extname(request)) return [
91
+ request
92
+ ];
93
+ return [
94
+ request,
95
+ `${request}.json`
96
+ ];
97
+ };
98
+ const resolveExtends = (request, configDirectory)=>{
99
+ const configRequire = (0, external_node_module_namespaceObject.createRequire)(external_node_path_default().join(configDirectory, 'tsconfig.json'));
100
+ for (const candidate of asTsConfigPath(request)){
101
+ if (candidate.startsWith('.') || external_node_path_default().isAbsolute(candidate)) {
102
+ const resolved = external_node_path_default().resolve(configDirectory, candidate);
103
+ if (external_node_fs_default().existsSync(resolved)) return resolved;
104
+ continue;
105
+ }
106
+ try {
107
+ return configRequire.resolve(candidate);
108
+ } catch {}
109
+ }
110
+ };
111
+ const PATH_COMPILER_OPTIONS = [
112
+ 'rootDir',
113
+ 'outDir',
114
+ 'declarationDir'
115
+ ];
116
+ const absolutiseConfigPaths = (compilerOptions, configDirectory)=>{
117
+ if (!compilerOptions) return {};
118
+ const resolved = {
119
+ ...compilerOptions
120
+ };
121
+ for (const option of PATH_COMPILER_OPTIONS){
122
+ const value = resolved[option];
123
+ if ('string' == typeof value && !external_node_path_default().isAbsolute(value)) resolved[option] = external_node_path_default().resolve(configDirectory, value);
124
+ }
125
+ return resolved;
126
+ };
127
+ const readTsConfig = (configFile, visited = new Set())=>{
128
+ if (visited.has(configFile) || !external_node_fs_default().existsSync(configFile)) return {};
129
+ visited.add(configFile);
130
+ const config = utils_namespaceObject.json5.parse(external_node_fs_default().readFileSync(configFile, 'utf8'));
131
+ const configDirectory = external_node_path_default().dirname(configFile);
132
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [
133
+ config.extends
134
+ ] : [];
135
+ const baseConfig = extendsList.reduce((merged, request)=>{
136
+ const resolved = resolveExtends(request, configDirectory);
137
+ if (!resolved) return merged;
138
+ const parentConfig = readTsConfig(resolved, visited);
139
+ return {
140
+ ...merged,
141
+ compilerOptions: {
142
+ ...merged.compilerOptions ?? {},
143
+ ...parentConfig.compilerOptions ?? {}
144
+ }
145
+ };
146
+ }, {});
147
+ return {
148
+ ...baseConfig,
149
+ compilerOptions: {
150
+ ...baseConfig.compilerOptions ?? {},
151
+ ...absolutiseConfigPaths(config.compilerOptions, configDirectory)
152
+ }
153
+ };
154
+ };
155
+ const readProjectReferences = (configFile)=>{
156
+ if (!external_node_fs_default().existsSync(configFile)) return [];
157
+ const config = utils_namespaceObject.json5.parse(external_node_fs_default().readFileSync(configFile, 'utf8'));
158
+ if (!Array.isArray(config.references)) return [];
159
+ const configDirectory = external_node_path_default().dirname(configFile);
160
+ return config.references.filter((reference)=>'string' == typeof reference?.path).map((reference)=>({
161
+ ...reference,
162
+ path: toPosixPath(external_node_path_default().resolve(configDirectory, reference.path))
163
+ }));
164
+ };
165
+ const toRelativeConfigPath = (fromDirectory, target)=>{
166
+ const relative = toPosixPath(external_node_path_default().relative(fromDirectory, target));
167
+ if (relative.startsWith('.')) return relative;
168
+ return `./${relative}`;
169
+ };
170
+ const writeFileIfChanged = (file, content)=>{
171
+ if (external_node_fs_default().existsSync(file) && external_node_fs_default().readFileSync(file, 'utf8') === content) return;
172
+ external_node_fs_default().writeFileSync(file, content);
173
+ };
174
+ const defaultTsgoCheckerConfigFile = (configFile)=>{
175
+ const hash = (0, external_node_crypto_namespaceObject.createHash)('sha1').update(configFile).digest('hex').slice(0, 10);
176
+ return external_node_path_default().join(external_node_path_default().dirname(configFile), TSGO_CHECKER_DIR, `tsconfig.${hash}.json`);
177
+ };
178
+ const createTsgoCheckerConfig = (configFile, checkerConfigFile = defaultTsgoCheckerConfigFile(configFile))=>{
179
+ const configDirectory = external_node_path_default().dirname(configFile);
180
+ const checkerConfigDirectory = external_node_path_default().dirname(checkerConfigFile);
181
+ const tsConfig = readTsConfig(configFile);
182
+ const compilerOptions = {
183
+ baseUrl: null
184
+ };
185
+ const declaredRootDir = tsConfig.compilerOptions?.rootDir;
186
+ if ('string' == typeof declaredRootDir) compilerOptions.rootDir = toPosixPath(declaredRootDir);
187
+ else if (tsConfig.compilerOptions?.composite === true) compilerOptions.rootDir = toPosixPath(configDirectory);
188
+ const moduleResolution = String(tsConfig.compilerOptions?.moduleResolution).toLowerCase();
189
+ if ([
190
+ 'node',
191
+ 'node10'
192
+ ].includes(moduleResolution)) compilerOptions.moduleResolution = null;
193
+ const references = readProjectReferences(configFile);
194
+ const checkerConfig = {
195
+ extends: toRelativeConfigPath(checkerConfigDirectory, configFile),
196
+ compilerOptions,
197
+ ...references.length > 0 ? {
198
+ references
199
+ } : {}
200
+ };
201
+ external_node_fs_default().mkdirSync(checkerConfigDirectory, {
202
+ recursive: true
203
+ });
204
+ writeFileIfChanged(checkerConfigFile, `${JSON.stringify(checkerConfig, null, 2)}\n`);
205
+ return checkerConfigFile;
206
+ };
207
+ const refreshTsgoCheckerConfig = (checkerConfigFile)=>{
208
+ const checkerConfigDirectory = external_node_path_default().dirname(checkerConfigFile);
209
+ if ('tsgo' !== external_node_path_default().basename(checkerConfigDirectory) || '.modern-js' !== external_node_path_default().basename(external_node_path_default().dirname(checkerConfigDirectory)) || !external_node_fs_default().existsSync(checkerConfigFile)) return;
210
+ let checkerConfig;
211
+ try {
212
+ checkerConfig = utils_namespaceObject.json5.parse(external_node_fs_default().readFileSync(checkerConfigFile, 'utf8'));
213
+ } catch {
214
+ return;
215
+ }
216
+ if ('string' != typeof checkerConfig.extends) return;
217
+ const projectConfigFile = external_node_path_default().resolve(checkerConfigDirectory, checkerConfig.extends);
218
+ if (external_node_fs_default().existsSync(projectConfigFile)) try {
219
+ createTsgoCheckerConfig(projectConfigFile, checkerConfigFile);
220
+ } catch {}
221
+ return projectConfigFile;
222
+ };
223
+ const normalizeTsgoConfig = (config, rootPath)=>{
224
+ const { typescript } = config;
225
+ if (typescript?.tsgo === false) return config;
226
+ const compilerOptions = {
227
+ ...typescript?.configOverwrite?.compilerOptions ?? {},
228
+ baseUrl: null
229
+ };
230
+ if ([
231
+ 'node',
232
+ 'node10'
233
+ ].includes(String(compilerOptions.moduleResolution).toLowerCase())) compilerOptions.moduleResolution = null;
234
+ config.typescript = {
235
+ ...typescript,
236
+ configOverwrite: {
237
+ ...typescript?.configOverwrite ?? {},
238
+ compilerOptions
239
+ }
240
+ };
241
+ if (typescript?.configFile) config.typescript.configFile = createTsgoCheckerConfig(external_node_path_default().resolve(rootPath, typescript.configFile));
242
+ return config;
243
+ };
244
+ const withTsgoDefaults = (userOptions, rootPath)=>{
245
+ const tsgoPath = resolveTsgoPackagePath(rootPath);
246
+ const userChain = userOptions ? Array.isArray(userOptions) ? userOptions : [
247
+ userOptions
248
+ ] : [];
249
+ return [
250
+ {
251
+ typescript: tsgoPath ? {
252
+ tsgo: true,
253
+ typescriptPath: tsgoPath
254
+ } : {
255
+ tsgo: true
256
+ }
257
+ },
258
+ ...userChain,
259
+ (config)=>{
260
+ const { typescript } = config;
261
+ if (typescript?.tsgo === false && typescript.typescriptPath === tsgoPath) typescript.typescriptPath = tryResolve("typescript", rootPath);
262
+ return normalizeTsgoConfig(config, rootPath);
263
+ }
264
+ ];
265
+ };
266
+ exports.refreshTsgoCheckerConfig = __webpack_exports__.refreshTsgoCheckerConfig;
267
+ exports.withTsgoDefaults = __webpack_exports__.withTsgoDefaults;
268
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
269
+ "refreshTsgoCheckerConfig",
270
+ "withTsgoDefaults"
271
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
272
+ Object.defineProperty(exports, '__esModule', {
273
+ value: true
274
+ });
@@ -1,3 +1,4 @@
1
1
  export { createRspackBuilder as createBuilder, parseConfig as parseRspackConfig } from "./createBuilder.mjs";
2
2
  export { logger } from "@rsbuild/core";
3
+ export { refreshTsgoCheckerConfig } from "./shared/tsgo.mjs";
3
4
  export { RUNTIME_CHUNK_NAME, RUNTIME_CHUNK_REGEX, SERVICE_WORKER_ENVIRONMENT_NAME, castArray, isHtmlDisabled } from "./shared/utils.mjs";
@@ -10,6 +10,7 @@ import { pluginGlobalVars } from "../plugins/globalVars.mjs";
10
10
  import { pluginHtmlMinifierTerser } from "../plugins/htmlMinify.mjs";
11
11
  import { pluginRuntimeChunk } from "../plugins/runtimeChunk.mjs";
12
12
  import { transformToRsbuildServerOptions } from "./devServer.mjs";
13
+ import { withTsgoDefaults } from "./tsgo.mjs";
13
14
  import { NODE_MODULES_REGEX } from "./utils.mjs";
14
15
  const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
15
16
  const GLOBAL_CSS_REGEX = /\.global\.\w+$/;
@@ -135,7 +136,7 @@ async function parseCommonConfig(builderConfig, options) {
135
136
  if (!disableTsChecker) {
136
137
  const { pluginTypeCheck } = await import("@rsbuild/plugin-type-check");
137
138
  rsbuildPlugins.push(pluginTypeCheck({
138
- tsCheckerOptions: tsChecker
139
+ tsCheckerOptions: withTsgoDefaults(tsChecker, options?.cwd ?? process.cwd())
139
140
  }));
140
141
  }
141
142
  if (convertToRem) {
@@ -0,0 +1,219 @@
1
+ import { createHash } from "node:crypto";
2
+ import node_fs from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import node_path from "node:path";
5
+ import { json5 } from "@modern-js/utils";
6
+ const builderRequire = createRequire(import.meta.url);
7
+ const STABLE_TSGO_PACKAGE = "typescript/package.json";
8
+ const NATIVE_PREVIEW_TSGO_PACKAGE = "@typescript/native-preview/package.json";
9
+ const TSGO_CHECKER_DIR = node_path.join('.modern-js', 'tsgo');
10
+ const tryResolve = (request, rootPath)=>{
11
+ try {
12
+ return builderRequire.resolve(request, {
13
+ paths: [
14
+ rootPath
15
+ ]
16
+ });
17
+ } catch {
18
+ return;
19
+ }
20
+ };
21
+ const readPackageMajorVersion = (packageJsonPath)=>{
22
+ try {
23
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf8'));
24
+ const major = Number.parseInt(String(packageJson.version).split('.')[0], 10);
25
+ return Number.isFinite(major) ? major : void 0;
26
+ } catch {
27
+ return;
28
+ }
29
+ };
30
+ const resolveTsgoPackagePath = (rootPath)=>{
31
+ const stableTypeScriptPath = tryResolve(STABLE_TSGO_PACKAGE, rootPath);
32
+ if (stableTypeScriptPath && (readPackageMajorVersion(stableTypeScriptPath) ?? 0) >= 7) return stableTypeScriptPath;
33
+ const previewFromProject = tryResolve(NATIVE_PREVIEW_TSGO_PACKAGE, rootPath);
34
+ if (previewFromProject) return previewFromProject;
35
+ try {
36
+ return builderRequire.resolve(NATIVE_PREVIEW_TSGO_PACKAGE);
37
+ } catch {
38
+ return;
39
+ }
40
+ };
41
+ const toPosixPath = (input)=>input.replaceAll(node_path.sep, '/');
42
+ const asTsConfigPath = (request)=>{
43
+ if (node_path.extname(request)) return [
44
+ request
45
+ ];
46
+ return [
47
+ request,
48
+ `${request}.json`
49
+ ];
50
+ };
51
+ const resolveExtends = (request, configDirectory)=>{
52
+ const configRequire = createRequire(node_path.join(configDirectory, 'tsconfig.json'));
53
+ for (const candidate of asTsConfigPath(request)){
54
+ if (candidate.startsWith('.') || node_path.isAbsolute(candidate)) {
55
+ const resolved = node_path.resolve(configDirectory, candidate);
56
+ if (node_fs.existsSync(resolved)) return resolved;
57
+ continue;
58
+ }
59
+ try {
60
+ return configRequire.resolve(candidate);
61
+ } catch {}
62
+ }
63
+ };
64
+ const PATH_COMPILER_OPTIONS = [
65
+ 'rootDir',
66
+ 'outDir',
67
+ 'declarationDir'
68
+ ];
69
+ const absolutiseConfigPaths = (compilerOptions, configDirectory)=>{
70
+ if (!compilerOptions) return {};
71
+ const resolved = {
72
+ ...compilerOptions
73
+ };
74
+ for (const option of PATH_COMPILER_OPTIONS){
75
+ const value = resolved[option];
76
+ if ('string' == typeof value && !node_path.isAbsolute(value)) resolved[option] = node_path.resolve(configDirectory, value);
77
+ }
78
+ return resolved;
79
+ };
80
+ const readTsConfig = (configFile, visited = new Set())=>{
81
+ if (visited.has(configFile) || !node_fs.existsSync(configFile)) return {};
82
+ visited.add(configFile);
83
+ const config = json5.parse(node_fs.readFileSync(configFile, 'utf8'));
84
+ const configDirectory = node_path.dirname(configFile);
85
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [
86
+ config.extends
87
+ ] : [];
88
+ const baseConfig = extendsList.reduce((merged, request)=>{
89
+ const resolved = resolveExtends(request, configDirectory);
90
+ if (!resolved) return merged;
91
+ const parentConfig = readTsConfig(resolved, visited);
92
+ return {
93
+ ...merged,
94
+ compilerOptions: {
95
+ ...merged.compilerOptions ?? {},
96
+ ...parentConfig.compilerOptions ?? {}
97
+ }
98
+ };
99
+ }, {});
100
+ return {
101
+ ...baseConfig,
102
+ compilerOptions: {
103
+ ...baseConfig.compilerOptions ?? {},
104
+ ...absolutiseConfigPaths(config.compilerOptions, configDirectory)
105
+ }
106
+ };
107
+ };
108
+ const readProjectReferences = (configFile)=>{
109
+ if (!node_fs.existsSync(configFile)) return [];
110
+ const config = json5.parse(node_fs.readFileSync(configFile, 'utf8'));
111
+ if (!Array.isArray(config.references)) return [];
112
+ const configDirectory = node_path.dirname(configFile);
113
+ return config.references.filter((reference)=>'string' == typeof reference?.path).map((reference)=>({
114
+ ...reference,
115
+ path: toPosixPath(node_path.resolve(configDirectory, reference.path))
116
+ }));
117
+ };
118
+ const toRelativeConfigPath = (fromDirectory, target)=>{
119
+ const relative = toPosixPath(node_path.relative(fromDirectory, target));
120
+ if (relative.startsWith('.')) return relative;
121
+ return `./${relative}`;
122
+ };
123
+ const writeFileIfChanged = (file, content)=>{
124
+ if (node_fs.existsSync(file) && node_fs.readFileSync(file, 'utf8') === content) return;
125
+ node_fs.writeFileSync(file, content);
126
+ };
127
+ const defaultTsgoCheckerConfigFile = (configFile)=>{
128
+ const hash = createHash('sha1').update(configFile).digest('hex').slice(0, 10);
129
+ return node_path.join(node_path.dirname(configFile), TSGO_CHECKER_DIR, `tsconfig.${hash}.json`);
130
+ };
131
+ const createTsgoCheckerConfig = (configFile, checkerConfigFile = defaultTsgoCheckerConfigFile(configFile))=>{
132
+ const configDirectory = node_path.dirname(configFile);
133
+ const checkerConfigDirectory = node_path.dirname(checkerConfigFile);
134
+ const tsConfig = readTsConfig(configFile);
135
+ const compilerOptions = {
136
+ baseUrl: null
137
+ };
138
+ const declaredRootDir = tsConfig.compilerOptions?.rootDir;
139
+ if ('string' == typeof declaredRootDir) compilerOptions.rootDir = toPosixPath(declaredRootDir);
140
+ else if (tsConfig.compilerOptions?.composite === true) compilerOptions.rootDir = toPosixPath(configDirectory);
141
+ const moduleResolution = String(tsConfig.compilerOptions?.moduleResolution).toLowerCase();
142
+ if ([
143
+ 'node',
144
+ 'node10'
145
+ ].includes(moduleResolution)) compilerOptions.moduleResolution = null;
146
+ const references = readProjectReferences(configFile);
147
+ const checkerConfig = {
148
+ extends: toRelativeConfigPath(checkerConfigDirectory, configFile),
149
+ compilerOptions,
150
+ ...references.length > 0 ? {
151
+ references
152
+ } : {}
153
+ };
154
+ node_fs.mkdirSync(checkerConfigDirectory, {
155
+ recursive: true
156
+ });
157
+ writeFileIfChanged(checkerConfigFile, `${JSON.stringify(checkerConfig, null, 2)}\n`);
158
+ return checkerConfigFile;
159
+ };
160
+ const refreshTsgoCheckerConfig = (checkerConfigFile)=>{
161
+ const checkerConfigDirectory = node_path.dirname(checkerConfigFile);
162
+ if ('tsgo' !== node_path.basename(checkerConfigDirectory) || '.modern-js' !== node_path.basename(node_path.dirname(checkerConfigDirectory)) || !node_fs.existsSync(checkerConfigFile)) return;
163
+ let checkerConfig;
164
+ try {
165
+ checkerConfig = json5.parse(node_fs.readFileSync(checkerConfigFile, 'utf8'));
166
+ } catch {
167
+ return;
168
+ }
169
+ if ('string' != typeof checkerConfig.extends) return;
170
+ const projectConfigFile = node_path.resolve(checkerConfigDirectory, checkerConfig.extends);
171
+ if (node_fs.existsSync(projectConfigFile)) try {
172
+ createTsgoCheckerConfig(projectConfigFile, checkerConfigFile);
173
+ } catch {}
174
+ return projectConfigFile;
175
+ };
176
+ const normalizeTsgoConfig = (config, rootPath)=>{
177
+ const { typescript } = config;
178
+ if (typescript?.tsgo === false) return config;
179
+ const compilerOptions = {
180
+ ...typescript?.configOverwrite?.compilerOptions ?? {},
181
+ baseUrl: null
182
+ };
183
+ if ([
184
+ 'node',
185
+ 'node10'
186
+ ].includes(String(compilerOptions.moduleResolution).toLowerCase())) compilerOptions.moduleResolution = null;
187
+ config.typescript = {
188
+ ...typescript,
189
+ configOverwrite: {
190
+ ...typescript?.configOverwrite ?? {},
191
+ compilerOptions
192
+ }
193
+ };
194
+ if (typescript?.configFile) config.typescript.configFile = createTsgoCheckerConfig(node_path.resolve(rootPath, typescript.configFile));
195
+ return config;
196
+ };
197
+ const withTsgoDefaults = (userOptions, rootPath)=>{
198
+ const tsgoPath = resolveTsgoPackagePath(rootPath);
199
+ const userChain = userOptions ? Array.isArray(userOptions) ? userOptions : [
200
+ userOptions
201
+ ] : [];
202
+ return [
203
+ {
204
+ typescript: tsgoPath ? {
205
+ tsgo: true,
206
+ typescriptPath: tsgoPath
207
+ } : {
208
+ tsgo: true
209
+ }
210
+ },
211
+ ...userChain,
212
+ (config)=>{
213
+ const { typescript } = config;
214
+ if (typescript?.tsgo === false && typescript.typescriptPath === tsgoPath) typescript.typescriptPath = tryResolve("typescript", rootPath);
215
+ return normalizeTsgoConfig(config, rootPath);
216
+ }
217
+ ];
218
+ };
219
+ export { refreshTsgoCheckerConfig, withTsgoDefaults };
@@ -1,4 +1,5 @@
1
1
  import "node:module";
2
2
  export { createRspackBuilder as createBuilder, parseConfig as parseRspackConfig } from "./createBuilder.mjs";
3
3
  export { logger } from "@rsbuild/core";
4
+ export { refreshTsgoCheckerConfig } from "./shared/tsgo.mjs";
4
5
  export { RUNTIME_CHUNK_NAME, RUNTIME_CHUNK_REGEX, SERVICE_WORKER_ENVIRONMENT_NAME, castArray, isHtmlDisabled } from "./shared/utils.mjs";
@@ -11,6 +11,7 @@ import { pluginGlobalVars } from "../plugins/globalVars.mjs";
11
11
  import { pluginHtmlMinifierTerser } from "../plugins/htmlMinify.mjs";
12
12
  import { pluginRuntimeChunk } from "../plugins/runtimeChunk.mjs";
13
13
  import { transformToRsbuildServerOptions } from "./devServer.mjs";
14
+ import { withTsgoDefaults } from "./tsgo.mjs";
14
15
  import { NODE_MODULES_REGEX } from "./utils.mjs";
15
16
  const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
16
17
  const GLOBAL_CSS_REGEX = /\.global\.\w+$/;
@@ -136,7 +137,7 @@ async function parseCommonConfig(builderConfig, options) {
136
137
  if (!disableTsChecker) {
137
138
  const { pluginTypeCheck } = await import("@rsbuild/plugin-type-check");
138
139
  rsbuildPlugins.push(pluginTypeCheck({
139
- tsCheckerOptions: tsChecker
140
+ tsCheckerOptions: withTsgoDefaults(tsChecker, options?.cwd ?? process.cwd())
140
141
  }));
141
142
  }
142
143
  if (convertToRem) {
@@ -0,0 +1,220 @@
1
+ import "node:module";
2
+ import { createHash } from "node:crypto";
3
+ import node_fs from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import node_path from "node:path";
6
+ import { json5 } from "@modern-js/utils";
7
+ const builderRequire = createRequire(import.meta.url);
8
+ const STABLE_TSGO_PACKAGE = "typescript/package.json";
9
+ const NATIVE_PREVIEW_TSGO_PACKAGE = "@typescript/native-preview/package.json";
10
+ const TSGO_CHECKER_DIR = node_path.join('.modern-js', 'tsgo');
11
+ const tryResolve = (request, rootPath)=>{
12
+ try {
13
+ return builderRequire.resolve(request, {
14
+ paths: [
15
+ rootPath
16
+ ]
17
+ });
18
+ } catch {
19
+ return;
20
+ }
21
+ };
22
+ const readPackageMajorVersion = (packageJsonPath)=>{
23
+ try {
24
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf8'));
25
+ const major = Number.parseInt(String(packageJson.version).split('.')[0], 10);
26
+ return Number.isFinite(major) ? major : void 0;
27
+ } catch {
28
+ return;
29
+ }
30
+ };
31
+ const resolveTsgoPackagePath = (rootPath)=>{
32
+ const stableTypeScriptPath = tryResolve(STABLE_TSGO_PACKAGE, rootPath);
33
+ if (stableTypeScriptPath && (readPackageMajorVersion(stableTypeScriptPath) ?? 0) >= 7) return stableTypeScriptPath;
34
+ const previewFromProject = tryResolve(NATIVE_PREVIEW_TSGO_PACKAGE, rootPath);
35
+ if (previewFromProject) return previewFromProject;
36
+ try {
37
+ return builderRequire.resolve(NATIVE_PREVIEW_TSGO_PACKAGE);
38
+ } catch {
39
+ return;
40
+ }
41
+ };
42
+ const toPosixPath = (input)=>input.replaceAll(node_path.sep, '/');
43
+ const asTsConfigPath = (request)=>{
44
+ if (node_path.extname(request)) return [
45
+ request
46
+ ];
47
+ return [
48
+ request,
49
+ `${request}.json`
50
+ ];
51
+ };
52
+ const resolveExtends = (request, configDirectory)=>{
53
+ const configRequire = createRequire(node_path.join(configDirectory, 'tsconfig.json'));
54
+ for (const candidate of asTsConfigPath(request)){
55
+ if (candidate.startsWith('.') || node_path.isAbsolute(candidate)) {
56
+ const resolved = node_path.resolve(configDirectory, candidate);
57
+ if (node_fs.existsSync(resolved)) return resolved;
58
+ continue;
59
+ }
60
+ try {
61
+ return configRequire.resolve(candidate);
62
+ } catch {}
63
+ }
64
+ };
65
+ const PATH_COMPILER_OPTIONS = [
66
+ 'rootDir',
67
+ 'outDir',
68
+ 'declarationDir'
69
+ ];
70
+ const absolutiseConfigPaths = (compilerOptions, configDirectory)=>{
71
+ if (!compilerOptions) return {};
72
+ const resolved = {
73
+ ...compilerOptions
74
+ };
75
+ for (const option of PATH_COMPILER_OPTIONS){
76
+ const value = resolved[option];
77
+ if ('string' == typeof value && !node_path.isAbsolute(value)) resolved[option] = node_path.resolve(configDirectory, value);
78
+ }
79
+ return resolved;
80
+ };
81
+ const readTsConfig = (configFile, visited = new Set())=>{
82
+ if (visited.has(configFile) || !node_fs.existsSync(configFile)) return {};
83
+ visited.add(configFile);
84
+ const config = json5.parse(node_fs.readFileSync(configFile, 'utf8'));
85
+ const configDirectory = node_path.dirname(configFile);
86
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [
87
+ config.extends
88
+ ] : [];
89
+ const baseConfig = extendsList.reduce((merged, request)=>{
90
+ const resolved = resolveExtends(request, configDirectory);
91
+ if (!resolved) return merged;
92
+ const parentConfig = readTsConfig(resolved, visited);
93
+ return {
94
+ ...merged,
95
+ compilerOptions: {
96
+ ...merged.compilerOptions ?? {},
97
+ ...parentConfig.compilerOptions ?? {}
98
+ }
99
+ };
100
+ }, {});
101
+ return {
102
+ ...baseConfig,
103
+ compilerOptions: {
104
+ ...baseConfig.compilerOptions ?? {},
105
+ ...absolutiseConfigPaths(config.compilerOptions, configDirectory)
106
+ }
107
+ };
108
+ };
109
+ const readProjectReferences = (configFile)=>{
110
+ if (!node_fs.existsSync(configFile)) return [];
111
+ const config = json5.parse(node_fs.readFileSync(configFile, 'utf8'));
112
+ if (!Array.isArray(config.references)) return [];
113
+ const configDirectory = node_path.dirname(configFile);
114
+ return config.references.filter((reference)=>'string' == typeof reference?.path).map((reference)=>({
115
+ ...reference,
116
+ path: toPosixPath(node_path.resolve(configDirectory, reference.path))
117
+ }));
118
+ };
119
+ const toRelativeConfigPath = (fromDirectory, target)=>{
120
+ const relative = toPosixPath(node_path.relative(fromDirectory, target));
121
+ if (relative.startsWith('.')) return relative;
122
+ return `./${relative}`;
123
+ };
124
+ const writeFileIfChanged = (file, content)=>{
125
+ if (node_fs.existsSync(file) && node_fs.readFileSync(file, 'utf8') === content) return;
126
+ node_fs.writeFileSync(file, content);
127
+ };
128
+ const defaultTsgoCheckerConfigFile = (configFile)=>{
129
+ const hash = createHash('sha1').update(configFile).digest('hex').slice(0, 10);
130
+ return node_path.join(node_path.dirname(configFile), TSGO_CHECKER_DIR, `tsconfig.${hash}.json`);
131
+ };
132
+ const createTsgoCheckerConfig = (configFile, checkerConfigFile = defaultTsgoCheckerConfigFile(configFile))=>{
133
+ const configDirectory = node_path.dirname(configFile);
134
+ const checkerConfigDirectory = node_path.dirname(checkerConfigFile);
135
+ const tsConfig = readTsConfig(configFile);
136
+ const compilerOptions = {
137
+ baseUrl: null
138
+ };
139
+ const declaredRootDir = tsConfig.compilerOptions?.rootDir;
140
+ if ('string' == typeof declaredRootDir) compilerOptions.rootDir = toPosixPath(declaredRootDir);
141
+ else if (tsConfig.compilerOptions?.composite === true) compilerOptions.rootDir = toPosixPath(configDirectory);
142
+ const moduleResolution = String(tsConfig.compilerOptions?.moduleResolution).toLowerCase();
143
+ if ([
144
+ 'node',
145
+ 'node10'
146
+ ].includes(moduleResolution)) compilerOptions.moduleResolution = null;
147
+ const references = readProjectReferences(configFile);
148
+ const checkerConfig = {
149
+ extends: toRelativeConfigPath(checkerConfigDirectory, configFile),
150
+ compilerOptions,
151
+ ...references.length > 0 ? {
152
+ references
153
+ } : {}
154
+ };
155
+ node_fs.mkdirSync(checkerConfigDirectory, {
156
+ recursive: true
157
+ });
158
+ writeFileIfChanged(checkerConfigFile, `${JSON.stringify(checkerConfig, null, 2)}\n`);
159
+ return checkerConfigFile;
160
+ };
161
+ const refreshTsgoCheckerConfig = (checkerConfigFile)=>{
162
+ const checkerConfigDirectory = node_path.dirname(checkerConfigFile);
163
+ if ('tsgo' !== node_path.basename(checkerConfigDirectory) || '.modern-js' !== node_path.basename(node_path.dirname(checkerConfigDirectory)) || !node_fs.existsSync(checkerConfigFile)) return;
164
+ let checkerConfig;
165
+ try {
166
+ checkerConfig = json5.parse(node_fs.readFileSync(checkerConfigFile, 'utf8'));
167
+ } catch {
168
+ return;
169
+ }
170
+ if ('string' != typeof checkerConfig.extends) return;
171
+ const projectConfigFile = node_path.resolve(checkerConfigDirectory, checkerConfig.extends);
172
+ if (node_fs.existsSync(projectConfigFile)) try {
173
+ createTsgoCheckerConfig(projectConfigFile, checkerConfigFile);
174
+ } catch {}
175
+ return projectConfigFile;
176
+ };
177
+ const normalizeTsgoConfig = (config, rootPath)=>{
178
+ const { typescript } = config;
179
+ if (typescript?.tsgo === false) return config;
180
+ const compilerOptions = {
181
+ ...typescript?.configOverwrite?.compilerOptions ?? {},
182
+ baseUrl: null
183
+ };
184
+ if ([
185
+ 'node',
186
+ 'node10'
187
+ ].includes(String(compilerOptions.moduleResolution).toLowerCase())) compilerOptions.moduleResolution = null;
188
+ config.typescript = {
189
+ ...typescript,
190
+ configOverwrite: {
191
+ ...typescript?.configOverwrite ?? {},
192
+ compilerOptions
193
+ }
194
+ };
195
+ if (typescript?.configFile) config.typescript.configFile = createTsgoCheckerConfig(node_path.resolve(rootPath, typescript.configFile));
196
+ return config;
197
+ };
198
+ const withTsgoDefaults = (userOptions, rootPath)=>{
199
+ const tsgoPath = resolveTsgoPackagePath(rootPath);
200
+ const userChain = userOptions ? Array.isArray(userOptions) ? userOptions : [
201
+ userOptions
202
+ ] : [];
203
+ return [
204
+ {
205
+ typescript: tsgoPath ? {
206
+ tsgo: true,
207
+ typescriptPath: tsgoPath
208
+ } : {
209
+ tsgo: true
210
+ }
211
+ },
212
+ ...userChain,
213
+ (config)=>{
214
+ const { typescript } = config;
215
+ if (typescript?.tsgo === false && typescript.typescriptPath === tsgoPath) typescript.typescriptPath = tryResolve("typescript", rootPath);
216
+ return normalizeTsgoConfig(config, rootPath);
217
+ }
218
+ ];
219
+ };
220
+ export { refreshTsgoCheckerConfig, withTsgoDefaults };
@@ -2,6 +2,7 @@ import { type BuilderInstance, createRspackBuilder } from './createBuilder.js';
2
2
  import type { CreateBuilderOptions } from './types.js';
3
3
  export { type ChainIdentifier, type ConfigChain, logger, type NormalizedConfig, type RsbuildConfig, type RsbuildContext, type RsbuildPlugin, type RsbuildPlugins, type RsbuildTarget, type Rspack, type RspackChain, } from '@rsbuild/core';
4
4
  export { parseConfig as parseRspackConfig } from './createBuilder.js';
5
+ export { refreshTsgoCheckerConfig } from './shared/tsgo.js';
5
6
  export { castArray, isHtmlDisabled, RUNTIME_CHUNK_NAME, RUNTIME_CHUNK_REGEX, SERVICE_WORKER_ENVIRONMENT_NAME, } from './shared/utils.js';
6
7
  export type { BuilderConfig, BundlerType, CacheGroup, MetaOptions, MultiStats, RspackConfig, Stats, ToolsDevServerConfig, } from './types.js';
7
8
  export type { BuilderInstance, CreateBuilderOptions };
@@ -0,0 +1,27 @@
1
+ import type { PluginTypeCheckerOptions } from '@rsbuild/plugin-type-check';
2
+ type TsCheckerChain = NonNullable<PluginTypeCheckerOptions['tsCheckerOptions']>;
3
+ type TsCheckerFn = Extract<TsCheckerChain, (config: never) => unknown>;
4
+ export type TsCheckerOptions = Parameters<TsCheckerFn>[0];
5
+ /**
6
+ * Regenerate a checker config from the project config it `extends`.
7
+ *
8
+ * The generated file is written once, at builder configuration; everything it
9
+ * inherits through `extends` is read fresh by the compiler on every check, but
10
+ * the values it has to restate (`references`, the pinned `rootDir`, the
11
+ * `moduleResolution` override) would otherwise stay frozen for the life of a
12
+ * `modern dev` session. The checker calls this before each run so an edit to
13
+ * the project's tsconfig - adding, removing or retargeting a project reference -
14
+ * takes effect on the next compilation instead of the next restart.
15
+ *
16
+ * Returns the project config the checker config was derived from, so the caller
17
+ * can watch it; `undefined` when the file is not a generated checker config.
18
+ */
19
+ export declare const refreshTsgoCheckerConfig: (checkerConfigFile: string) => string | undefined;
20
+ /**
21
+ * Type checking runs on TypeScript Go (`tsgo`) by default. The checker
22
+ * prefers the project's stable TypeScript 7 package, then falls back to
23
+ * `@typescript/native-preview` for projects still on the preview lane.
24
+ * Set `tools.tsChecker.typescript.tsgo: false` to use the classic checker.
25
+ */
26
+ export declare const withTsgoDefaults: (userOptions: TsCheckerChain | undefined, rootPath: string) => TsCheckerChain;
27
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bleedingdev/modern-js-builder",
3
- "version": "3.9.0-ultramodern.8",
3
+ "version": "3.9.0-ultramodern.9",
4
4
  "description": "A builder for Modern.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "dependencies": {
29
29
  "@jridgewell/trace-mapping": "^0.3.31",
30
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.8",
30
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.9",
31
31
  "@rsbuild/core": "2.2.3",
32
32
  "@rsbuild/plugin-assets-retry": "2.0.2",
33
33
  "@rsbuild/plugin-check-syntax": "2.0.1",
@@ -61,7 +61,7 @@
61
61
  "ts-deepmerge": "8.0.0"
62
62
  },
63
63
  "devDependencies": {
64
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.8",
64
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.9",
65
65
  "@rsdoctor/rspack-plugin": "^1.6.3",
66
66
  "@rslib/core": "1.0.0",
67
67
  "@scripts/rstest-config": "2.66.0",