Skip to content

Commit 30b0ec1

Browse files
authored
feat(command): support --lib arguments (#390)
1 parent c42383a commit 30b0ec1

File tree

8 files changed

+204
-55
lines changed

8 files changed

+204
-55
lines changed

packages/core/src/build.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
import type { RsbuildInstance } from '@rsbuild/core';
1+
import { type RsbuildInstance, createRsbuild } from '@rsbuild/core';
22
import type { BuildOptions } from './cli/commands';
3-
import { initRsbuild } from './config';
3+
import { composeRsbuildEnvironments, pruneEnvironments } from './config';
44
import type { RslibConfig } from './types/config';
55

66
export async function build(
77
config: RslibConfig,
88
options?: BuildOptions,
99
): Promise<RsbuildInstance> {
10-
const rsbuildInstance = await initRsbuild(config);
10+
const environments = await composeRsbuildEnvironments(config);
11+
const rsbuildInstance = await createRsbuild({
12+
rsbuildConfig: {
13+
environments: pruneEnvironments(environments, options?.lib),
14+
},
15+
});
1116

1217
await rsbuildInstance.build({
1318
watch: options?.watch,

packages/core/src/cli/commands.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
import type { RsbuildMode } from '@rsbuild/core';
1+
import { type RsbuildMode, createRsbuild } from '@rsbuild/core';
22
import { type Command, program } from 'commander';
33
import { build } from '../build';
4-
import { initRsbuild, loadConfig } from '../config';
4+
import {
5+
composeRsbuildEnvironments,
6+
loadConfig,
7+
pruneEnvironments,
8+
} from '../config';
59
import { logger } from '../utils/logger';
610

711
export type CommonOptions = {
812
config?: string;
913
envMode?: string;
14+
lib?: string[];
1015
};
1116

1217
export type BuildOptions = CommonOptions & {
@@ -31,6 +36,10 @@ const applyCommonOptions = (command: Command) => {
3136
);
3237
};
3338

39+
const repeatableOption = (value: string, previous: string[]) => {
40+
return (previous ?? []).concat([value]);
41+
};
42+
3443
export function runCli(): void {
3544
program.name('rslib').usage('<command> [options]').version(RSLIB_VERSION);
3645

@@ -40,6 +49,11 @@ export function runCli(): void {
4049
[buildCommand, inspectCommand].forEach(applyCommonOptions);
4150

4251
buildCommand
52+
.option(
53+
'--lib <name>',
54+
'build the specified library (may be repeated)',
55+
repeatableOption,
56+
)
4357
.option('-w --watch', 'turn on watch mode, watch for changes and rebuild')
4458
.description('build the library for production')
4559
.action(async (options: BuildOptions) => {
@@ -58,6 +72,11 @@ export function runCli(): void {
5872

5973
inspectCommand
6074
.description('inspect the Rsbuild / Rspack configs of Rslib projects')
75+
.option(
76+
'--lib <name>',
77+
'inspect the specified library (may be repeated)',
78+
repeatableOption,
79+
)
6180
.option(
6281
'--output <output>',
6382
'specify inspect content output path',
@@ -71,7 +90,12 @@ export function runCli(): void {
7190
path: options.config,
7291
envMode: options.envMode,
7392
});
74-
const rsbuildInstance = await initRsbuild(rslibConfig);
93+
const environments = await composeRsbuildEnvironments(rslibConfig);
94+
const rsbuildInstance = await createRsbuild({
95+
rsbuildConfig: {
96+
environments: pruneEnvironments(environments, options.lib),
97+
},
98+
});
7599
await rsbuildInstance.inspectConfig({
76100
mode: options.mode,
77101
verbose: options.verbose,

packages/core/src/config.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import fs from 'node:fs';
22
import path, { dirname, extname, isAbsolute, join } from 'node:path';
33
import {
4+
type EnvironmentConfig,
45
type RsbuildConfig,
5-
type RsbuildInstance,
6-
createRsbuild,
76
defineConfig as defineRsbuildConfig,
87
loadConfig as loadRsbuildConfig,
98
mergeRsbuildConfig,
@@ -1191,9 +1190,9 @@ export async function composeCreateRsbuildConfig(
11911190
return composedRsbuildConfig;
11921191
}
11931192

1194-
export async function initRsbuild(
1193+
export async function composeRsbuildEnvironments(
11951194
rslibConfig: RslibConfig,
1196-
): Promise<RsbuildInstance> {
1195+
): Promise<Record<string, EnvironmentConfig>> {
11971196
const rsbuildConfigObject = await composeCreateRsbuildConfig(rslibConfig);
11981197
const environments: RsbuildConfig['environments'] = {};
11991198
const formatCount: Record<Format, number> = rsbuildConfigObject.reduce(
@@ -1220,9 +1219,18 @@ export async function initRsbuild(
12201219
] = config;
12211220
}
12221221

1223-
return createRsbuild({
1224-
rsbuildConfig: {
1225-
environments,
1226-
},
1227-
});
1222+
return environments;
12281223
}
1224+
1225+
export const pruneEnvironments = (
1226+
environments: Record<string, EnvironmentConfig>,
1227+
libs?: string[],
1228+
): Record<string, EnvironmentConfig> => {
1229+
if (!libs) {
1230+
return environments;
1231+
}
1232+
1233+
return Object.fromEntries(
1234+
Object.entries(environments).filter(([name]) => libs.includes(name)),
1235+
);
1236+
};

tests/integration/cli/build.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { execSync } from 'node:child_process';
2+
import path from 'node:path';
3+
import fse from 'fs-extra';
4+
import { globContentJSON } from 'test-helper';
5+
import { describe, expect, test } from 'vitest';
6+
7+
describe('build command', async () => {
8+
test('basic', async () => {
9+
await fse.remove(path.join(__dirname, 'dist'));
10+
execSync('npx rslib build', {
11+
cwd: __dirname,
12+
});
13+
14+
const files = await globContentJSON(path.join(__dirname, 'dist'));
15+
const fileNames = Object.keys(files).sort();
16+
expect(fileNames).toMatchInlineSnapshot(`
17+
[
18+
"<ROOT>/tests/integration/cli/dist/cjs/index.cjs",
19+
"<ROOT>/tests/integration/cli/dist/esm/index.js",
20+
]
21+
`);
22+
});
23+
24+
test('--lib', async () => {
25+
await fse.remove(path.join(__dirname, 'dist'));
26+
execSync('npx rslib build --lib esm', {
27+
cwd: __dirname,
28+
});
29+
30+
const files = await globContentJSON(path.join(__dirname, 'dist'));
31+
const fileNames = Object.keys(files).sort();
32+
expect(fileNames).toMatchInlineSnapshot(`
33+
[
34+
"<ROOT>/tests/integration/cli/dist/esm/index.js",
35+
]
36+
`);
37+
});
38+
39+
test('--lib multiple', async () => {
40+
await fse.remove(path.join(__dirname, 'dist'));
41+
execSync('npx rslib build --lib esm --lib cjs', {
42+
cwd: __dirname,
43+
});
44+
45+
const files = await globContentJSON(path.join(__dirname, 'dist'));
46+
const fileNames = Object.keys(files).sort();
47+
expect(fileNames).toMatchInlineSnapshot(`
48+
[
49+
"<ROOT>/tests/integration/cli/dist/cjs/index.cjs",
50+
"<ROOT>/tests/integration/cli/dist/esm/index.js",
51+
]
52+
`);
53+
});
54+
});

tests/integration/cli/index.test.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

tests/integration/cli/inspect.test.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { execSync } from 'node:child_process';
2+
import path from 'node:path';
3+
import { describe } from 'node:test';
4+
import fse from 'fs-extra';
5+
import { globContentJSON } from 'test-helper';
6+
import { expect, test } from 'vitest';
7+
8+
describe('inspect command', async () => {
9+
test('basic', async () => {
10+
await fse.remove(path.join(__dirname, 'dist'));
11+
execSync('npx rslib inspect', {
12+
cwd: __dirname,
13+
});
14+
15+
const files = await globContentJSON(path.join(__dirname, 'dist/.rsbuild'));
16+
const fileNames = Object.keys(files).sort();
17+
18+
expect(fileNames).toMatchInlineSnapshot(`
19+
[
20+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rsbuild.config.cjs.mjs",
21+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rsbuild.config.esm.mjs",
22+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rspack.config.cjs.mjs",
23+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rspack.config.esm.mjs",
24+
]
25+
`);
26+
27+
// esm rsbuild config
28+
const rsbuildConfigEsm = fileNames.find((item) =>
29+
item.includes('rsbuild.config.esm.mjs'),
30+
);
31+
expect(rsbuildConfigEsm).toBeTruthy();
32+
expect(files[rsbuildConfigEsm!]).toContain("type: 'modern-module'");
33+
34+
// esm rspack config
35+
const rspackConfigEsm = fileNames.find((item) =>
36+
item.includes('rspack.config.esm.mjs'),
37+
);
38+
expect(rspackConfigEsm).toBeTruthy();
39+
expect(files[rspackConfigEsm!]).toContain("type: 'modern-module'");
40+
});
41+
42+
test('--lib', async () => {
43+
await fse.remove(path.join(__dirname, 'dist'));
44+
execSync('npx rslib inspect --lib esm', {
45+
cwd: __dirname,
46+
});
47+
48+
const files = await globContentJSON(
49+
path.join(__dirname, 'dist/esm/.rsbuild'),
50+
);
51+
const fileNames = Object.keys(files).sort();
52+
53+
// Rsbuild will emit dump files to `dist/esm` if only one environment is specified.
54+
expect(fileNames).toMatchInlineSnapshot(`
55+
[
56+
"<ROOT>/tests/integration/cli/dist/esm/.rsbuild/rsbuild.config.mjs",
57+
"<ROOT>/tests/integration/cli/dist/esm/.rsbuild/rspack.config.esm.mjs",
58+
]
59+
`);
60+
61+
// esm rsbuild config
62+
const rsbuildConfigEsm = fileNames.find((item) =>
63+
item.includes('rsbuild.config.mjs'),
64+
);
65+
expect(rsbuildConfigEsm).toBeTruthy();
66+
expect(files[rsbuildConfigEsm!]).toContain("type: 'modern-module'");
67+
68+
// esm rspack config
69+
const rspackConfigEsm = fileNames.find((item) =>
70+
item.includes('rspack.config.esm.mjs'),
71+
);
72+
expect(rspackConfigEsm).toBeTruthy();
73+
expect(files[rspackConfigEsm!]).toContain("type: 'modern-module'");
74+
});
75+
76+
test('--lib multiple', async () => {
77+
await fse.remove(path.join(__dirname, 'dist'));
78+
execSync('npx rslib inspect --lib esm --lib cjs', {
79+
cwd: __dirname,
80+
});
81+
82+
const files = await globContentJSON(path.join(__dirname, 'dist/.rsbuild'));
83+
const fileNames = Object.keys(files).sort();
84+
85+
// Rsbuild will emit dump files to `dist/esm` if only one environment is specified.
86+
expect(fileNames).toMatchInlineSnapshot(`
87+
[
88+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rsbuild.config.cjs.mjs",
89+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rsbuild.config.esm.mjs",
90+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rspack.config.cjs.mjs",
91+
"<ROOT>/tests/integration/cli/dist/.rsbuild/rspack.config.esm.mjs",
92+
]
93+
`);
94+
});
95+
});

tests/integration/cli/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const foo = 'foo';

website/docs/en/guide/basic/cli.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ build the library for production
3737
Options:
3838
-c --config <config> specify the configuration file, can be a relative or absolute path
3939
--env-mode <mode> specify the env mode to load the `.env.[mode]` file
40+
--lib <name> build the specified library (may be repeated)
4041
-w --watch turn on watch mode, watch for changes and rebuild
4142
-h, --help display help for command
4243
```
@@ -58,6 +59,7 @@ inspect the Rsbuild / Rspack configs of Rslib projects
5859
Options:
5960
-c --config <config> specify the configuration file, can be a relative or absolute path
6061
--env-mode <mode> specify the env mode to load the `.env.[mode]` file
62+
--lib <name> build the specified library (may be repeated)
6163
--output <output> specify inspect content output path (default: ".rsbuild")
6264
--verbose show full function definitions in output
6365
-h, --help display help for command

0 commit comments

Comments
 (0)