Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions packages/rspack-cli/src/utils/compileTypeScript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { rspack } from '@rspack/core';

type ModuleType = 'commonjs' | 'es6';

const injectInlineSourceMap = ({
code,
map,
}: {
code: string;
map: string | undefined;
}): string => {
if (map) {
const base64Map = Buffer.from(map, 'utf8').toString('base64');
const sourceMapContent = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64Map}`;
return `${code}\n${sourceMapContent}`;
}
return code;
};

export const compileTypeScript = (
sourcecode: string,
filename: string,
moduleType: ModuleType,
) => {
const { code, map } = rspack.experiments.swc.transformSync(sourcecode, {
jsc: {
parser: {
syntax: 'typescript',
tsx: false,
decorators: true,
dynamicImport: true,
},
},
filename,
module: { type: moduleType },
sourceMaps: true,
isModule: true,
});

return injectInlineSourceMap({ code, map });
};
195 changes: 156 additions & 39 deletions packages/rspack-cli/src/utils/loadConfig.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,84 @@
import fs from 'node:fs';
import { createRequire } from 'node:module';
import { createRequire, register as registerModule } from 'node:module';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import type { MultiRspackOptions, RspackOptions } from '@rspack/core';
import { rspack } from '@rspack/core';
import { addHook } from 'pirates';
import { compileTypeScript } from './compileTypeScript';
import { crossImport } from './crossImport';
import findConfig from './findConfig';
import { isEsmFile } from './isEsmFile';
import isTsFile, { TS_EXTENSION } from './isTsFile';
import isTsFile from './isTsFile';
import type { CommonOptions } from './options';

const require = createRequire(import.meta.url);
const CORE_MODULE_URL = pathToFileURL(require.resolve('@rspack/core')).href;

const injectInlineSourceMap = ({
code,
map,
}: {
code: string;
map: string | undefined;
}): string => {
const DEFAULT_CONFIG_NAME = 'rspack.config' as const;
let isCommonJsLoaderRegistered = false;
let isEsmLoaderRegistered = false;

const shouldCompileAsCommonJs = (filename: string) =>
isTsFile(filename) && !isEsmFile(filename);

const ESM_TS_LOADER_SOURCE = `
import fs from 'node:fs';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

let rspack;

export async function initialize(data) {
({ rspack } = await import(data.coreModuleUrl));
}

const TS_EXTENSION = ['.ts', '.cts', '.mts'];

const isTsFile = (filePath) => TS_EXTENSION.includes(path.extname(filePath));

const readPackageUp = (cwd) => {
let current = cwd;

while (true) {
const packageJsonPath = path.join(current, 'package.json');
if (fs.existsSync(packageJsonPath)) {
try {
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
} catch {
return undefined;
}
}

const parent = path.dirname(current);
if (parent === current) {
return undefined;
}
current = parent;
}
};

const isEsmFile = (filePath) => {
if (/\\.(mjs|mts)$/.test(filePath)) {
return true;
}
if (/\\.(cjs|cts)$/.test(filePath)) {
return false;
}
return readPackageUp(path.dirname(filePath))?.type === 'module';
};

const injectInlineSourceMap = ({ code, map }) => {
if (map) {
const base64Map = Buffer.from(map, 'utf8').toString('base64');
const sourceMapContent = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64Map}`;
return `${code}\n${sourceMapContent}`;
const sourceMapContent = \`//# sourceMappingURL=data:application/json;charset=utf-8;base64,\${base64Map}\`;
return \`\${code}\\n\${sourceMapContent}\`;
}
return code;
};

export function compile(sourcecode: string, filename: string) {
const compileTypeScript = (sourcecode, filename, moduleType) => {
const { code, map } = rspack.experiments.swc.transformSync(sourcecode, {
jsc: {
parser: {
Expand All @@ -37,42 +88,100 @@ export function compile(sourcecode: string, filename: string) {
dynamicImport: true,
},
},
filename: filename,
module: { type: 'commonjs' },
filename,
module: { type: moduleType },
sourceMaps: true,
isModule: true,
});

return injectInlineSourceMap({ code, map });
}
};

const DEFAULT_CONFIG_NAME = 'rspack.config' as const;
export async function load(url, context, nextLoad) {
if (!url.startsWith('file:')) {
return nextLoad(url, context);
}

// modified based on https://github.com/swc-project/swc-node/blob/master/packages/register/register.ts#L117
const registerLoader = (configPath: string) => {
// For ESM and `.mts` you need to use: 'NODE_OPTIONS="--loader ts-node/esm" rspack build --config ./rspack.config.mts'
if (isEsmFile(configPath) && isTsFile(configPath)) {
return;
const filename = fileURLToPath(url);
if (!isTsFile(filename)) {
return nextLoad(url, context);
}

const moduleType = isEsmFile(filename) ? 'es6' : 'commonjs';
const format = moduleType === 'es6' ? 'module' : 'commonjs';
const source = await readFile(new URL(url), 'utf8');

try {
return {
format,
shortCircuit: true,
source: compileTypeScript(source, filename, moduleType),
};
} catch (err) {
throw new Error(
\`Failed to transform file "\${filename}" when loading TypeScript config file:\\n \${err instanceof Error ? err.message : String(err)}\`,
);
}
}
`;

const ESM_TS_LOADER_URL = `data:text/javascript;base64,${Buffer.from(
ESM_TS_LOADER_SOURCE,
'utf8',
).toString('base64')}`;

// Only support TypeScript files with a CommonJS loader here
if (!isTsFile(configPath)) {
throw new Error(`config file "${configPath}" is not supported.`);
const registerCommonJsLoader = () => {
if (isCommonJsLoaderRegistered) {
return;
}

addHook(
(code, filename) => {
try {
return compile(code, filename);
return compileTypeScript(code, filename, 'commonjs');
} catch (err) {
throw new Error(
`Failed to transform file "${filename}" when loading TypeScript config file:\n ${err instanceof Error ? err.message : String(err)}`,
);
}
},
{
exts: TS_EXTENSION,
exts: ['.ts', '.cts', '.mts'],
matcher: shouldCompileAsCommonJs,
},
);
isCommonJsLoaderRegistered = true;
};

const registerEsmLoader = () => {
if (isEsmLoaderRegistered) {
return;
}

registerModule(ESM_TS_LOADER_URL, {
parentURL: import.meta.url,
data: {
coreModuleUrl: CORE_MODULE_URL,
},
});
isEsmLoaderRegistered = true;
};

const loadConfigFile = async <T = LoadedRspackConfig>(
configPath: string,
options: CommonOptions,
): Promise<T> => {
if (isTsFile(configPath) && options.configLoader === 'register') {
if (isEsmFile(configPath)) {
registerEsmLoader();
const loaded = await import(pathToFileURL(configPath).href);
return loaded.default as T;
}

registerCommonJsLoader();
}

return crossImport<T>(configPath);
};

export type LoadedRspackConfig =
Expand All @@ -84,6 +193,8 @@ export type LoadedRspackConfig =
argv?: Record<string, any>,
) => RspackOptions | MultiRspackOptions);

type ResolvedRspackConfig = RspackOptions | MultiRspackOptions;

const checkIsMultiRspackOptions = (
config: RspackOptions | MultiRspackOptions,
): config is MultiRspackOptions => Array.isArray(config);
Expand Down Expand Up @@ -212,25 +323,35 @@ export async function loadExtendedConfig(
);
}

