Skip to content

Commit

Permalink
feat: support outBase config (#745)
Browse files Browse the repository at this point in the history
Co-authored-by: Timeless0911 <[email protected]>
  • Loading branch information
fi3ework and Timeless0911 authored Feb 11, 2025
1 parent 676cad1 commit 53a8598
Show file tree
Hide file tree
Showing 21 changed files with 335 additions and 24 deletions.
51 changes: 32 additions & 19 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -889,13 +889,14 @@ const composeEntryConfig = async (
bundle: LibConfig['bundle'],
root: string,
cssModulesAuto: CssLoaderOptionsAuto,
): Promise<{ entryConfig: EnvironmentConfig; lcp: string | null }> => {
userOutBase?: string,
): Promise<{ entryConfig: EnvironmentConfig; outBase: string | null }> => {
let entries: RsbuildConfigEntry = rawEntry;

if (!entries) {
// In bundle mode, return directly to let Rsbuild apply default entry to './src/index.ts'
if (bundle !== false) {
return { entryConfig: {}, lcp: null };
return { entryConfig: {}, outBase: null };
}

// In bundleless mode, set default entry to './src/**'
Expand Down Expand Up @@ -957,13 +958,26 @@ const composeEntryConfig = async (
entry: appendEntryQuery(resolveEntryPath(entries, root)),
},
},
lcp: null,
outBase: null,
};
}

