From 7456c535a8c7e82532d84084b4185aaa4da361b8 Mon Sep 17 00:00:00 2001 From: fi3ework Date: Fri, 17 Oct 2025 16:09:13 +0800 Subject: [PATCH 1/3] feat: support build without config file --- packages/core/src/cli/initConfig.ts | 31 +++++++++++++------ packages/core/src/config.ts | 18 ++++++++--- tests/integration/cli/build/build.test.ts | 19 ++++++++---- .../cli/build/no-config/src/index.ts | 2 +- website/docs/en/guide/basic/cli.mdx | 4 +++ website/docs/zh/guide/basic/cli.mdx | 4 +++ 6 files changed, 57 insertions(+), 21 deletions(-) diff --git a/packages/core/src/cli/initConfig.ts b/packages/core/src/cli/initConfig.ts index db197cdd2..11881f905 100644 --- a/packages/core/src/cli/initConfig.ts +++ b/packages/core/src/cli/initConfig.ts @@ -2,7 +2,11 @@ import path from 'node:path'; import util from 'node:util'; import { loadEnv, type RsbuildEntry } from '@rsbuild/core'; import { loadConfig } from '../config'; -import type { RsbuildConfigOutputTarget, RslibConfig } from '../types'; +import type { + LibConfig, + RsbuildConfigOutputTarget, + RslibConfig, +} from '../types'; import { getAbsolutePath } from '../utils/helper'; import { logger } from '../utils/logger'; import type { BuildOptions, CommonOptions } from './commands'; @@ -85,16 +89,16 @@ export const applyCliOptions = ( lib.autoExtension = options.autoExtension; if (options.autoExternal !== undefined) lib.autoExternal = options.autoExternal; - const output = lib.output ?? {}; + lib.output ??= {}; if (options.target !== undefined) - output.target = options.target as RsbuildConfigOutputTarget; - if (options.minify !== undefined) output.minify = options.minify; - if (options.clean !== undefined) output.cleanDistPath = options.clean; + lib.output.target = options.target as RsbuildConfigOutputTarget; + if (options.minify !== undefined) lib.output.minify = options.minify; + if (options.clean !== undefined) lib.output.cleanDistPath = options.clean; const externals = options.externals?.filter(Boolean) ?? []; - if (externals.length > 0) output.externals = externals; + if (externals.length > 0) lib.output.externals = externals; if (options.distPath) { - output.distPath = { - ...(typeof output.distPath === 'object' ? output.distPath : {}), + lib.output.distPath = { + ...(typeof lib.output.distPath === 'object' ? lib.output.distPath : {}), root: options.distPath, }; } @@ -103,7 +107,7 @@ export const applyCliOptions = ( export async function initConfig(options: CommonOptions): Promise<{ config: RslibConfig; - configFilePath: string; + configFilePath?: string; watchFiles: string[]; }> { const cwd = process.cwd(); @@ -122,6 +126,13 @@ export async function initConfig(options: CommonOptions): Promise<{ loader: options.configLoader, }); + if (configFilePath === undefined) { + config.lib = [{} satisfies LibConfig]; + logger.debug( + 'No config file found. Falling back to CLI options for the default library.', + ); + } + config.source ||= {}; config.source.define = { ...envs.publicVars, @@ -136,6 +147,6 @@ export async function initConfig(options: CommonOptions): Promise<{ return { config, configFilePath, - watchFiles: [configFilePath, ...envs.filePaths], + watchFiles: [configFilePath, ...envs.filePaths].filter(Boolean) as string[], }; } diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index ef3fc1817..b309abc03 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -99,7 +99,10 @@ const findConfig = (basePath: string): string | undefined => { ); }; -const resolveConfigPath = (root: string, customConfig?: string): string => { +const resolveConfigPath = ( + root: string, + customConfig?: string, +): string | undefined => { if (customConfig) { const customConfigPath = isAbsolute(customConfig) ? customConfig @@ -115,8 +118,7 @@ const resolveConfigPath = (root: string, customConfig?: string): string => { if (configFilePath) { return configFilePath; } - - throw new Error(`${DEFAULT_CONFIG_NAME} not found in ${root}`); + return undefined; }; export type ConfigLoader = 'auto' | 'jiti' | 'native'; @@ -133,9 +135,17 @@ export async function loadConfig({ loader?: ConfigLoader; }): Promise<{ content: RslibConfig; - filePath: string; + filePath?: string; }> { const configFilePath = resolveConfigPath(cwd, path); + if (!configFilePath) { + return { + content: { + lib: [], + }, + filePath: undefined, + }; + } const { content } = await loadRsbuildConfig({ cwd: dirname(configFilePath), path: configFilePath, diff --git a/tests/integration/cli/build/build.test.ts b/tests/integration/cli/build/build.test.ts index 9c786a55a..1f3be98f5 100644 --- a/tests/integration/cli/build/build.test.ts +++ b/tests/integration/cli/build/build.test.ts @@ -142,15 +142,22 @@ describe('build command', async () => { `); }); - test('should throw error if config file is absent, but it should work if the future', async () => { + test('should build when config file is absent', async () => { const fixturePath = path.join(__dirname, 'no-config'); await fse.remove(path.join(fixturePath, 'dist')); - expect(() => - runCliSync('build --format cjs', { - cwd: fixturePath, - }), - ).toThrowError(/rslib\.config not found in.*cli[\\/]build[\\/]no-config/); + runCliSync('build --dist-path=dist/a --syntax=es2015', { + cwd: fixturePath, + }); + + const files = await globContentJSON(path.join(fixturePath, 'dist')); + expect(files).toMatchInlineSnapshot(` + { + "/tests/integration/cli/build/no-config/dist/a/index.js": "const withoutConfig = 1000; + export { withoutConfig }; + ", + } + `); }); test('build options', async () => { diff --git a/tests/integration/cli/build/no-config/src/index.ts b/tests/integration/cli/build/no-config/src/index.ts index 68a0993f6..36e685774 100644 --- a/tests/integration/cli/build/no-config/src/index.ts +++ b/tests/integration/cli/build/no-config/src/index.ts @@ -1 +1 @@ -export const withoutConfig = 'works'; +export const withoutConfig = 1_000; diff --git a/website/docs/en/guide/basic/cli.mdx b/website/docs/en/guide/basic/cli.mdx index 38b22586e..58833454b 100644 --- a/website/docs/en/guide/basic/cli.mdx +++ b/website/docs/en/guide/basic/cli.mdx @@ -62,6 +62,10 @@ Options: --tsconfig use specific tsconfig (relative to project root) ``` +:::note +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. +::: + ### Environment variables 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). diff --git a/website/docs/zh/guide/basic/cli.mdx b/website/docs/zh/guide/basic/cli.mdx index e30f087e2..e27cd44e2 100644 --- a/website/docs/zh/guide/basic/cli.mdx +++ b/website/docs/zh/guide/basic/cli.mdx @@ -62,6 +62,10 @@ Options: --tsconfig 使用指定的 tsconfig(相对于项目根目录) ``` +:::note +如果项目中不存在 `rslib.config.*` 文件,CLI 会退回到仅包含单个 [lib](/config/lib/) 的默认配置,并按照命令行参数执行构建。一旦需要更复杂的配置或多库产物,再补充配置文件即可。 +::: + ### 环境变量 Rslib 支持在构建过程中向代码中注入环境变量或表达式,这对于区分运行环境、替换常量值等场景很有帮助。你可以查看 [Rsbuild - 环境变量](https://rsbuild.rs/zh/guide/advanced/env-vars) 了解更多详细信息。 From 31e498eb57eeda409fec9c9fae083ed712719000 Mon Sep 17 00:00:00 2001 From: Timeless0911 <50201324+Timeless0911@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:19:55 +0800 Subject: [PATCH 2/3] Update website/docs/en/guide/basic/cli.mdx --- website/docs/en/guide/basic/cli.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/en/guide/basic/cli.mdx b/website/docs/en/guide/basic/cli.mdx index 58833454b..af3a55056 100644 --- a/website/docs/en/guide/basic/cli.mdx +++ b/website/docs/en/guide/basic/cli.mdx @@ -63,7 +63,7 @@ Options: ``` :::note -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. +If the [Rslib configuration file](/guide/basic/configure-rslib#configuration-file) is not present in your project, the CLI will automatically use the default configuration containing only a single [lib](/config/lib/) and apply all build options from the command line. You can add a configuration file once you need a more complex configuration or want to build outputs in multiple formats. ::: ### Environment variables From d77978c31a01d3fdf1e8e55cf3049b68bedacd56 Mon Sep 17 00:00:00 2001 From: Timeless0911 <50201324+Timeless0911@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:20:07 +0800 Subject: [PATCH 3/3] Update website/docs/zh/guide/basic/cli.mdx --- website/docs/zh/guide/basic/cli.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/zh/guide/basic/cli.mdx b/website/docs/zh/guide/basic/cli.mdx index e27cd44e2..adc91c49d 100644 --- a/website/docs/zh/guide/basic/cli.mdx +++ b/website/docs/zh/guide/basic/cli.mdx @@ -63,7 +63,7 @@ Options: ``` :::note -如果项目中不存在 `rslib.config.*` 文件,CLI 会退回到仅包含单个 [lib](/config/lib/) 的默认配置,并按照命令行参数执行构建。一旦需要更复杂的配置或多库产物,再补充配置文件即可。 +如果项目中不存在 Rslib [配置文件](/guide/basic/configure-rslib#配置文件),CLI 将自动使用仅包含单个 [lib](/config/lib/) 的默认配置,并根据命令行参数完成构建。当需要更复杂的配置或构建多种格式的产物时,再补充配置文件即可。 ::: ### 环境变量