diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 528fbce5..69062d73 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -11,6 +11,7 @@ import { import glob from 'fast-glob'; import { DEFAULT_CONFIG_NAME, DEFAULT_EXTENSIONS } from './constant'; import type { + AutoExternal, Format, LibConfig, PkgJson, @@ -21,7 +22,6 @@ import type { Syntax, } from './types'; import { getDefaultExtension } from './utils/extension'; -import { composeAutoExternalConfig } from './utils/external'; import { calcLongestCommonPath, color, @@ -82,6 +82,60 @@ export async function loadConfig( return content as RslibConfig; } +export const composeAutoExternalConfig = (options: { + autoExternal: AutoExternal; + pkgJson?: PkgJson; + userExternals?: NonNullable['externals']; +}): RsbuildConfig => { + const { autoExternal, pkgJson, userExternals } = options; + + if (!autoExternal) { + return {}; + } + + if (!pkgJson) { + logger.warn( + 'autoExternal configuration will not be applied due to read package.json failed', + ); + return {}; + } + + const externalOptions = { + dependencies: true, + peerDependencies: true, + devDependencies: false, + ...(autoExternal === true ? {} : autoExternal), + }; + + // User externals configuration has higher priority than autoExternal + // eg: autoExternal: ['react'], user: output: { externals: { react: 'react-1' } } + // Only handle the case where the externals type is object, string / string[] does not need to be processed, other types are too complex. + const userExternalKeys = + userExternals && + Object.prototype.toString.call(userExternals) === '[object Object]' + ? Object.keys(userExternals) + : []; + + const externals = ( + ['dependencies', 'peerDependencies', 'devDependencies'] as const + ) + .reduce((prev, type) => { + if (externalOptions[type]) { + return pkgJson[type] ? prev.concat(Object.keys(pkgJson[type]!)) : prev; + } + return prev; + }, []) + .filter((name) => !userExternalKeys.includes(name)); + + return externals.length + ? { + output: { + externals: Array.from(new Set(externals)), + }, + } + : {}; +}; + export async function createInternalRsbuildConfig(): Promise { return defineRsbuildConfig({ dev: { diff --git a/packages/core/src/utils/external.ts b/packages/core/src/utils/external.ts deleted file mode 100644 index c066fbb0..00000000 --- a/packages/core/src/utils/external.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { RsbuildConfig } from '@rsbuild/core'; -import type { PkgJson } from '../types'; -import type { AutoExternal } from '../types/config'; -import { logger } from './logger'; - -export const composeAutoExternalConfig = (options: { - autoExternal: AutoExternal; - pkgJson?: PkgJson; - userExternals?: NonNullable['externals']; -}): RsbuildConfig => { - const { autoExternal, pkgJson, userExternals } = options; - - if (!autoExternal) { - return {}; - } - - if (!pkgJson) { - logger.warn( - 'autoExternal configuration will not be applied due to read package.json failed', - ); - return {}; - } - - const externalOptions = { - dependencies: true, - peerDependencies: true, - devDependencies: false, - ...(autoExternal === true ? {} : autoExternal), - }; - - // User externals configuration has higher priority than autoExternal - // eg: autoExternal: ['react'], user: output: { externals: { react: 'react-1' } } - // Only handle the case where the externals type is object, string / string[] does not need to be processed, other types are too complex. - const userExternalKeys = - userExternals && - Object.prototype.toString.call(userExternals) === '[object Object]' - ? Object.keys(userExternals) - : []; - - const externals = ( - ['dependencies', 'peerDependencies', 'devDependencies'] as const - ) - .reduce((prev, type) => { - if (externalOptions[type]) { - return pkgJson[type] ? prev.concat(Object.keys(pkgJson[type]!)) : prev; - } - return prev; - }, []) - .filter((name) => !userExternalKeys.includes(name)); - - return externals.length - ? { - output: { - externals, - }, - } - : {}; -}; diff --git a/packages/core/tests/external.test.ts b/packages/core/tests/external.test.ts index 6e194d33..95ab8288 100644 --- a/packages/core/tests/external.test.ts +++ b/packages/core/tests/external.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from 'vitest'; -import { composeAutoExternalConfig } from '../src/utils/external'; +import { composeAutoExternalConfig } from '../src/config'; vi.mock('rslog'); @@ -28,6 +28,32 @@ describe('should composeAutoExternalConfig correctly', () => { }); }); + it('autoExternal will deduplication ', () => { + const result = composeAutoExternalConfig({ + autoExternal: true, + pkgJson: { + dependencies: { + foo: '1.0.0', + foo1: '1.0.0', + }, + devDependencies: { + bar: '1.0.0', + }, + peerDependencies: { + baz: '1.0.0', + foo: '1.0.0', + foo1: '1.0.0', + }, + }, + }); + + expect(result).toEqual({ + output: { + externals: ['foo', 'foo1', 'baz'], + }, + }); + }); + it('autoExternal is object', () => { const result = composeAutoExternalConfig({ autoExternal: {