// Register loader for TypeScript files
if (isTsFile(resolvedPath) && options.configLoader === 'register') {
registerLoader(resolvedPath);
}

// Load the extended configuration
let loadedConfig = await crossImport(resolvedPath);
let loadedConfig = await loadConfigFile<LoadedRspackConfig>(
resolvedPath,
options,
);

// If the extended config is a function, execute it
if (typeof loadedConfig === 'function') {
loadedConfig = loadedConfig(options.env, options);
loadedConfig = loadedConfig(options.env as Record<string, any>, options);
// if return promise we should await its result
if (
typeof (loadedConfig as unknown as Promise<unknown>).then === 'function'
) {
loadedConfig = await loadedConfig;
loadedConfig = (await loadedConfig) as ResolvedRspackConfig;
}
}

if (!loadedConfig) {
throw new Error(
`Extended configuration file "${resolvedPath}" must export a configuration object.`,
);
}

if (checkIsMultiRspackOptions(loadedConfig)) {
throw new Error(
`Extended configuration file "${resolvedPath}" must export a single configuration object.`,
);
}

// Recursively load extended configurations from the extended config
const { config: extendedConfig, pathMap: extendedPathMap } =
await loadExtendedConfig(loadedConfig, resolvedPath, cwd, options);
Expand Down Expand Up @@ -269,11 +390,7 @@ export async function loadRspackConfig(
configPath = defaultConfig;
}

// load config
if (isTsFile(configPath) && options.configLoader === 'register') {
registerLoader(configPath);
}
const loadedConfig = await crossImport(configPath);
const loadedConfig = await loadConfigFile(configPath, options);

