From 3a17836970220712a8a60959c992c1d76b59d784 Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 22 Aug 2026 09:40:50 +0800 Subject: [PATCH 1/3] perf(rstack): load config once during rs check --- packages/rstack/src/cli/commands.ts | 24 +++++++++++++++++------- packages/rstack/src/fmt/cli.ts | 22 +++++++++++++++++----- packages/rstack/src/rslintConfig.ts | 7 +++++-- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/packages/rstack/src/cli/commands.ts b/packages/rstack/src/cli/commands.ts index 4368dbea..c4dadaa7 100644 --- a/packages/rstack/src/cli/commands.ts +++ b/packages/rstack/src/cli/commands.ts @@ -1,5 +1,6 @@ import { join, resolve } from 'node:path'; -import { getConfigState } from '../config.ts'; +import { pathToFileURL } from 'node:url'; +import { getConfigState, type LoadedRstackConfig } from '../config.ts'; import { insertConfigArg, parseArgs, parseCliArgs } from './args.ts'; import { hasHelpFlag, printCommandHelp } from './help.ts'; @@ -138,6 +139,8 @@ async function runRspressCLI(args: string[]): Promise { } } +const RSLINT_CONFIG_PATH = join(import.meta.dirname, 'rslintConfig.js'); + async function runRslintCLI(args: string[]): Promise { if (hasHelpFlag(args)) { return printCommandHelp('lint'); @@ -146,17 +149,23 @@ async function runRslintCLI(args: string[]): Promise { const argv = [ process.execPath, 'rslint', - ...insertConfigArg( - args, - '--config', - join(import.meta.dirname, 'rslintConfig.js'), - ), + ...insertConfigArg(args, '--config', RSLINT_CONFIG_PATH), ]; const { runCLI } = await import('@rslint/core'); await runCLI({ argv }); } +const getLoadedRslintRstackConfig = async (): Promise => { + // Rslint loads its one-shot config through Node's module cache. Import the + // same URL to read the Rstack config exported for the following fmt phase. + const configModule = (await import( + pathToFileURL(RSLINT_CONFIG_PATH).href + )) as typeof import('../rslintConfig.ts'); + + return configModule.loadedConfig; +}; + async function runCheckCLI(args: string[]): Promise { const { values } = parseArgs({ args, @@ -177,11 +186,12 @@ async function runCheckCLI(args: string[]): Promise { return; } + const loadedConfig = await getLoadedRslintRstackConfig(); const { runFmtCLI } = await import( /* rspackChunkName: 'fmt' */ '../fmt/cli.ts' ); - await runFmtCLI(['--check']); + await runFmtCLI(['--check'], { loadedConfig }); } export async function setupCommands(): Promise { diff --git a/packages/rstack/src/fmt/cli.ts b/packages/rstack/src/fmt/cli.ts index 7b13f498..0eb4e626 100644 --- a/packages/rstack/src/fmt/cli.ts +++ b/packages/rstack/src/fmt/cli.ts @@ -3,7 +3,7 @@ import { performance } from 'node:perf_hooks'; import { color, logger } from 'rslog'; import { parseArgs } from '../cli/args.ts'; import { printCommandHelp } from '../cli/help.ts'; -import { loadRstackConfig } from '../config.ts'; +import { loadRstackConfig, type LoadedRstackConfig } from '../config.ts'; import { ensureProjectCacheDir } from '../projectCache.ts'; import { fmtCacheFileName } from './cacheStore.ts'; import { resolveFmtConfig } from './config.ts'; @@ -29,6 +29,11 @@ interface ParsedFmtCLIArgs { lsp: boolean; } +type RunFmtCLIOptions = { + /** Rstack config already loaded by the lint phase of `rs check`. */ + loadedConfig?: LoadedRstackConfig; +}; + const parseMaxWorkers = (value: string | undefined): number | undefined => { if (value === undefined) { return undefined; @@ -255,8 +260,12 @@ const logFmtResult = ( } }; -const loadFmtConfig = async (cwd: string): Promise => { - const { configs, filePath } = await loadRstackConfig({ cwd }); +const loadFmtConfig = async ( + cwd: string, + loadedConfig?: LoadedRstackConfig, +): Promise => { + const { configs, filePath } = + loadedConfig ?? (await loadRstackConfig({ cwd })); return resolveFmtConfig({ definition: configs.fmt, @@ -265,7 +274,10 @@ const loadFmtConfig = async (cwd: string): Promise => { }); }; -const runFmtCLI = async (args: string[]): Promise => { +const runFmtCLI = async ( + args: string[], + { loadedConfig }: RunFmtCLIOptions = {}, +): Promise => { const cwd = process.cwd(); const startTime = performance.now(); @@ -337,7 +349,7 @@ const runFmtCLI = async (args: string[]): Promise => { } } - const config = await loadFmtConfig(cwd); + const config = await loadFmtConfig(cwd, loadedConfig); const files = await discoverFmtFiles({ cwd, patterns, diff --git a/packages/rstack/src/rslintConfig.ts b/packages/rstack/src/rslintConfig.ts index 50f13c20..2a0cb25f 100644 --- a/packages/rstack/src/rslintConfig.ts +++ b/packages/rstack/src/rslintConfig.ts @@ -1,7 +1,10 @@ -import { loadRstackConfig } from './config.ts'; +import { loadRstackConfig, type LoadedRstackConfig } from './config.ts'; import type { RslintConfig } from '@rslint/core'; -const { configs } = await loadRstackConfig(); +// Expose the loaded config so `rs check` can pass it to fmt instead of loading +// and executing the Rstack config a second time. +export const loadedConfig: LoadedRstackConfig = await loadRstackConfig(); +const { configs } = loadedConfig; const lintDefinition = configs.lint ?? []; let lintConfig: RslintConfig; From 674807626e9d4255972b3410453fc8c286b46e05 Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 22 Aug 2026 11:41:54 +0800 Subject: [PATCH 2/3] refactor(rstack): simplify loaded config helper name --- packages/rstack/src/cli/commands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rstack/src/cli/commands.ts b/packages/rstack/src/cli/commands.ts index c4dadaa7..c2aee04c 100644 --- a/packages/rstack/src/cli/commands.ts +++ b/packages/rstack/src/cli/commands.ts @@ -156,7 +156,7 @@ async function runRslintCLI(args: string[]): Promise { await runCLI({ argv }); } -const getLoadedRslintRstackConfig = async (): Promise => { +const getLoadedConfig = async (): Promise => { // Rslint loads its one-shot config through Node's module cache. Import the // same URL to read the Rstack config exported for the following fmt phase. const configModule = (await import( @@ -186,7 +186,7 @@ async function runCheckCLI(args: string[]): Promise { return; } - const loadedConfig = await getLoadedRslintRstackConfig(); + const loadedConfig = await getLoadedConfig(); const { runFmtCLI } = await import( /* rspackChunkName: 'fmt' */ '../fmt/cli.ts' From b3536cb575ba3fc118cf74b6b308107f76e4c70e Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 22 Aug 2026 11:47:08 +0800 Subject: [PATCH 3/3] refactor(rstack): inline loaded config import --- packages/rstack/src/cli/commands.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/rstack/src/cli/commands.ts b/packages/rstack/src/cli/commands.ts index c2aee04c..891f67d5 100644 --- a/packages/rstack/src/cli/commands.ts +++ b/packages/rstack/src/cli/commands.ts @@ -1,6 +1,6 @@ import { join, resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; -import { getConfigState, type LoadedRstackConfig } from '../config.ts'; +import { getConfigState } from '../config.ts'; import { insertConfigArg, parseArgs, parseCliArgs } from './args.ts'; import { hasHelpFlag, printCommandHelp } from './help.ts'; @@ -156,16 +156,6 @@ async function runRslintCLI(args: string[]): Promise { await runCLI({ argv }); } -const getLoadedConfig = async (): Promise => { - // Rslint loads its one-shot config through Node's module cache. Import the - // same URL to read the Rstack config exported for the following fmt phase. - const configModule = (await import( - pathToFileURL(RSLINT_CONFIG_PATH).href - )) as typeof import('../rslintConfig.ts'); - - return configModule.loadedConfig; -}; - async function runCheckCLI(args: string[]): Promise { const { values } = parseArgs({ args, @@ -186,7 +176,11 @@ async function runCheckCLI(args: string[]): Promise { return; } - const loadedConfig = await getLoadedConfig(); + // Rslint loads its one-shot config through Node's module cache. Import the + // same URL to read the Rstack config exported for the following fmt phase. + const { loadedConfig } = (await import( + pathToFileURL(RSLINT_CONFIG_PATH).href + )) as typeof import('../rslintConfig.ts'); const { runFmtCLI } = await import( /* rspackChunkName: 'fmt' */ '../fmt/cli.ts'