@@ -889,13 +889,14 @@ const composeEntryConfig = async (
889889 bundle : LibConfig [ 'bundle' ] ,
890890 root : string ,
891891 cssModulesAuto : CssLoaderOptionsAuto ,
892- ) : Promise < { entryConfig : EnvironmentConfig ; lcp : string | null } > => {
892+ userOutBase ?: string ,
893+ ) : Promise < { entryConfig : EnvironmentConfig ; outBase : string | null } > => {
893894 let entries : RsbuildConfigEntry = rawEntry ;
894895
895896 if ( ! entries ) {
896897 // In bundle mode, return directly to let Rsbuild apply default entry to './src/index.ts'
897898 if ( bundle !== false ) {
898- return { entryConfig : { } , lcp : null } ;
899+ return { entryConfig : { } , outBase : null } ;
899900 }
900901
901902 // In bundleless mode, set default entry to './src/**'
@@ -957,13 +958,26 @@ const composeEntryConfig = async (
957958 entry : appendEntryQuery ( resolveEntryPath ( entries , root ) ) ,
958959 } ,
959960 } ,
960- lcp : null ,
961+ outBase : null ,
961962 } ;
962963 }
963964
964- const scanGlobEntries = async ( calcLcp : boolean ) => {
965+ const scanGlobEntries = async ( tryResolveOutBase : boolean ) => {
965966 // In bundleless mode, resolve glob patterns and convert them to entry object.
966967 const resolvedEntries : Record < string , string > = { } ;
968+
969+ const resolveOutBase = async ( resolvedEntryFiles : string [ ] ) => {
970+ if ( userOutBase !== undefined ) {
971+ return path . isAbsolute ( userOutBase )
972+ ? userOutBase
973+ : path . resolve ( root , userOutBase ) ;
974+ }
975+ // Similar to `rootDir` in tsconfig and `outbase` in esbuild.
976+ // Using the longest common path of all non-declaration input files if not specified.
977+ const lcp = ( await calcLongestCommonPath ( resolvedEntryFiles ) ) ?? root ;
978+ return lcp ;
979+ } ;
980+
967981 for ( const key of Object . keys ( entries ) ) {
968982 const entry = entries [ key ] ;
969983
@@ -998,10 +1012,7 @@ const composeEntryConfig = async (
9981012 throw new Error ( `Cannot find ${ resolvedEntryFiles } ` ) ;
9991013 }
10001014
1001- // Similar to `rootDir` in tsconfig and `outbase` in esbuild.
1002- const lcp = await calcLongestCommonPath ( resolvedEntryFiles ) ;
1003- // Using the longest common path of all non-declaration input files by default.
1004- const outBase = lcp === null ? root : lcp ;
1015+ const outBase = await resolveOutBase ( resolvedEntryFiles ) ;
10051016
10061017 function getEntryName ( file : string ) {
10071018 const { dir, name } = path . parse ( path . relative ( outBase , file ) ) ;
@@ -1021,7 +1032,7 @@ const composeEntryConfig = async (
10211032 const entryName = getEntryName ( file ) ;
10221033
10231034 if ( resolvedEntries [ entryName ] ) {
1024- calcLcp &&
1035+ tryResolveOutBase &&
10251036 logger . warn (
10261037 `Duplicate entry ${ color . cyan ( entryName ) } from ${ color . cyan (
10271038 path . relative ( root , file ) ,
@@ -1035,15 +1046,15 @@ const composeEntryConfig = async (
10351046 }
10361047 }
10371048
1038- if ( calcLcp ) {
1039- const lcp = await calcLongestCommonPath ( Object . values ( resolvedEntries ) ) ;
1040- return { resolvedEntries, lcp } ;
1049+ if ( tryResolveOutBase ) {
1050+ const outBase = await resolveOutBase ( Object . values ( resolvedEntries ) ) ;
1051+ return { resolvedEntries, outBase } ;
10411052 }
1042- return { resolvedEntries, lcp : null } ;
1053+ return { resolvedEntries, outBase : null } ;
10431054 } ;
10441055
1045- // LCP could only be determined at the first time of glob scan.
1046- const { lcp } = await scanGlobEntries ( true ) ;
1056+ // OutBase could only be determined at the first time of glob scan.
1057+ const { outBase } = await scanGlobEntries ( true ) ;
10471058 const entryConfig : EnvironmentConfig = {
10481059 tools : {
10491060 rspack : {
@@ -1057,7 +1068,7 @@ const composeEntryConfig = async (
10571068
10581069 return {
10591070 entryConfig,
1060- lcp ,
1071+ outBase ,
10611072 } ;
10621073} ;
10631074
@@ -1416,14 +1427,15 @@ async function composeLibRsbuildConfig(
14161427 pkgJson,
14171428 userExternals : config . output ?. externals ,
14181429 } ) ;
1419- const { entryConfig, lcp } = await composeEntryConfig (
1430+ const { entryConfig, outBase } = await composeEntryConfig (
14201431 config . source ?. entry ! ,
14211432 config . bundle ,
14221433 rootPath ,
14231434 cssModulesAuto ,
1435+ config . outBase ,
14241436 ) ;
14251437 const cssConfig = composeCssConfig (
1426- lcp ,
1438+ outBase ,
14271439 config . bundle ,
14281440 banner ?. css ,
14291441 footer ?. css ,
@@ -1432,7 +1444,7 @@ async function composeLibRsbuildConfig(
14321444
14331445 const entryChunkConfig = composeEntryChunkConfig ( {
14341446 enabledImportMetaUrlShim : enabledShims . cjs [ 'import.meta.url' ] ,
1435- contextToWatch : lcp ,
1447+ contextToWatch : outBase ,
14361448 } ) ;
14371449 const dtsConfig = await composeDtsConfig ( config , dtsExtension ) ;
14381450 const externalsWarnConfig = composeExternalsWarnConfig (
@@ -1549,6 +1561,7 @@ export async function composeCreateRsbuildConfig(
15491561 dts : true ,
15501562 shims : true ,
15511563 umdName : true ,
1564+ outBase : true ,
15521565 } ) ,
15531566 ) ,
15541567 } ;
0 commit comments