return { loadedConfig, configPath };
}
54 changes: 54 additions & 0 deletions packages/rspack-cli/tests/build/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
}),
).resolves.toMatch(/Main cjs file/);
});

});
describe('should load cjs config', () => {
const cwd = resolve(__dirname, './cjs');
Expand Down Expand Up @@ -157,7 +158,7 @@
nodeOptions: ['--experimental-loader=ts-node/esm'],
},
);
expect(stdout).toBeTruthy();

Check failure on line 161 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load esm config > should load config.ts file

expected '' to be truthy - Expected%3A true + Received%3A ""
expect(exitCode).toBe(0);
await expect(
readFile(resolve(cwd, './dist/ts-2/ts.bundle.js'), {
Expand All @@ -166,6 +167,25 @@
).resolves.toMatch(/Main esm file/);
});

it('should load config.ts file with register loader', async () => {
const { exitCode, stderr, stdout } = await run(cwd, [
'-c',
'rspack.config.ts',
'--config-loader',
'register',
'--output-path',
'dist/ts-register',
]);
expect(stderr).toBeFalsy();

Check failure on line 179 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load esm config > should load config.ts file with register loader

expected 'Panic occurred at runtime. Please file an issue on GitHub with the panic info and backtrace below%3A https%3A//github.com/web-infra-dev/rspack/issues\n\nthread \'<unnamed>\' (2) panicked at index.crates.io-1949cf8c6b5b557f/napi-3.8.4/src/error.rs%3A538%3A1%3A\nassertion `left == right` failed%3A Check exception status failed\n left%3A 1\n right%3A 0\nstack backtrace%3A\n[rspack] CLI failed%3A\nError%3A Failed to transform file "/home/runner/work/rspack/rspack/packages/rspack-cli/tests/build/config/esm/rspack.config.ts" when loading TypeScript config file%3A\n unreachable\n at load (data%3Atext/javascript;base64%2CCmltcG9ydCBmcyBmcm9tICdub2RlOmZzJzsKaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJzsKaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJzsKaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ25vZGU6dXJsJzsKCmxldCByc3BhY2s7CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdGlhbGl6ZShkYXRhKSB7CiAgKHsgcnNwYWNrIH0gPSBhd2FpdCBpbXBvcnQoZGF0YS5jb3JlTW9kdWxlVXJsKSk7Cn0KCmNvbnN0IFRTX0VYVEVOU0lPTiA9IFsnLnRzJywgJy5jdHMnLCAnLm10cyddOwoKY29uc3QgaXNUc0ZpbGUgPSAoZmlsZVBhdGgpID0+IFRTX0VYVEVOU0lPTi5pbmNsdWRlcyhwYXRoLmV4dG5hbWUoZmlsZVBhdGgpKTsKCmNvbnN0IHJlYWRQYWNrYWdlVXAgPSAoY3dkKSA9PiB7CiAgbGV0IGN1cnJlbnQgPSBjd2Q7CgogIHdoaWxlICh0cnVlKSB7CiAgICBjb25zdCBwYWNrYWdlSnNvblBhdGggPSBwYXRoLmpvaW4oY3VycmVudCwgJ3BhY2thZ2UuanNvbicpOwogICAgaWYgKGZzLmV4aXN0c1N5bmMocGFja2FnZUpzb25QYXRoKSkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhwYWNrYWdlSnNvblBhdGgsICd1dGY4JykpOwogICAgICB9IGNhdGNoIHsKICAgICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgICB9CiAgICB9CgogICAgY29uc3QgcGFyZW50ID0gcGF0aC5kaXJuYW1lKGN1cnJlbnQpOwogICAgaWYgKHBhcmVudCA9PT0gY3VycmVudCkgewogICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgfQogICAgY3VycmVudCA9IHBhcmVudDsKICB9Cn07Cgpjb25zdCBpc0VzbUZpbGUgPSAoZmlsZVBhdGgpID0+IHsKICBpZiAoL1wuKG1qc3xtdHMpJC8udGVzdChmaWxlUGF0aCkpIHsKICAgIHJldHVybiB0cnVlOwogIH0KICBpZiAoL1wuKGNqc3xjdHMpJC8udGVzdChmaWxlUGF0aCkpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIHJlYWRQYWNrYWdlVXAocGF0aC5kaXJuYW1lKGZpbGVQYXRoKSk/LnR5cGUgPT09ICdtb2R1bGUnOwp9OwoKY29uc3QgaW5qZWN0SW5saW5lU291cmNlTWFwID0gKHsgY29kZSwgbWFwIH0pID0+IHsKICBpZiAobWFwKSB7CiAgICBjb25zdCBiYXNlNjRNYXAgPSBCdWZmZXIuZnJvbShtYXAsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpOwogICAgY29uc3Qgc291cmNlTWFwQ29udGVudCA9IGAvLyMgc291cmNlTWFwcGluZ1VSTD1kYXRhOmFwcGxpY2F0aW9uL2pzb247Y2hhcnNldD11dGYtODtiYXNlNjQsJHtiYXNlNjRNYXB9YDsKICAgIHJldHVybiBgJHtjb2RlfVxuJHtzb3VyY2VNYXBDb250ZW50fWA7CiAgfQogIHJldHVybiBjb2RlOwp9OwoKY29uc3QgY29tcGlsZVR5cGVTY3JpcHQgPSAoc291cmNlY29kZSwgZmlsZW5hbWUsIG1vZHVsZVR5cGUpID0+IHsKICBjb25zdCB7IGNvZGUsIG1hcCB9ID0gcnNwYWNrLmV4cGVyaW1lbnRzLnN3Yy50cmFuc2Zvcm1TeW5jKHNvdXJjZWNvZGUsIHsKICAgIGpzYzogewogICAgICBwYXJzZXI6IHsKICAgICAgICBzeW50YXg6ICd0eXBlc2NyaXB0JywKICAgICAgICB0c3g6IGZhbHNlLAogICAgICAgIGRlY29yYXRvcnM6IHRydWUsCiAgICAgICAgZHluYW1pY0ltcG9ydDogdHJ1ZSwKICAgICAgfSwKICAgIH0sCiAgICBmaWxlbmFtZSwKICAgIG1vZHVsZTogeyB0eXBlOiBtb2R1bGVUeXBlIH0sCiAgICBzb3VyY2VNYXBzOiB0cnVlLAogICAgaXNNb2R1bGU6IHRydWUsCiAgfSk7CgogIHJldHVybiBpbmplY3RJbmxpbmVTb3VyY2VNYXAoeyBjb2RlLCBtYXAgfSk7Cn07CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9hZCh1cmwsIGNvbnRleHQsIG5leHRMb2FkKSB7CiAgaWYgKCF1cmwuc3RhcnRzV2l0aCgnZmlsZTonKSkgewogICAgcmV0dXJuIG5leHRMb2FkKHVybCwgY29udGV4dCk7CiAgfQoKICBjb25zdCBmaWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgodXJsKTsKICBpZiAoIWlzVHNGaWxlKGZpbGVuYW1lKSkgewogICAgcmV0dXJuIG5leHRMb2FkKHVybCwgY29udGV4dCk7CiAgfQoKICBjb25zdCBtb2R1bGVUeXBlID0gaXNFc21GaWxlKGZpbGVuYW1lKSA/ICdlczYnIDogJ2NvbW1vbmpzJzsKICBjb25zdCBmb3JtYXQgPSBtb2R1bGVUeXBlID09PSAnZXM2JyA/ICdtb2R1bGUnIDogJ2NvbW1vbmpzJzsKICBjb25zdCBzb3VyY2UgPSBhd2FpdCByZWFkRmlsZShuZXcgVVJMKHVybCksICd1dGY4Jyk7CgogIHRyeSB7CiAgICByZXR1cm4gewogICAgICBmb3JtYXQsCiAgICAgIHNob3J0Q2lyY3VpdDogdHJ1ZSwKICAgICAgc291cmNlOiBjb21waWxlVHlwZVNjcmlwdChzb3VyY2UsIGZpbGVuYW1lLCBtb2R1bGVUeXBlKSwKICAgIH07CiAgfSBjYXRjaCAoZXJyKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgIGBGYWlsZWQgdG8gdHJhbnNmb3JtIGZpbGUgIiR7ZmlsZW5hbWV9IiB3aGVuIGxvYWRpbmcgVHlwZVNjcmlwdCBjb25maWcgZmlsZTpcbiAke2VyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKX1gLAogICAgKTsKICB9Cn0K%3A97%3A11)\n\u001b[90m at async nextLoad (node%3Ainternal/modules/esm/hooks%3
expect(stdout).toBeTruthy();
expect(exitCode).toBe(0);
await expect(
readFile(resolve(cwd, './dist/ts-register/ts.bundle.js'), {
encoding: 'utf-8',
}),
).resolves.toMatch(/Main esm file/);
});

