Skip to content

Commit 7332aad

Browse files
committed
feat: support build without config file
1 parent f274031 commit 7332aad

File tree

6 files changed

+57
-21
lines changed

6 files changed

+57
-21
lines changed

packages/core/src/cli/initConfig.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import path from 'node:path';
22
import util from 'node:util';
33
import { loadEnv, type RsbuildEntry } from '@rsbuild/core';
44
import { loadConfig } from '../config';
5-
import type { RsbuildConfigOutputTarget, RslibConfig } from '../types';
5+
import type {
6+
LibConfig,
7+
RsbuildConfigOutputTarget,
8+
RslibConfig,
9+
} from '../types';
610
import { getAbsolutePath } from '../utils/helper';
711
import { logger } from '../utils/logger';
812
import type { BuildOptions, CommonOptions } from './commands';
@@ -85,16 +89,16 @@ export const applyCliOptions = (
8589
lib.autoExtension = options.autoExtension;
8690
if (options.autoExternal !== undefined)
8791
lib.autoExternal = options.autoExternal;
88-
const output = lib.output ?? {};
92+
lib.output ??= {};
8993
if (options.target !== undefined)
90-
output.target = options.target as RsbuildConfigOutputTarget;
91-
if (options.minify !== undefined) output.minify = options.minify;
92-
if (options.clean !== undefined) output.cleanDistPath = options.clean;
94+
lib.output.target = options.target as RsbuildConfigOutputTarget;
95+
if (options.minify !== undefined) lib.output.minify = options.minify;
96+
if (options.clean !== undefined) lib.output.cleanDistPath = options.clean;
9397
const externals = options.externals?.filter(Boolean) ?? [];
94-
if (externals.length > 0) output.externals = externals;
98+
if (externals.length > 0) lib.output.externals = externals;
9599
if (options.distPath) {
96-
output.distPath = {
97-
...(typeof output.distPath === 'object' ? output.distPath : {}),
100+
lib.output.distPath = {
101+
...(typeof lib.output.distPath === 'object' ? lib.output.distPath : {}),
98102
root: options.distPath,
99103
};
100104
}
@@ -103,7 +107,7 @@ export const applyCliOptions = (
103107

104108
export async function initConfig(options: CommonOptions): Promise<{
105109
config: RslibConfig;
106-
configFilePath: string;
110+
configFilePath?: string;
107111
watchFiles: string[];
108112
}> {
109113
const cwd = process.cwd();
@@ -122,6 +126,13 @@ export async function initConfig(options: CommonOptions): Promise<{
122126
loader: options.configLoader,
123127
});
124128

129+
if (configFilePath === undefined) {
130+
config.lib = [{} as LibConfig];
131+
logger.debug(
132+
'No config file found. Falling back to CLI options for the default library.',
133+
);
134+
}
135+
125136
config.source ||= {};
126137
config.source.define = {
127138
...envs.publicVars,
@@ -136,6 +147,6 @@ export async function initConfig(options: CommonOptions): Promise<{
136147
return {
137148
config,
138149
configFilePath,
139-
watchFiles: [configFilePath, ...envs.filePaths],
150+
watchFiles: [configFilePath, ...envs.filePaths].filter(Boolean) as string[],
140151
};
141152
}

packages/core/src/config.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ const findConfig = (basePath: string): string | undefined => {
9999
);
100100
};
101101

102-
const resolveConfigPath = (root: string, customConfig?: string): string => {
102+
const resolveConfigPath = (
103+
root: string,
104+
customConfig?: string,
105+
): string | undefined => {
103106
if (customConfig) {
104107
const customConfigPath = isAbsolute(customConfig)
105108
? customConfig
@@ -115,8 +118,7 @@ const resolveConfigPath = (root: string, customConfig?: string): string => {
115118
if (configFilePath) {
116119
return configFilePath;
117120
}
118-
119-
throw new Error(`${DEFAULT_CONFIG_NAME} not found in ${root}`);
121+
return undefined;
120122
};
121123

122124
export type ConfigLoader = 'auto' | 'jiti' | 'native';
@@ -133,9 +135,17 @@ export async function loadConfig({
133135
loader?: ConfigLoader;
134136
}): Promise<{
135137
content: RslibConfig;
136-
filePath: string;
138+
filePath?: string;
137139
}> {
138140
const configFilePath = resolveConfigPath(cwd, path);
141+
if (!configFilePath) {
142+
return {
143+
content: {
144+
lib: [],
145+
},
146+
filePath: undefined,
147+
};
148+
}
139149
const { content } = await loadRsbuildConfig({
140150
cwd: dirname(configFilePath),
141151
path: configFilePath,

tests/integration/cli/build/build.test.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,22 @@ describe('build command', async () => {
142142
`);
143143
});
144144

145-
test('should throw error if config file is absent, but it should work if the future', async () => {
145+
test('should build when config file is absent', async () => {
146146
const fixturePath = path.join(__dirname, 'no-config');
147147
await fse.remove(path.join(fixturePath, 'dist'));
148148

149-
expect(() =>
150-
runCliSync('build --format cjs', {
151-
cwd: fixturePath,
152-
}),
153-
).toThrowError(/rslib\.config not found in.*cli[\\/]build[\\/]no-config/);
149+
runCliSync('build --dist-path=dist/a --syntax=es2015', {
150+
cwd: fixturePath,
151+
});
152+
153+
const files = await globContentJSON(path.join(fixturePath, 'dist'));
154+
expect(files).toMatchInlineSnapshot(`
155+
{
156+
"<ROOT>/tests/integration/cli/build/no-config/dist/a/index.js": "const withoutConfig = 1000;
157+
export { withoutConfig };
158+
",
159+
}
160+
`);
154161
});
155162

156163
test('build options', async () => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const withoutConfig = 'works';
1+
export const withoutConfig = 1_000;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ Options:
6262
--tsconfig <path> use specific tsconfig (relative to project root)
6363
```
6464

65+
:::note
66+
If the project does not provide an `rslib.config.*` file, the CLI falls back to a default single [lib](/config/lib/) configuration and applies all build options from the command line. You can still specify `--config` later once you need more complex setups.
67+
:::
68+
6569
### Environment variables
6670

6771
Rslib supports injecting environment variables or expressions into the code during the build, which is helpful for distinguishing running environments or replacing constants. You can see more details in [Rsbuild - Environment variables](https://rsbuild.rs/guide/advanced/env-vars).

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ Options:
6262
--tsconfig <path> 使用指定的 tsconfig(相对于项目根目录)
6363
```
6464

65+
:::note
66+
如果项目中不存在 `rslib.config.*` 文件,CLI 会退回到仅包含单个 [lib](/config/lib/) 的默认配置,并按照命令行参数执行构建。一旦需要更复杂的配置或多库产物,再补充配置文件即可。
67+
:::
68+
6569
### 环境变量
6670

6771
Rslib 支持在构建过程中向代码中注入环境变量或表达式,这对于区分运行环境、替换常量值等场景很有帮助。你可以查看 [Rsbuild - 环境变量](https://rsbuild.rs/zh/guide/advanced/env-vars) 了解更多详细信息。

0 commit comments

Comments
 (0)