const scanGlobEntries = async (calcLcp: boolean) => {
const scanGlobEntries = async (tryResolveOutBase: boolean) => {
// In bundleless mode, resolve glob patterns and convert them to entry object.
const resolvedEntries: Record<string, string> = {};

const resolveOutBase = async (resolvedEntryFiles: string[]) => {
if (userOutBase !== undefined) {
return path.isAbsolute(userOutBase)
? userOutBase
: path.resolve(root, userOutBase);
}
// Similar to `rootDir` in tsconfig and `outbase` in esbuild.
// Using the longest common path of all non-declaration input files if not specified.
const lcp = (await calcLongestCommonPath(resolvedEntryFiles)) ?? root;
return lcp;
};

for (const key of Object.keys(entries)) {
const entry = entries[key];

Expand Down Expand Up @@ -998,10 +1012,7 @@ const composeEntryConfig = async (
throw new Error(`Cannot find ${resolvedEntryFiles}`);
}

// Similar to `rootDir` in tsconfig and `outbase` in esbuild.
const lcp = await calcLongestCommonPath(resolvedEntryFiles);
// Using the longest common path of all non-declaration input files by default.
const outBase = lcp === null ? root : lcp;
const outBase = await resolveOutBase(resolvedEntryFiles);

function getEntryName(file: string) {
const { dir, name } = path.parse(path.relative(outBase, file));
Expand All @@ -1021,7 +1032,7 @@ const composeEntryConfig = async (
const entryName = getEntryName(file);

if (resolvedEntries[entryName]) {
calcLcp &&
tryResolveOutBase &&
logger.warn(
`Duplicate entry ${color.cyan(entryName)} from ${color.cyan(
path.relative(root, file),
Expand All @@ -1035,15 +1046,15 @@ const composeEntryConfig = async (
}
}

if (calcLcp) {
const lcp = await calcLongestCommonPath(Object.values(resolvedEntries));
return { resolvedEntries, lcp };
if (tryResolveOutBase) {
const outBase = await resolveOutBase(Object.values(resolvedEntries));
return { resolvedEntries, outBase };
}
return { resolvedEntries, lcp: null };
return { resolvedEntries, outBase: null };
};

// LCP could only be determined at the first time of glob scan.
const { lcp } = await scanGlobEntries(true);
// OutBase could only be determined at the first time of glob scan.
const { outBase } = await scanGlobEntries(true);
const entryConfig: EnvironmentConfig = {
tools: {
rspack: {
Expand All @@ -1057,7 +1068,7 @@ const composeEntryConfig = async (

return {
entryConfig,
lcp,
outBase,
};
};

Expand Down Expand Up @@ -1416,14 +1427,15 @@ async function composeLibRsbuildConfig(
pkgJson,
userExternals: config.output?.externals,
});
const { entryConfig, lcp } = await composeEntryConfig(
const { entryConfig, outBase } = await composeEntryConfig(
config.source?.entry!,
config.bundle,
rootPath,
cssModulesAuto,
config.outBase,
);
const cssConfig = composeCssConfig(
lcp,
outBase,
config.bundle,
banner?.css,
footer?.css,
Expand All @@ -1432,7 +1444,7 @@ async function composeLibRsbuildConfig(

const entryChunkConfig = composeEntryChunkConfig({
enabledImportMetaUrlShim: enabledShims.cjs['import.meta.url'],
contextToWatch: lcp,
contextToWatch: outBase,
});
const dtsConfig = await composeDtsConfig(config, dtsExtension);
const externalsWarnConfig = composeExternalsWarnConfig(
Expand Down Expand Up @@ -1549,6 +1561,7 @@ export async function composeCreateRsbuildConfig(
dts: true,
shims: true,
umdName: true,
outBase: true,
}),
),
};
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,12 @@ export interface LibConfig extends EnvironmentConfig {
* @see {@link https://lib.rsbuild.dev/config/lib/umd-name}
*/
umdName?: string;
/**
* The base directory of the output files.
* @defaultValue `undefined`
* @see {@link https://lib.rsbuild.dev/config/lib/out-base}
*/
outBase?: string;
}

export type LibOnlyConfig = Omit<LibConfig, keyof EnvironmentConfig>;
Expand Down
4 changes: 4 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions tests/integration/outBase/custom-entry/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "outbase-custom-entry-dir-test",
"version": "1.0.0",
"private": true,
"type": "module"
}
52 changes: 52 additions & 0 deletions tests/integration/outBase/custom-entry/rslib.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import path from 'node:path';
import { defineConfig } from '@rslib/core';
import { generateBundleEsmConfig } from 'test-helper';

export default defineConfig({
lib: [
// default
generateBundleEsmConfig({
bundle: false,
source: {
entry: {
index: './src/utils/foo',
},
},
output: {
distPath: {
root: './dist/esm0',
},
},
}),
// configured with relative outBase
generateBundleEsmConfig({
bundle: false,
outBase: './src/utils',
source: {
entry: {
index: './src/utils/foo',
},
},
output: {
distPath: {
root: './dist/esm1',
},
},
}),
// configured with absolute outBase
generateBundleEsmConfig({
bundle: false,
outBase: path.resolve(__dirname, 'src/utils'),
source: {
entry: {
index: './src/utils/foo',
},
},
output: {
distPath: {
root: './dist/esm2',
},
},
}),
],
});
1 change: 1 addition & 0 deletions tests/integration/outBase/custom-entry/src/bar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const bar = 'foo';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = 'foo';
2 changes: 2 additions & 0 deletions tests/integration/outBase/custom-entry/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { foo } from './foo';
export { bar } from './bar';
61 changes: 61 additions & 0 deletions tests/integration/outBase/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { join } from 'node:path';
import { buildAndGetResults } from 'test-helper';
import { describe, expect, test } from 'vitest';

describe('outBase', async () => {
test('base', async () => {
const fixturePath = join(__dirname, 'nested-dir');
const { files } = await buildAndGetResults({
fixturePath,
});

expect(files.esm0!.sort()).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm0/bar/index.js",
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm0/foo/index.js",
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm0/index.js",
]
`);

expect(files.esm1!.sort()).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm1/utils/bar/index.js",
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm1/utils/foo/index.js",
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm1/utils/index.js",
]
`);

expect(files.esm2!.sort()).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm2/utils/bar/index.js",
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm2/utils/foo/index.js",
"<ROOT>/tests/integration/outBase/nested-dir/dist/esm2/utils/index.js",
]
`);
});

test('with custom entry', async () => {
const fixturePath = join(__dirname, 'custom-entry');
const { files } = await buildAndGetResults({
fixturePath,
});

expect(files.esm0!.sort()).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/outBase/custom-entry/dist/esm0/index.js",
]
`);

expect(files.esm1!.sort()).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/outBase/custom-entry/dist/esm1/foo/index.js",
]
`);

expect(files.esm2!.sort()).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/outBase/custom-entry/dist/esm2/foo/index.js",
]
`);
});
});
6 changes: 6 additions & 0 deletions tests/integration/outBase/nested-dir/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "outbase-nested-dir-test",
"version": "1.0.0",
"private": true,
"type": "module"
}
37 changes: 37 additions & 0 deletions tests/integration/outBase/nested-dir/rslib.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import path from 'node:path';
import { defineConfig } from '@rslib/core';
import { generateBundleEsmConfig } from 'test-helper';

export default defineConfig({
lib: [
// default
generateBundleEsmConfig({
bundle: false,
output: {
distPath: {
root: './dist/esm0',
},
},
}),
// configured with relative outBase
generateBundleEsmConfig({
bundle: false,
outBase: './src',
output: {
distPath: {
root: './dist/esm1',
},
},
}),
// configured with absolute outBase
generateBundleEsmConfig({
bundle: false,
outBase: path.resolve(__dirname, 'src'),
output: {
distPath: {
root: './dist/esm2',
},
},
}),
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const bar = 'foo';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = 'foo';
2 changes: 2 additions & 0 deletions tests/integration/outBase/nested-dir/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { foo } from './foo';
export { bar } from './bar';
3 changes: 2 additions & 1 deletion website/docs/en/config/lib/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"dts",
"shims",
"id",
"umd-name"
"umd-name",
"out-base"
]
Loading

0 comments on commit 53a8598

Please sign in to comment.