it('should load config.mjs file', async () => {
const { exitCode, stderr, stdout } = await run(cwd, [
'-c',
Expand All @@ -192,7 +212,7 @@
},
);

expect(stdout).toBeTruthy();

Check failure on line 215 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load esm config > should load config.mts file

expected '' to be truthy - Expected%3A true + Received%3A ""
expect(exitCode).toBe(0);
await expect(
readFile(resolve(cwd, './dist/mts-1/mts.bundle.js'), {
Expand All @@ -200,6 +220,40 @@
}),
).resolves.toMatch(/Main esm file/);
});

it('should load config.mts file with register loader', async () => {
const { exitCode, stderr, stdout } = await run(cwd, [
'-c',
'rspack.config.mts',
'--config-loader',
'register',
'--output-path',
'dist/mts-register',
]);

expect(stderr).toBeFalsy();

Check failure on line 234 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load esm config > should load config.mts file with register loader

expected 'Panic occurred at runtime. Please file an issue on GitHub with the panic info and backtrace below%3A https%3A//github.com/web-infra-dev/rspack/issues\n\nthread \'<unnamed>\' (2) panicked at index.crates.io-1949cf8c6b5b557f/napi-3.8.4/src/error.rs%3A538%3A1%3A\nassertion `left == right` failed%3A Check exception status failed\n left%3A 1\n right%3A 0\nstack backtrace%3A\n[rspack] CLI failed%3A\nError%3A Failed to transform file "/home/runner/work/rspack/rspack/packages/rspack-cli/tests/build/config/esm/rspack.config.mts" when loading TypeScript config file%3A\n unreachable\n at load (data%3Atext/javascript;base64%2CCmltcG9ydCBmcyBmcm9tICdub2RlOmZzJzsKaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJzsKaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJzsKaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ25vZGU6dXJsJzsKCmxldCByc3BhY2s7CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdGlhbGl6ZShkYXRhKSB7CiAgKHsgcnNwYWNrIH0gPSBhd2FpdCBpbXBvcnQoZGF0YS5jb3JlTW9kdWxlVXJsKSk7Cn0KCmNvbnN0IFRTX0VYVEVOU0lPTiA9IFsnLnRzJywgJy5jdHMnLCAnLm10cyddOwoKY29uc3QgaXNUc0ZpbGUgPSAoZmlsZVBhdGgpID0+IFRTX0VYVEVOU0lPTi5pbmNsdWRlcyhwYXRoLmV4dG5hbWUoZmlsZVBhdGgpKTsKCmNvbnN0IHJlYWRQYWNrYWdlVXAgPSAoY3dkKSA9PiB7CiAgbGV0IGN1cnJlbnQgPSBjd2Q7CgogIHdoaWxlICh0cnVlKSB7CiAgICBjb25zdCBwYWNrYWdlSnNvblBhdGggPSBwYXRoLmpvaW4oY3VycmVudCwgJ3BhY2thZ2UuanNvbicpOwogICAgaWYgKGZzLmV4aXN0c1N5bmMocGFja2FnZUpzb25QYXRoKSkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhwYWNrYWdlSnNvblBhdGgsICd1dGY4JykpOwogICAgICB9IGNhdGNoIHsKICAgICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgICB9CiAgICB9CgogICAgY29uc3QgcGFyZW50ID0gcGF0aC5kaXJuYW1lKGN1cnJlbnQpOwogICAgaWYgKHBhcmVudCA9PT0gY3VycmVudCkgewogICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgfQogICAgY3VycmVudCA9IHBhcmVudDsKICB9Cn07Cgpjb25zdCBpc0VzbUZpbGUgPSAoZmlsZVBhdGgpID0+IHsKICBpZiAoL1wuKG1qc3xtdHMpJC8udGVzdChmaWxlUGF0aCkpIHsKICAgIHJldHVybiB0cnVlOwogIH0KICBpZiAoL1wuKGNqc3xjdHMpJC8udGVzdChmaWxlUGF0aCkpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIHJlYWRQYWNrYWdlVXAocGF0aC5kaXJuYW1lKGZpbGVQYXRoKSk/LnR5cGUgPT09ICdtb2R1bGUnOwp9OwoKY29uc3QgaW5qZWN0SW5saW5lU291cmNlTWFwID0gKHsgY29kZSwgbWFwIH0pID0+IHsKICBpZiAobWFwKSB7CiAgICBjb25zdCBiYXNlNjRNYXAgPSBCdWZmZXIuZnJvbShtYXAsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpOwogICAgY29uc3Qgc291cmNlTWFwQ29udGVudCA9IGAvLyMgc291cmNlTWFwcGluZ1VSTD1kYXRhOmFwcGxpY2F0aW9uL2pzb247Y2hhcnNldD11dGYtODtiYXNlNjQsJHtiYXNlNjRNYXB9YDsKICAgIHJldHVybiBgJHtjb2RlfVxuJHtzb3VyY2VNYXBDb250ZW50fWA7CiAgfQogIHJldHVybiBjb2RlOwp9OwoKY29uc3QgY29tcGlsZVR5cGVTY3JpcHQgPSAoc291cmNlY29kZSwgZmlsZW5hbWUsIG1vZHVsZVR5cGUpID0+IHsKICBjb25zdCB7IGNvZGUsIG1hcCB9ID0gcnNwYWNrLmV4cGVyaW1lbnRzLnN3Yy50cmFuc2Zvcm1TeW5jKHNvdXJjZWNvZGUsIHsKICAgIGpzYzogewogICAgICBwYXJzZXI6IHsKICAgICAgICBzeW50YXg6ICd0eXBlc2NyaXB0JywKICAgICAgICB0c3g6IGZhbHNlLAogICAgICAgIGRlY29yYXRvcnM6IHRydWUsCiAgICAgICAgZHluYW1pY0ltcG9ydDogdHJ1ZSwKICAgICAgfSwKICAgIH0sCiAgICBmaWxlbmFtZSwKICAgIG1vZHVsZTogeyB0eXBlOiBtb2R1bGVUeXBlIH0sCiAgICBzb3VyY2VNYXBzOiB0cnVlLAogICAgaXNNb2R1bGU6IHRydWUsCiAgfSk7CgogIHJldHVybiBpbmplY3RJbmxpbmVTb3VyY2VNYXAoeyBjb2RlLCBtYXAgfSk7Cn07CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9hZCh1cmwsIGNvbnRleHQsIG5leHRMb2FkKSB7CiAgaWYgKCF1cmwuc3RhcnRzV2l0aCgnZmlsZTonKSkgewogICAgcmV0dXJuIG5leHRMb2FkKHVybCwgY29udGV4dCk7CiAgfQoKICBjb25zdCBmaWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgodXJsKTsKICBpZiAoIWlzVHNGaWxlKGZpbGVuYW1lKSkgewogICAgcmV0dXJuIG5leHRMb2FkKHVybCwgY29udGV4dCk7CiAgfQoKICBjb25zdCBtb2R1bGVUeXBlID0gaXNFc21GaWxlKGZpbGVuYW1lKSA/ICdlczYnIDogJ2NvbW1vbmpzJzsKICBjb25zdCBmb3JtYXQgPSBtb2R1bGVUeXBlID09PSAnZXM2JyA/ICdtb2R1bGUnIDogJ2NvbW1vbmpzJzsKICBjb25zdCBzb3VyY2UgPSBhd2FpdCByZWFkRmlsZShuZXcgVVJMKHVybCksICd1dGY4Jyk7CgogIHRyeSB7CiAgICByZXR1cm4gewogICAgICBmb3JtYXQsCiAgICAgIHNob3J0Q2lyY3VpdDogdHJ1ZSwKICAgICAgc291cmNlOiBjb21waWxlVHlwZVNjcmlwdChzb3VyY2UsIGZpbGVuYW1lLCBtb2R1bGVUeXBlKSwKICAgIH07CiAgfSBjYXRjaCAoZXJyKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgIGBGYWlsZWQgdG8gdHJhbnNmb3JtIGZpbGUgIiR7ZmlsZW5hbWV9IiB3aGVuIGxvYWRpbmcgVHlwZVNjcmlwdCBjb25maWcgZmlsZTpcbiAke2VyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKX1gLAogICAgKTsKICB9Cn0K%3A97%3A11)\n\u001b[90m at async nextLoad (node%3Ainternal/modules/esm/hooks%
expect(stdout).toBeTruthy();
expect(exitCode).toBe(0);
await expect(
readFile(resolve(cwd, './dist/mts-register/mts.bundle.js'), {
encoding: 'utf-8',
}),
).resolves.toMatch(/Main esm file/);
});

