diff --git a/.vscode/settings.json b/.vscode/settings.json index 108fe84e3..732d0ca50 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,11 +57,11 @@ "json.schemas": [ { "fileMatch": ["**/_meta.json"], - "url": "./website/node_modules/rspress/meta-json-schema.json" + "url": "./website/node_modules/@rspress/core/meta-json-schema.json" }, { "fileMatch": ["**/_nav.json"], - "url": "./website/node_modules/rspress/nav-json-schema.json" + "url": "./website/node_modules/@rspress/core/nav-json-schema.json" } ] } diff --git a/packages/core/src/cli/build.ts b/packages/core/src/cli/build.ts index 3dc4a64ea..bf95c5c1a 100644 --- a/packages/core/src/cli/build.ts +++ b/packages/core/src/cli/build.ts @@ -1,6 +1,7 @@ import { createRsbuild, type RsbuildInstance } from '@rsbuild/core'; import { composeRsbuildEnvironments, pruneEnvironments } from '../config'; import type { RslibConfig } from '../types/config'; +import { isDebug } from '../utils/logger'; import type { BuildOptions } from './commands'; import { onBeforeRestart } from './restart'; @@ -17,6 +18,7 @@ export async function build( plugins: config.plugins, dev: config.dev, server: config.server, + logLevel: isDebug() ? 'info' : config.logLevel, environments: pruneEnvironments(environments, options.lib), }, }); diff --git a/packages/core/src/cli/commands.ts b/packages/core/src/cli/commands.ts index ec551b52a..0358abe26 100644 --- a/packages/core/src/cli/commands.ts +++ b/packages/core/src/cli/commands.ts @@ -1,4 +1,4 @@ -import type { RsbuildMode } from '@rsbuild/core'; +import type { LogLevel, RsbuildMode } from '@rsbuild/core'; import cac, { type CAC } from 'cac'; import type { ConfigLoader } from '../config'; import { logger } from '../utils/logger'; @@ -15,6 +15,7 @@ export type CommonOptions = { envMode?: string; lib?: string[]; configLoader?: ConfigLoader; + logLevel?: LogLevel; }; export type BuildOptions = CommonOptions & { @@ -49,6 +50,10 @@ const applyCommonOptions = (cli: CAC) => { }, ) .option('--env-dir ', 'specify the directory to load `.env` files') + .option( + '--log-level ', + 'set the log level (info | warn | error | silent)', + ) .option( '--lib ', 'specify the library (repeatable, e.g. --lib esm --lib cjs)', diff --git a/packages/core/src/cli/init.ts b/packages/core/src/cli/init.ts index 86f4a8e16..2845675e1 100644 --- a/packages/core/src/cli/init.ts +++ b/packages/core/src/cli/init.ts @@ -44,6 +44,10 @@ export async function init(options: CommonOptions): Promise<{ config.root = root; } + if (options.logLevel) { + config.logLevel = options.logLevel; + } + return { config, configFilePath, diff --git a/packages/core/src/cli/inspect.ts b/packages/core/src/cli/inspect.ts index 789c26925..c52201b3b 100644 --- a/packages/core/src/cli/inspect.ts +++ b/packages/core/src/cli/inspect.ts @@ -1,6 +1,7 @@ import { createRsbuild, type RsbuildInstance } from '@rsbuild/core'; import { composeRsbuildEnvironments, pruneEnvironments } from '../config'; import type { RslibConfig } from '../types/config'; +import { isDebug } from '../utils/logger'; import type { InspectOptions } from './commands'; export async function inspect( @@ -16,6 +17,7 @@ export async function inspect( plugins: config.plugins, dev: config.dev, server: config.server, + logLevel: isDebug() ? 'info' : config.logLevel, environments: pruneEnvironments(environments, options.lib), }, }); diff --git a/packages/core/src/cli/mf.ts b/packages/core/src/cli/mf.ts index 2caaae57e..c8b3c3f51 100644 --- a/packages/core/src/cli/mf.ts +++ b/packages/core/src/cli/mf.ts @@ -2,6 +2,7 @@ import type { RsbuildInstance } from '@rsbuild/core'; import { createRsbuild } from '@rsbuild/core'; import { composeRsbuildEnvironments, pruneEnvironments } from '../config'; import type { RslibConfig } from '../types'; +import { isDebug } from '../utils/logger'; import type { CommonOptions } from './commands'; import { onBeforeRestart } from './restart'; @@ -53,6 +54,7 @@ async function initMFRsbuild( plugins: config.plugins, dev: config.dev, server: config.server, + logLevel: isDebug() ? 'info' : config.logLevel, environments: selectedEnvironments, }, }); diff --git a/packages/core/src/cli/prepare.ts b/packages/core/src/cli/prepare.ts index 064237fa7..644556eaf 100644 --- a/packages/core/src/cli/prepare.ts +++ b/packages/core/src/cli/prepare.ts @@ -1,4 +1,5 @@ -import { logger } from '../utils/logger'; +import type { LogLevel } from '@rsbuild/core'; +import { isDebug, logger } from '../utils/logger'; function initNodeEnv() { if (!process.env.NODE_ENV) { @@ -9,8 +10,22 @@ function initNodeEnv() { } } +// ensure log level is set before any log is printed +function setupLogLevel() { + const logLevelIndex = process.argv.findIndex( + (item) => item === '--log-level' || item === '--logLevel', + ); + if (logLevelIndex !== -1) { + const level = process.argv[logLevelIndex + 1]; + if (level && ['warn', 'error', 'silent'].includes(level) && !isDebug()) { + logger.level = level as LogLevel; + } + } +} + export function prepareCli(): void { initNodeEnv(); + setupLogLevel(); // Print a blank line to keep the greet log nice. // Some package managers automatically output a blank line, some do not. @@ -20,7 +35,7 @@ export function prepareCli(): void { npm_execpath.includes('npx-cli.js') || npm_execpath.includes('.bun') ) { - console.log(); + logger.log(); } logger.greet(` Rslib v${RSLIB_VERSION}\n`); diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 1140195f1..4f7b0bdfb 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -73,7 +73,7 @@ import { pick, readPackageJson, } from './utils/helper'; -import { logger } from './utils/logger'; +import { isDebug, logger } from './utils/logger'; import { ESX_TO_BROWSERSLIST, transformSyntaxToBrowserslist, @@ -1804,8 +1804,13 @@ export async function composeCreateRsbuildConfig( plugins: sharedPlugins, dev: _dev, server: _server, + logLevel, ...sharedRsbuildConfig } = rslibConfig; + // debug mode should always verbose logs + if (logLevel && !isDebug()) { + logger.level = logLevel; + } if (!Array.isArray(libConfigsArray) || libConfigsArray.length === 0) { throw new Error( diff --git a/packages/core/src/utils/logger.ts b/packages/core/src/utils/logger.ts index b6e9b3fbf..5814ffd04 100644 --- a/packages/core/src/utils/logger.ts +++ b/packages/core/src/utils/logger.ts @@ -21,7 +21,9 @@ export const isDebug = (): boolean => { } const values = process.env.DEBUG.toLocaleLowerCase().split(','); - return ['rslib', 'rs*', 'rstack', '*'].some((key) => values.includes(key)); + return ['rslib', 'rsbuild', 'rs*', 'rstack', '*'].some((key) => + values.includes(key), + ); }; // setup the logger level diff --git a/packages/core/tests/__snapshots__/config.test.ts.snap b/packages/core/tests/__snapshots__/config.test.ts.snap index 777737d91..1689d7f39 100644 --- a/packages/core/tests/__snapshots__/config.test.ts.snap +++ b/packages/core/tests/__snapshots__/config.test.ts.snap @@ -287,7 +287,8 @@ exports[`Should compose create Rsbuild config correctly > Merge Rsbuild config i name: 'rsbuild:nonce', setup() {} } - ] + ], + logLevel: undefined }" `; diff --git a/packages/plugin-dts/src/dts.ts b/packages/plugin-dts/src/dts.ts index 028757672..68f2714da 100644 --- a/packages/plugin-dts/src/dts.ts +++ b/packages/plugin-dts/src/dts.ts @@ -136,7 +136,10 @@ export async function generateDts(data: DtsGenOptions): Promise { extension: false, }, tsgo, + loggerLevel, } = data; + logger.level = loggerLevel; + if (!isWatch) { logger.start(`generating declaration files... ${color.dim(`(${name})`)}`); } diff --git a/packages/plugin-dts/src/index.ts b/packages/plugin-dts/src/index.ts index 757d1d9a9..d02d0ab64 100644 --- a/packages/plugin-dts/src/index.ts +++ b/packages/plugin-dts/src/index.ts @@ -1,7 +1,12 @@ import { type ChildProcess, fork } from 'node:child_process'; import { dirname, extname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { logger, type RsbuildConfig, type RsbuildPlugin } from '@rsbuild/core'; +import { + type LogLevel, + logger, + type RsbuildConfig, + type RsbuildPlugin, +} from '@rsbuild/core'; import color from 'picocolors'; import type { ParsedCommandLine } from 'typescript'; @@ -66,6 +71,7 @@ export type DtsGenOptions = Omit & { tsConfigResult: ParsedCommandLine; userExternals?: NonNullable['externals']; apiExtractorOptions?: ApiExtractorOptions; + loggerLevel: LogLevel; }; interface TaskResult { @@ -81,6 +87,9 @@ export const pluginDts = (options: PluginDtsOptions = {}): RsbuildPlugin => ({ name: PLUGIN_DTS_NAME, setup(api) { + const loggerLevel = api.logger.level; + logger.level = loggerLevel; + let apiExtractorOptions = {}; if (options.bundle && typeof options.bundle === 'object') { @@ -179,6 +188,7 @@ export const pluginDts = (options: PluginDtsOptions = {}): RsbuildPlugin => ({ name: environment.name, cwd, isWatch, + loggerLevel: loggerLevel as LogLevel, }; childProcess.send(dtsGenOptions); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddc971b24..af21a1537 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -699,6 +699,8 @@ importers: tests/integration/cli/inspect: {} + tests/integration/cli/log-level: {} + tests/integration/cli/mf/build: {} tests/integration/cli/mf/dev: {} diff --git a/tests/integration/cli/log-level/index.test.ts b/tests/integration/cli/log-level/index.test.ts new file mode 100644 index 000000000..7d37d7c77 --- /dev/null +++ b/tests/integration/cli/log-level/index.test.ts @@ -0,0 +1,42 @@ +import { describe } from 'node:test'; +import { stripVTControlCharacters as stripAnsi } from 'node:util'; +import { expect, test } from '@rstest/core'; +import { runCliSync } from 'test-helper'; + +describe('log level', async () => { + test('should run build command with log level: info', async () => { + const stdout = stripAnsi( + runCliSync('build --log-level info', { + cwd: __dirname, + }).toString(), + ); + expect(stdout).toContain('Rslib v'); + expect(stdout).toContain('build started...'); + expect(stdout).toContain('built in'); + }); + + test('should run build command with log level: warn', async () => { + const stdout = stripAnsi( + runCliSync('build --log-level warn', { + cwd: __dirname, + }).toString(), + ); + expect(stdout).not.toContain('Rslib v'); + expect(stdout).not.toContain('build started...'); + expect(stdout).not.toContain('built in'); + }); + + test('should always print verbose logs when debug mode is enabled', async () => { + const stdout = stripAnsi( + runCliSync('build --log-level warn', { + cwd: __dirname, + env: { + ...process.env, + DEBUG: 'rsbuild', + }, + }).toString(), + ); + expect(stdout).toContain('creating compiler'); + expect(stdout).toContain('config inspection completed'); + }); +}); diff --git a/tests/integration/cli/log-level/package.json b/tests/integration/cli/log-level/package.json new file mode 100644 index 000000000..ef984de26 --- /dev/null +++ b/tests/integration/cli/log-level/package.json @@ -0,0 +1,6 @@ +{ + "name": "cli-log-level-test", + "version": "1.0.0", + "private": true, + "type": "module" +} diff --git a/tests/integration/cli/log-level/rslib.config.ts b/tests/integration/cli/log-level/rslib.config.ts new file mode 100644 index 000000000..a1b1d8104 --- /dev/null +++ b/tests/integration/cli/log-level/rslib.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from '@rslib/core'; +import { generateBundleEsmConfig } from 'test-helper'; + +export default defineConfig({ + lib: [generateBundleEsmConfig()], +}); diff --git a/tests/integration/cli/log-level/src/index.ts b/tests/integration/cli/log-level/src/index.ts new file mode 100644 index 000000000..3329a7d97 --- /dev/null +++ b/tests/integration/cli/log-level/src/index.ts @@ -0,0 +1 @@ +export const foo = 'foo'; diff --git a/website/docs/en/config/rsbuild/_meta.json b/website/docs/en/config/rsbuild/_meta.json index 5c06549da..238d78036 100644 --- a/website/docs/en/config/rsbuild/_meta.json +++ b/website/docs/en/config/rsbuild/_meta.json @@ -1,4 +1,9 @@ [ + { + "type": "file", + "name": "log-level", + "label": "logLevel" + }, "resolve", "source", "output", diff --git a/website/docs/en/config/rsbuild/index.mdx b/website/docs/en/config/rsbuild/index.mdx index c31f585e5..6683c4acd 100644 --- a/website/docs/en/config/rsbuild/index.mdx +++ b/website/docs/en/config/rsbuild/index.mdx @@ -1,5 +1,4 @@ import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; -import { Overview } from 'rspress/theme'; # Rsbuild configurations @@ -11,6 +10,7 @@ To learn more about Rslib configurations, check out [Configure Rslib](/guide/bas ## Overview +- [logLevel](/config/rsbuild/log-level): Specify the log level. - [resolve](/config/rsbuild/resolve): Options for module resolution. - [source](/config/rsbuild/source): Options for input source code. - [output](/config/rsbuild/output): Options for build outputs. diff --git a/website/docs/en/config/rsbuild/log-level.mdx b/website/docs/en/config/rsbuild/log-level.mdx new file mode 100644 index 000000000..093dc7725 --- /dev/null +++ b/website/docs/en/config/rsbuild/log-level.mdx @@ -0,0 +1,8 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# logLevel + +- **Type:** `'info' | 'warn' | 'error' | 'silent'` +- **Default:** `'info'` + +Specify the log level, the default value is `info`. diff --git a/website/docs/en/guide/basic/cli.mdx b/website/docs/en/guide/basic/cli.mdx index d620e69c6..315d42d87 100644 --- a/website/docs/en/guide/basic/cli.mdx +++ b/website/docs/en/guide/basic/cli.mdx @@ -34,6 +34,7 @@ Rslib CLI provides several common flags that can be used with all commands: | `--env-mode ` | Specify the env mode to load the `.env.[mode]` file, see [Rsbuild - Env mode](https://rsbuild.rs/guide/advanced/env-vars#env-mode) | | `-h, --help` | Display help for command | | `--lib ` | Specify the library to run commands (repeatable, e.g. `--lib esm --lib cjs`), see [lib.id](/config/lib/id) to learn how to get or set the ID of the library | +| `--log-level ` | Set the log level (`info` \| `warn` \| `error` \| `silent`), see [logLevel](/config/rsbuild/log-level) | | `-r, --root ` | Specify the project root directory, can be an absolute path or a path relative to cwd | ## rslib build diff --git a/website/docs/zh/config/rsbuild/_meta.json b/website/docs/zh/config/rsbuild/_meta.json index 5c06549da..238d78036 100644 --- a/website/docs/zh/config/rsbuild/_meta.json +++ b/website/docs/zh/config/rsbuild/_meta.json @@ -1,4 +1,9 @@ [ + { + "type": "file", + "name": "log-level", + "label": "logLevel" + }, "resolve", "source", "output", diff --git a/website/docs/zh/config/rsbuild/index.mdx b/website/docs/zh/config/rsbuild/index.mdx index 6bcb06599..51dab9fe5 100644 --- a/website/docs/zh/config/rsbuild/index.mdx +++ b/website/docs/zh/config/rsbuild/index.mdx @@ -10,6 +10,7 @@ Rslib 继承了 Rsbuild 的配置,所以你也可以配置 + +- **类型:** `'info' | 'warn' | 'error' | 'silent'` +- **默认值:** `'info'` + +指定日志级别,默认值为 `info`。 diff --git a/website/docs/zh/guide/basic/cli.mdx b/website/docs/zh/guide/basic/cli.mdx index ca51046df..341047a06 100644 --- a/website/docs/zh/guide/basic/cli.mdx +++ b/website/docs/zh/guide/basic/cli.mdx @@ -34,6 +34,7 @@ Rslib CLI 提供了一些公共选项,可以用于所有命令: | `--env-mode ` | 指定 env 模式来加载 `.env.[mode]` 文件,详见 [Rsbuild - Env 模式](https://rsbuild.rs/zh/guide/advanced/env-vars#env-模式) | | `-h, --help` | 显示命令帮助 | | `--lib ` | 指定运行命令的库(可重复,例如:`--lib esm --lib cjs`),查看 [lib.id](/config/lib/id) 了解如何获取或设置库的 ID | +| `--log-level ` | 指定日志级别(`info` \| `warn` \| `error` \| `silent`),详见 [logLevel](/config/rsbuild/log-level) | | `-r, --root ` | 指定项目根目录,可以是绝对路径或者相对于 cwd 的路径 | ## rslib build