Skip to content

Commit 1b66825

Browse files
committed
feat: support outBase config
1 parent 36dea47 commit 1b66825

File tree

14 files changed

+114
-15
lines changed

14 files changed

+114
-15
lines changed

packages/core/src/config.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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,22 @@ const composeEntryConfig = async (
957958
entry: appendEntryQuery(resolveEntryPath(entries, root)),
958959
},
959960
},
960-
lcp: null,
961+
outBase: null,
961962
};
962963
}
963964

964965
const scanGlobEntries = async (calcLcp: boolean) => {
965966
// In bundleless mode, resolve glob patterns and convert them to entry object.
966967
const resolvedEntries: Record<string, string> = {};
968+
969+
const calcOutBase = async (resolvedEntryFiles: string[]) => {
970+
// Similar to `rootDir` in tsconfig and `outbase` in esbuild.
971+
const lcp = await calcLongestCommonPath(resolvedEntryFiles);
972+
// Using the longest common path of all non-declaration input files by default.
973+
const outBase = userOutBase ?? (lcp === null ? root : lcp);
974+
return outBase;
975+
};
976+
967977
for (const key of Object.keys(entries)) {
968978
const entry = entries[key];
969979

@@ -998,10 +1008,7 @@ const composeEntryConfig = async (
9981008
throw new Error(`Cannot find ${resolvedEntryFiles}`);
9991009
}
10001010

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;
1011+
const outBase = await calcOutBase(resolvedEntryFiles);
10051012

10061013
function getEntryName(file: string) {
10071014
const { dir, name } = path.parse(path.relative(outBase, file));
@@ -1036,14 +1043,14 @@ const composeEntryConfig = async (
10361043
}
10371044

10381045
if (calcLcp) {
1039-
const lcp = await calcLongestCommonPath(Object.values(resolvedEntries));
1040-
return { resolvedEntries, lcp };
1046+
const outBase = await calcOutBase(Object.values(resolvedEntries));
1047+
return { resolvedEntries, outBase };
10411048
}
1042-
return { resolvedEntries, lcp: null };
1049+
return { resolvedEntries, outBase: null };
10431050
};
10441051

10451052
// LCP could only be determined at the first time of glob scan.
1046-
const { lcp } = await scanGlobEntries(true);
1053+
const { outBase } = await scanGlobEntries(true);
10471054
const entryConfig: EnvironmentConfig = {
10481055
tools: {
10491056
rspack: {
@@ -1057,7 +1064,7 @@ const composeEntryConfig = async (
10571064

10581065
return {
10591066
entryConfig,
1060-
lcp,
1067+
outBase,
10611068
};
10621069
};
10631070

@@ -1415,14 +1422,15 @@ async function composeLibRsbuildConfig(
14151422
pkgJson,
14161423
userExternals: config.output?.externals,
14171424
});
1418-
const { entryConfig, lcp } = await composeEntryConfig(
1425+
const { entryConfig, outBase } = await composeEntryConfig(
14191426
config.source?.entry!,
14201427
config.bundle,
14211428
rootPath,
14221429
cssModulesAuto,
1430+
config.outBase,
14231431
);
14241432
const cssConfig = composeCssConfig(
1425-
lcp,
1433+
outBase,
14261434
config.bundle,
14271435
banner?.css,
14281436
footer?.css,
@@ -1431,7 +1439,7 @@ async function composeLibRsbuildConfig(
14311439

14321440
const entryChunkConfig = composeEntryChunkConfig({
14331441
enabledImportMetaUrlShim: enabledShims.cjs['import.meta.url'],
1434-
contextToWatch: lcp,
1442+
contextToWatch: outBase,
14351443
});
14361444
const dtsConfig = await composeDtsConfig(config, dtsExtension);
14371445
const externalsWarnConfig = composeExternalsWarnConfig(
@@ -1548,6 +1556,7 @@ export async function composeCreateRsbuildConfig(
15481556
dts: true,
15491557
shims: true,
15501558
umdName: true,
1559+
outBase: true,
15511560
}),
15521561
),
15531562
};

packages/core/src/types/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ export interface LibConfig extends EnvironmentConfig {
285285
* @see {@link https://lib.rsbuild.dev/config/lib/umd-name}
286286
*/
287287
umdName?: string;
288+
/**
289+
* The base directory of the output files.
290+
* @defaultValue `undefined`
291+
* @see {@link https://lib.rsbuild.dev/config/lib/out-base}
292+
*/
293+
outBase?: string;
288294
}
289295

290296
export type LibOnlyConfig = Omit<LibConfig, keyof EnvironmentConfig>;

pnpm-lock.yaml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "outbase-nested-dir-test",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module"
6+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineConfig } from '@rslib/core';
2+
import { generateBundleEsmConfig } from 'test-helper';
3+
4+
export default defineConfig({
5+
lib: [
6+
generateBundleEsmConfig({
7+
bundle: false,
8+
outBase: './src/utils',
9+
source: {
10+
entry: {
11+
index: './src/utils/foo',
12+
},
13+
},
14+
}),
15+
],
16+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const bar = 'foo';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const foo = 'foo';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { foo } from './foo';
2+
export { bar } from './bar';
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { join } from 'node:path';
2+
import { buildAndGetResults } from 'test-helper';
3+
import { describe, expect, test } from 'vitest';
4+
5+
describe('outBase', async () => {
6+
test('nested-dir', async () => {
7+
const fixturePath = join(__dirname, 'nested-dir');
8+
const { files } = await buildAndGetResults({
9+
fixturePath,
10+
});
11+
12+
expect(files.esm.sort()).toMatchInlineSnapshot(`
13+
[
14+
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm/utils/bar/index.js",
15+
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm/utils/foo/index.js",
16+
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm/utils/index.js",
17+
]
18+
`);
19+
});
20+
21+
test('custom', async () => {
22+
const fixturePath = join(__dirname, 'custom');
23+
const { files } = await buildAndGetResults({
24+
fixturePath,
25+
});
26+
27+
expect(files.esm.sort()).toMatchInlineSnapshot(`
28+
[
29+
"<ROOT>/tests/integration/outBase/custom/dist/esm/foo/index.js",
30+
]
31+
`);
32+
});
33+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "outbase-custom-test",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module"
6+
}

0 commit comments

Comments
 (0)