it('should reject faux esm config.ts with register loader', async () => {
const { exitCode, stderr, stdout } = await run(cwd, [
'-c',
'rspack.config.faux.ts',
'--config-loader',
'register',
]);

expect(stdout).toBeFalsy();
expect(stderr).toBeTruthy();
expect(stderr).toMatch(/__dirname is not defined in ES module scope/);

Check failure on line 254 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load esm config > should reject faux esm config.ts with register loader

expected 'Panic occurred at runtime. Please file an issue on GitHub with the panic info and backtrace below%3A https%3A//github.com/web-infra-dev/rspack/issues\n\nthread \'<unnamed>\' (2) panicked at index.crates.io-1949cf8c6b5b557f/napi-3.8.4/src/error.rs%3A538%3A1%3A\nassertion `left == right` failed%3A Check exception status failed\n left%3A 1\n right%3A 0\nstack backtrace%3A\n[rspack] CLI failed%3A\nError%3A Failed to transform file "/home/runner/work/rspack/rspack/packages/rspack-cli/tests/build/config/esm/rspack.config.faux.ts" when loading TypeScript config file%3A\n unreachable\n at load (data%3Atext/javascript;base64%2CCmltcG9ydCBmcyBmcm9tICdub2RlOmZzJzsKaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJzsKaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJzsKaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ25vZGU6dXJsJzsKCmxldCByc3BhY2s7CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdGlhbGl6ZShkYXRhKSB7CiAgKHsgcnNwYWNrIH0gPSBhd2FpdCBpbXBvcnQoZGF0YS5jb3JlTW9kdWxlVXJsKSk7Cn0KCmNvbnN0IFRTX0VYVEVOU0lPTiA9IFsnLnRzJywgJy5jdHMnLCAnLm10cyddOwoKY29uc3QgaXNUc0ZpbGUgPSAoZmlsZVBhdGgpID0+IFRTX0VYVEVOU0lPTi5pbmNsdWRlcyhwYXRoLmV4dG5hbWUoZmlsZVBhdGgpKTsKCmNvbnN0IHJlYWRQYWNrYWdlVXAgPSAoY3dkKSA9PiB7CiAgbGV0IGN1cnJlbnQgPSBjd2Q7CgogIHdoaWxlICh0cnVlKSB7CiAgICBjb25zdCBwYWNrYWdlSnNvblBhdGggPSBwYXRoLmpvaW4oY3VycmVudCwgJ3BhY2thZ2UuanNvbicpOwogICAgaWYgKGZzLmV4aXN0c1N5bmMocGFja2FnZUpzb25QYXRoKSkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhwYWNrYWdlSnNvblBhdGgsICd1dGY4JykpOwogICAgICB9IGNhdGNoIHsKICAgICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgICB9CiAgICB9CgogICAgY29uc3QgcGFyZW50ID0gcGF0aC5kaXJuYW1lKGN1cnJlbnQpOwogICAgaWYgKHBhcmVudCA9PT0gY3VycmVudCkgewogICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgfQogICAgY3VycmVudCA9IHBhcmVudDsKICB9Cn07Cgpjb25zdCBpc0VzbUZpbGUgPSAoZmlsZVBhdGgpID0+IHsKICBpZiAoL1wuKG1qc3xtdHMpJC8udGVzdChmaWxlUGF0aCkpIHsKICAgIHJldHVybiB0cnVlOwogIH0KICBpZiAoL1wuKGNqc3xjdHMpJC8udGVzdChmaWxlUGF0aCkpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIHJlYWRQYWNrYWdlVXAocGF0aC5kaXJuYW1lKGZpbGVQYXRoKSk/LnR5cGUgPT09ICdtb2R1bGUnOwp9OwoKY29uc3QgaW5qZWN0SW5saW5lU291cmNlTWFwID0gKHsgY29kZSwgbWFwIH0pID0+IHsKICBpZiAobWFwKSB7CiAgICBjb25zdCBiYXNlNjRNYXAgPSBCdWZmZXIuZnJvbShtYXAsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpOwogICAgY29uc3Qgc291cmNlTWFwQ29udGVudCA9IGAvLyMgc291cmNlTWFwcGluZ1VSTD1kYXRhOmFwcGxpY2F0aW9uL2pzb247Y2hhcnNldD11dGYtODtiYXNlNjQsJHtiYXNlNjRNYXB9YDsKICAgIHJldHVybiBgJHtjb2RlfVxuJHtzb3VyY2VNYXBDb250ZW50fWA7CiAgfQogIHJldHVybiBjb2RlOwp9OwoKY29uc3QgY29tcGlsZVR5cGVTY3JpcHQgPSAoc291cmNlY29kZSwgZmlsZW5hbWUsIG1vZHVsZVR5cGUpID0+IHsKICBjb25zdCB7IGNvZGUsIG1hcCB9ID0gcnNwYWNrLmV4cGVyaW1lbnRzLnN3Yy50cmFuc2Zvcm1TeW5jKHNvdXJjZWNvZGUsIHsKICAgIGpzYzogewogICAgICBwYXJzZXI6IHsKICAgICAgICBzeW50YXg6ICd0eXBlc2NyaXB0JywKICAgICAgICB0c3g6IGZhbHNlLAogICAgICAgIGRlY29yYXRvcnM6IHRydWUsCiAgICAgICAgZHluYW1pY0ltcG9ydDogdHJ1ZSwKICAgICAgfSwKICAgIH0sCiAgICBmaWxlbmFtZSwKICAgIG1vZHVsZTogeyB0eXBlOiBtb2R1bGVUeXBlIH0sCiAgICBzb3VyY2VNYXBzOiB0cnVlLAogICAgaXNNb2R1bGU6IHRydWUsCiAgfSk7CgogIHJldHVybiBpbmplY3RJbmxpbmVTb3VyY2VNYXAoeyBjb2RlLCBtYXAgfSk7Cn07CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9hZCh1cmwsIGNvbnRleHQsIG5leHRMb2FkKSB7CiAgaWYgKCF1cmwuc3RhcnRzV2l0aCgnZmlsZTonKSkgewogICAgcmV0dXJuIG5leHRMb2FkKHVybCwgY29udGV4dCk7CiAgfQoKICBjb25zdCBmaWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgodXJsKTsKICBpZiAoIWlzVHNGaWxlKGZpbGVuYW1lKSkgewogICAgcmV0dXJuIG5leHRMb2FkKHVybCwgY29udGV4dCk7CiAgfQoKICBjb25zdCBtb2R1bGVUeXBlID0gaXNFc21GaWxlKGZpbGVuYW1lKSA/ICdlczYnIDogJ2NvbW1vbmpzJzsKICBjb25zdCBmb3JtYXQgPSBtb2R1bGVUeXBlID09PSAnZXM2JyA/ICdtb2R1bGUnIDogJ2NvbW1vbmpzJzsKICBjb25zdCBzb3VyY2UgPSBhd2FpdCByZWFkRmlsZShuZXcgVVJMKHVybCksICd1dGY4Jyk7CgogIHRyeSB7CiAgICByZXR1cm4gewogICAgICBmb3JtYXQsCiAgICAgIHNob3J0Q2lyY3VpdDogdHJ1ZSwKICAgICAgc291cmNlOiBjb21waWxlVHlwZVNjcmlwdChzb3VyY2UsIGZpbGVuYW1lLCBtb2R1bGVUeXBlKSwKICAgIH07CiAgfSBjYXRjaCAoZXJyKSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgIGBGYWlsZWQgdG8gdHJhbnNmb3JtIGZpbGUgIiR7ZmlsZW5hbWV9IiB3aGVuIGxvYWRpbmcgVHlwZVNjcmlwdCBjb25maWcgZmlsZTpcbiAke2VyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKX1gLAogICAgKTsKICB9Cn0K%3A97%3A11)\n\u001b[90m at async nextLoad (node%3Ainternal/modules/esm/ho
expect(exitCode).toBe(1);
});
});

