Skip to content

Commit e1cfaff

Browse files
committed
feat: support more param for build command
11 11 1 doc thank u win32. doc
1 parent 0a56962 commit e1cfaff

File tree

34 files changed

+676
-65
lines changed

34 files changed

+676
-65
lines changed

packages/core/__mocks__/rslog.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ module.exports = {
22
logger: {
33
warn: () => {},
44
override: () => {},
5+
debug: () => {},
56
},
67
};

packages/core/src/cli/commands.ts

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { LogLevel, RsbuildMode } from '@rsbuild/core';
22
import cac, { type CAC } from 'cac';
33
import type { ConfigLoader } from '../config';
4+
import type { Format } from '../types/config';
45
import { logger } from '../utils/logger';
56
import { build } from './build';
6-
import { init } from './init';
7+
import { initConfig } from './initConfig';
78
import { inspect } from './inspect';
89
import { startMFDevServer } from './mf';
910
import { watchFilesForRestart } from './restart';
@@ -16,6 +17,19 @@ export type CommonOptions = {
1617
lib?: string[];
1718
configLoader?: ConfigLoader;
1819
logLevel?: LogLevel;
20+
format?: Format;
21+
entry?: string[];
22+
distPath?: string;
23+
bundle?: boolean;
24+
syntax?: string;
25+
target?: string;
26+
dts?: boolean;
27+
externals?: string[];
28+
minify?: boolean;
29+
clean?: boolean;
30+
autoExtension?: boolean;
31+
autoExternal?: boolean;
32+
tsconfig?: string;
1933
};
2034

