diff --git a/e2e/cases/externals/node/rslib.config.ts b/e2e/cases/externals/node/rslib.config.ts index eb27eb423..1adc696cf 100644 --- a/e2e/cases/externals/node/rslib.config.ts +++ b/e2e/cases/externals/node/rslib.config.ts @@ -4,8 +4,8 @@ import { generateBundleCjsConfig, generateBundleEsmConfig } from '#shared'; export default defineConfig({ lib: [ - generateBundleEsmConfig(__dirname, { platform: 'node' }), - generateBundleCjsConfig(__dirname, { platform: 'node' }), + generateBundleEsmConfig(__dirname, { output: { target: 'node' } }), + generateBundleCjsConfig(__dirname, { output: { target: 'node' } }), ], source: { entry: { diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 1cf200d24..2b3e1d2f1 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -10,11 +10,11 @@ import { DEFAULT_CONFIG_NAME, DEFAULT_EXTENSIONS } from './constant'; import type { Format, LibConfig, - Platform, RslibConfig, RslibConfigAsyncFn, RslibConfigExport, RslibConfigSyncFn, + Syntax, } from './types/config'; import { getDefaultExtension } from './utils/extension'; import { color } from './utils/helper'; @@ -155,27 +155,6 @@ const getDefaultFormatConfig = (format: Format): RsbuildConfig => { } }; -const getDefaultPlatformConfig = (platform: Platform): RsbuildConfig => { - switch (platform) { - case 'browser': - return {}; - case 'node': - return { - output: { - // When output.target is 'node', Node.js's built-in will be treated as externals of type `node-commonjs`. - // Simply override the built-in modules to make them external. - // https://github.com/webpack/webpack/blob/dd44b206a9c50f4b4cb4d134e1a0bd0387b159a3/lib/node/NodeTargetPlugin.js#L81 - externals: nodeBuiltInModules, - target: 'node', - }, - }; - case 'neutral': - return {}; - default: - throw new Error(`Unsupported platform: ${platform}`); - } -}; - const getDefaultAutoExtensionConfig = ( format: Format, root: string, @@ -196,33 +175,77 @@ const getDefaultAutoExtensionConfig = ( }; }; -export function convertLibConfigToRsbuildConfig( +export function convertLibConfigToRsbuildConfig_legacy( libConfig: LibConfig, rsbuildConfig: RsbuildConfig, ): RsbuildConfig { - const { format, platform = 'browser', autoExtension = false } = libConfig; + const { format, autoExtension = false } = libConfig; const formatConfig = getDefaultFormatConfig(format!); - const platformConfig = getDefaultPlatformConfig(platform); const autoExtensionConfig = getDefaultAutoExtensionConfig( format!, dirname(rsbuildConfig._privateMeta?.configFilePath ?? process.cwd()), autoExtension, ); - return mergeRsbuildConfig( - rsbuildConfig, - formatConfig, - platformConfig, - autoExtensionConfig, + return mergeRsbuildConfig(rsbuildConfig, formatConfig, autoExtensionConfig); +} + +const getDefaultSyntax = (_syntax?: Syntax): RsbuildConfig => { + return {}; +}; + +export function convertLibConfigToRsbuildConfig( + libConfig: LibConfig, + configPath: string, +): RsbuildConfig { + const { format, autoExtension = false } = libConfig; + + const formatConfig = getDefaultFormatConfig(format!); + const autoExtensionConfig = getDefaultAutoExtensionConfig( + format!, + dirname(configPath), + autoExtension, + ); + const syntaxConfig = getDefaultSyntax(libConfig.output?.syntax); + + return mergeRsbuildConfig(formatConfig, autoExtensionConfig, syntaxConfig); +} + +function postUpdateRsbuildConfig(rsbuildConfig: RsbuildConfig) { + const defaultTargetConfig = getDefaultTargetConfig( + rsbuildConfig.output?.target ?? 'web', ); + + return mergeRsbuildConfig(defaultTargetConfig); } +const getDefaultTargetConfig = (target: string): RsbuildConfig => { + switch (target) { + case 'web': + return {}; + case 'node': + return { + output: { + // When output.target is 'node', Node.js's built-in will be treated as externals of type `node-commonjs`. + // Simply override the built-in modules to make them external. + // https://github.com/webpack/webpack/blob/dd44b206a9c50f4b4cb4d134e1a0bd0387b159a3/lib/node/NodeTargetPlugin.js#L81 + externals: nodeBuiltInModules, + target: 'node', + }, + }; + case 'neutral': + return {}; + default: + throw new Error(`Unsupported platform: ${target}`); + } +}; + export async function composeCreateRsbuildConfig( rslibConfig: RslibConfig, ): Promise>> { const internalRsbuildConfig = await createInternalRsbuildConfig(); - + const configPath = rslibConfig._privateMeta?.configFilePath ?? process.cwd(); const { lib: libConfigsArray, ...sharedRsbuildConfig } = rslibConfig; if (!libConfigsArray) { @@ -234,19 +257,29 @@ export async function composeCreateRsbuildConfig( const composedRsbuildConfig: Partial> = {}; for (const libConfig of libConfigsArray) { - const { format, platform, ...overrideRsbuildConfig } = libConfig; + const { format, ...overrideRsbuildConfig } = libConfig; + + const libConvertedRsbuildConfig = convertLibConfigToRsbuildConfig( + libConfig, + configPath, + ); - // Merge order matters, keep `internalRsbuildConfig` at the last position - // to ensure that the internal config is not overridden by the user's config. const mergedRsbuildConfig = mergeRsbuildConfig( sharedRsbuildConfig, overrideRsbuildConfig, - internalRsbuildConfig, + libConvertedRsbuildConfig, ); - composedRsbuildConfig[format!] = convertLibConfigToRsbuildConfig( - libConfig, + // Some configurations can be defined both in the shared config and the lib config. + // So we need to do the post process after lib config is converted and merged. + const postUpdatedConfig = postUpdateRsbuildConfig(mergedRsbuildConfig); + + composedRsbuildConfig[format!] = mergeRsbuildConfig( mergedRsbuildConfig, + postUpdatedConfig, + // Merge order matters, keep `internalRsbuildConfig` at the last position + // to ensure that the internal config is not overridden by user's config. + internalRsbuildConfig, ); } diff --git a/packages/core/src/types/config/index.ts b/packages/core/src/types/config/index.ts index b3dad7b31..38ffc1781 100644 --- a/packages/core/src/types/config/index.ts +++ b/packages/core/src/types/config/index.ts @@ -1,12 +1,38 @@ import type { RsbuildConfig } from '@rsbuild/core'; export type Format = 'esm' | 'cjs' | 'umd'; -export type Platform = 'node' | 'browser' | 'neutral'; + +export type EcmaScriptVersion = + | 'esnext' + | 'es5' + | 'es6' + | 'es2015' + | 'es2016' + | 'es2017' + | 'es2018' + | 'es2019' + | 'es2020' + | 'es2021' + | 'es2022' + | 'es2023' + | 'es2024'; + +export type Syntax = + // Use browserslist config file + | 'browserslist' + // ECMAScript versions as an common used addition to browserslist query + | EcmaScriptVersion + | EcmaScriptVersion[] + // Support inline browserslist query, like defined in package.json + | string[]; export interface LibConfig extends RsbuildConfig { format?: Format; - platform?: Platform; autoExtension?: boolean; + output?: RsbuildConfig['output'] & { + /** Support esX and browserslist query */ + syntax?: Syntax; + }; } export interface RslibConfig extends RsbuildConfig { diff --git a/packages/core/src/utils/browserslist.ts b/packages/core/src/utils/browserslist.ts new file mode 100644 index 000000000..a84928860 --- /dev/null +++ b/packages/core/src/utils/browserslist.ts @@ -0,0 +1,8 @@ +import type { EcmaScriptVersion } from '../types/config'; + +export const esVersionToBrowserList = ( + _esVersion: EcmaScriptVersion, +): string[] => { + // TODO: transform esX to browserslist + return []; +};