From 94546924b8e2868763cd91133931cc43c235043d Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 13 Oct 2026 19:14:04 +0800 Subject: [PATCH 1/3] feat: use auto config loader with bundled jiti --- packages/rstack/src/config.ts | 6 ++++-- packages/rstack/tests/config/load-config/index.test.ts | 6 ++++++ packages/rstack/tests/config/load-config/jiti.config.ts | 7 +++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 packages/rstack/tests/config/load-config/jiti.config.ts diff --git a/packages/rstack/src/config.ts b/packages/rstack/src/config.ts index f806237f..84a3540c 100644 --- a/packages/rstack/src/config.ts +++ b/packages/rstack/src/config.ts @@ -1,5 +1,5 @@ import { AsyncLocalStorage } from 'node:async_hooks'; -import { loadConfig } from '@rstackjs/load-config'; +import { loadConfig, setJitiLoader } from '@rstackjs/load-config'; import type { defineConfig as defineAppConfig, RsbuildConfigDefinition, @@ -15,6 +15,8 @@ import type { FmtConfigDefinition } from './fmt/types.ts'; import type { StagedConfig } from './staged.ts'; import { composeConfigLayers, flattenConfigLayers } from './configLayers.ts'; +setJitiLoader(() => import('@rsbuild/core/jiti')); + export type RspressConfigDefinition = UserConfig | UserConfigAsyncFn; type RslintConfigFactory = ( @@ -254,7 +256,7 @@ export const loadRstackConfig = async ({ return getConfigSessionStorage().run(session, async () => { try { const { filePath, dependencies } = await loadConfig({ - loader: 'native', + loader: 'auto', exportName: false, fresh: true, cwd, diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts index b6ec8f01..446ce556 100644 --- a/packages/rstack/tests/config/load-config/index.test.ts +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -58,6 +58,12 @@ test('should prefer an explicit config path over the state config path', async ( expect(filePath).toBe(explicitConfigPath); }); +test('should fall back to jiti for TypeScript syntax unsupported by the native loader', async () => { + const { configs } = await loadConfigFile('jiti.config.ts'); + + expect(configs.app).toEqual({ html: { title: 'jiti config' } }); +}); + test('should resolve a relative explicit config path from cwd', async () => { const { configs, filePath } = await loadRstackConfig({ configFilePath: 'explicit.config.ts', diff --git a/packages/rstack/tests/config/load-config/jiti.config.ts b/packages/rstack/tests/config/load-config/jiti.config.ts new file mode 100644 index 00000000..5762e944 --- /dev/null +++ b/packages/rstack/tests/config/load-config/jiti.config.ts @@ -0,0 +1,7 @@ +import { define } from 'rstack'; + +enum Title { + App = 'jiti config', +} + +define.app({ html: { title: Title.App } }); From 0cc8e0b18128e8e171194a45e6b38e6a0c71f9b9 Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 13 Oct 2026 21:20:18 +0800 Subject: [PATCH 2/3] fix: clear partial config definitions before jiti fallback --- packages/rstack/src/config.ts | 17 ++++++++++++++++- .../tests/config/load-config/fallback.config.ts | 6 ++++++ .../tests/config/load-config/index.test.ts | 12 ++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 packages/rstack/tests/config/load-config/fallback.config.ts diff --git a/packages/rstack/src/config.ts b/packages/rstack/src/config.ts index 84a3540c..e6c2ceb0 100644 --- a/packages/rstack/src/config.ts +++ b/packages/rstack/src/config.ts @@ -15,7 +15,22 @@ import type { FmtConfigDefinition } from './fmt/types.ts'; import type { StagedConfig } from './staged.ts'; import { composeConfigLayers, flattenConfigLayers } from './configLayers.ts'; -setJitiLoader(() => import('@rsbuild/core/jiti')); +setJitiLoader(async () => { + const { createJiti } = await import('@rsbuild/core/jiti'); + + return { + createJiti: (...args: Parameters) => { + const session = getConfigSessionStorage().getStore(); + if (session?.active) { + // A native attempt may have registered configs before falling back. + // Reset per attempt, since the jiti importer itself is cached. + session.configs = {}; + session.extends = undefined; + } + return createJiti(...args); + }, + }; +}); export type RspressConfigDefinition = UserConfig | UserConfigAsyncFn; diff --git a/packages/rstack/tests/config/load-config/fallback.config.ts b/packages/rstack/tests/config/load-config/fallback.config.ts new file mode 100644 index 00000000..d2477808 --- /dev/null +++ b/packages/rstack/tests/config/load-config/fallback.config.ts @@ -0,0 +1,6 @@ +import { define } from 'rstack'; + +define.extends([{ fmt: { singleQuote: true } }]); +define.lib({}); + +await import('./jiti.config.ts'); diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts index 446ce556..0171a172 100644 --- a/packages/rstack/tests/config/load-config/index.test.ts +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -64,6 +64,18 @@ test('should fall back to jiti for TypeScript syntax unsupported by the native l expect(configs.app).toEqual({ html: { title: 'jiti config' } }); }); +test('should discard partial definitions before each jiti fallback', async () => { + for (let attempt = 0; attempt < 2; attempt++) { + const { configs } = await loadConfigFile('fallback.config.ts'); + + expect(configs).toEqual({ + app: { html: { title: 'jiti config' } }, + lib: {}, + fmt: { singleQuote: true }, + }); + } +}); + test('should resolve a relative explicit config path from cwd', async () => { const { configs, filePath } = await loadRstackConfig({ configFilePath: 'explicit.config.ts', From f930d78a0c746050cc96fd35cb1e21e8014f97cd Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 13 Oct 2026 21:33:18 +0800 Subject: [PATCH 3/3] test: clarify repeated jiti fallback test title --- packages/rstack/tests/config/load-config/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts index 0171a172..2f7c5da7 100644 --- a/packages/rstack/tests/config/load-config/index.test.ts +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -64,7 +64,7 @@ test('should fall back to jiti for TypeScript syntax unsupported by the native l expect(configs.app).toEqual({ html: { title: 'jiti config' } }); }); -test('should discard partial definitions before each jiti fallback', async () => { +test('should avoid duplicate definitions when falling back to jiti across repeated loads', async () => { for (let attempt = 0; attempt < 2; attempt++) { const { configs } = await loadConfigFile('fallback.config.ts');