2135
export type BuildOptions = CommonOptions & {
@@ -84,13 +98,45 @@ export function runCli(): void {
8498

8599
buildCommand
86100
.option('-w, --watch', 'turn on watch mode, watch for changes and rebuild')
101+
.option('--entry <entry>', 'set entry file or pattern (repeatable)', {
102+
type: [String],
103+
default: [],
104+
})
105+
.option('--dist-path <dir>', 'set output directory')
106+
.option('--bundle', 'enable bundle mode (use --no-bundle to disable)')
107+
.option(
108+
'--format <format>',
109+
'specify the output format (esm | cjs | umd | mf | iife)',
110+
)
111+
.option('--syntax <syntax>', 'set build syntax target (repeatable)')
112+
.option('--target <target>', 'set runtime target (web | node)')
113+
.option('--dts', 'emit declaration files (use --no-dts to disable)')
114+
.option('--externals <pkg>', 'add package to externals (repeatable)', {
115+
type: [String],
116+
default: [],
117+
})
118+
.option('--minify', 'minify output (use --no-minify to disable)')
119+
.option(
120+
'--clean',
121+
'clean output directory before build (use --no-clean to disable)',
122+
)
123+
.option(
124+
'--auto-extension',
125+
'control automatic extension redirect (use --no-auto-extension to disable)',
126+
)
127+
.option(
128+
'--auto-external',
129+
'control automatic dependency externalization (use --no-auto-external to disable)',
130+
)
131+
.option(
132+
'--tsconfig <path>',
133+
'use specific tsconfig (relative to project root)',
134+
)
87135
.action(async (options: BuildOptions) => {
88136
try {
89137
const cliBuild = async () => {
90-
const { config, watchFiles } = await init(options);
91-
138+
const { config, watchFiles } = await initConfig(options);
92139
await build(config, options);
93-
94140
if (options.watch) {
95141
watchFilesForRestart(watchFiles, async () => {
96142
await cliBuild();
@@ -120,7 +166,7 @@ export function runCli(): void {
120166
.action(async (options: InspectOptions) => {
121167
try {
122168
// TODO: inspect should output Rslib's config
123-
const { config } = await init(options);
169+
const { config } = await initConfig(options);
124170
await inspect(config, {
125171
lib: options.lib,
126172
mode: options.mode,
@@ -137,7 +183,7 @@ export function runCli(): void {
137183
mfDevCommand.action(async (options: CommonOptions) => {
138184
try {
139185
const cliMfDev = async () => {
140-
const { config, watchFiles } = await init(options);
186+
const { config, watchFiles } = await initConfig(options);
141187
await startMFDevServer(config, {
142188
lib: options.lib,
143189
});

packages/core/src/cli/init.ts

Lines changed: 0 additions & 56 deletions
This file was deleted.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import path from 'node:path';
2+
import util from 'node:util';
3+
import { loadEnv, type RsbuildEntry } from '@rsbuild/core';
4+
import { loadConfig } from '../config';
5+
import type {
6+
EcmaScriptVersion,
7+
RsbuildConfigOutputTarget,
8+
RslibConfig,
9+
Syntax,
10+
} from '../types';
11+
import { getAbsolutePath } from '../utils/helper';
12+
import { logger } from '../utils/logger';
13+
import type { CommonOptions } from './commands';
14+
import { onBeforeRestart } from './restart';
15+
16+
const getEnvDir = (cwd: string, envDir?: string) => {
17+
if (envDir) {
18+
return path.isAbsolute(envDir) ? envDir : path.resolve(cwd, envDir);
19+
}
20+
return cwd;
21+
};
22+
23+
export const parseEntryOption = (
24+
entries?: string[],
25+
): Record<string, string> | undefined => {
26+
if (!entries || entries.length === 0) {
27+
return undefined;
28+
}
29+
30+
const parsed: Record<string, string> = {};
31+
let unnamedIndex = 0;
32+
33+
for (const rawEntry of entries) {
34+
const value = rawEntry?.trim();
35+
if (!value) {
36+
continue;
37+
}
38+
39+
const equalIndex = value.indexOf('=');
40+
if (equalIndex > -1) {
41+
const name = value.slice(0, equalIndex).trim();
42+
const entryPath = value.slice(equalIndex + 1).trim();
43+
if (name && entryPath) {
44+
parsed[name] = entryPath;
45+
continue;
46+
}
47+
}
48+
49+
unnamedIndex += 1;
50+
const key = unnamedIndex === 1 ? 'index' : `entry${unnamedIndex}`;
51+
parsed[key] = value;
52+
}
53+
54+
return Object.keys(parsed).length === 0 ? undefined : parsed;
55+
};
56+
57+
// export const parseSyntaxOption = (syntax?: string): Syntax | undefined => {
58+
// if (!syntax) {
59+
// return undefined;
60+
// }
61+
62+
// const trimmed = syntax.trim();
63+
// if (!trimmed) {
64+
// return undefined;
65+
// }
66+
67+
// if (trimmed.startsWith('[')) {
68+
// try {
69+
// const parsed = JSON.parse(trimmed);
70+
// if (Array.isArray(parsed)) {
71+
// return parsed;
72+
// }
73+
// } catch (e) {
74+
// const reason = e instanceof Error ? e.message : String(e);
75+
// throw new Error(
76+
// `Failed to parse --syntax option "${trimmed}" as JSON array: ${reason}`,
77+
// );
78+
// }
79+
// }
80+
81+
// return trimmed as EcmaScriptVersion;
82+
// };
83+
84+
export const applyCliOptions = (
85+
config: RslibConfig,
86+
options: CommonOptions,
87+
root: string,
88+
): void => {
89+
if (options.root) config.root = root;
90+
if (options.logLevel) config.logLevel = options.logLevel;
91+
92+
for (const lib of config.lib) {
93+
if (options.format !== undefined) lib.format = options.format;
94+
if (options.bundle !== undefined) lib.bundle = options.bundle;
95+
if (options.tsconfig !== undefined) {
96+
lib.source ||= {};
97+
lib.source.tsconfigPath = options.tsconfig;
98+
}
99+
const entry = parseEntryOption(options.entry);
100+
if (entry !== undefined) {
101+
lib.source ||= {};
102+
lib.source.entry = entry as RsbuildEntry;
103+
}
104+
const syntax = options.syntax as Syntax | undefined;
105+
if (syntax !== undefined) lib.syntax = syntax;
106+
if (options.dts !== undefined) lib.dts = options.dts;
107+
if (options.autoExtension !== undefined)
108+
lib.autoExtension = options.autoExtension;
109+
if (options.autoExternal !== undefined)
110+
lib.autoExternal = options.autoExternal;
111+
const output = lib.output ?? {};
112+
if (options.target !== undefined)
113+
output.target = options.target as RsbuildConfigOutputTarget;
114+
if (options.minify !== undefined) output.minify = options.minify;
115+
if (options.clean !== undefined) output.cleanDistPath = options.clean;
116+
const externals = options.externals?.filter(Boolean) ?? [];
117+
if (externals.length > 0) output.externals = externals;
118+
if (options.distPath) {
119+
output.distPath = {
120+
...(typeof output.distPath === 'object' ? output.distPath : {}),
121+
root: options.distPath,
122+
};
123+
}
124+
}
125+
};
126+
127+
export async function initConfig(options: CommonOptions): Promise<{
128+
config: RslibConfig;
129+
configFilePath: string;
130+
watchFiles: string[];
131+
}> {
132+
const cwd = process.cwd();
133+
const root = options.root ? getAbsolutePath(cwd, options.root) : cwd;
134+
const envs = loadEnv({
135+
cwd: getEnvDir(root, options.envDir),
136+
mode: options.envMode,
137+
});
138+
139+
onBeforeRestart(envs.cleanup);
140+
141+
const { content: config, filePath: configFilePath } = await loadConfig({
142+
cwd: root,
143+
path: options.config,
144+
envMode: options.envMode,
145+
loader: options.configLoader,
146+
});
147+
148+
config.source ||= {};
149+
config.source.define = {
150+
...envs.publicVars,
151+
...config.source.define,
152+
};
153+
154+
applyCliOptions(config, options, root);
155+
156+
logger.debug('Rslib config used to generate Rsbuild environments:');
157+
logger.debug(`\n${util.inspect(config, { depth: null, colors: true })}`);
158+
159+
return {
160+
config,
161+
configFilePath,
162+
watchFiles: [configFilePath, ...envs.filePaths],
163+
};
164+
}

0 commit comments

Comments
 (0)