describe('should load config with defineConfig helper', () => {
Expand All @@ -213,7 +267,7 @@
nodeOptions: ['--experimental-loader=ts-node/esm'],
},
);
expect(stdout).toBeTruthy();

Check failure on line 270 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load config with defineConfig helper > should load config.ts file

expected '' to be truthy - Expected%3A true + Received%3A ""
expect(exitCode).toBe(0);
await expect(
readFile(resolve(cwd, './dist/ts-3/ts.bundle.js'), {
Expand All @@ -231,7 +285,7 @@
},
);

expect(stdout).toBeTruthy();

Check failure on line 288 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load config with defineConfig helper > should load config.mts file

expected '' to be truthy - Expected%3A true + Received%3A ""
expect(exitCode).toBe(0);
await expect(
readFile(resolve(cwd, './dist/mts-2/mts.bundle.js'), {
Expand All @@ -247,7 +301,7 @@
const { exitCode, stdout } = await run(cwd, ['-c', 'rspack.config.ts'], {
nodeOptions: ['--experimental-loader=ts-node/esm'],
});
expect(stdout).toBeTruthy();

Check failure on line 304 in packages/rspack-cli/tests/build/config/config.test.ts

View workflow job for this annotation

GitHub Actions / Test WASM / Test Node 24

tests/build/config/config.test.ts > rspack cli > should load monorepo config > should load monorepo config.ts file

expected '' to be truthy - Expected%3A true + Received%3A ""
expect(exitCode).toBe(0);
await expect(
readFile(
Expand Down
Loading
Loading