Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions packages/rstack/src/config.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -15,6 +15,23 @@ import type { FmtConfigDefinition } from './fmt/types.ts';
import type { StagedConfig } from './staged.ts';
import { composeConfigLayers, flattenConfigLayers } from './configLayers.ts';

setJitiLoader(async () => {
const { createJiti } = await import('@rsbuild/core/jiti');

return {
createJiti: (...args: Parameters<typeof createJiti>) => {
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;

type RslintConfigFactory = (
Expand Down Expand Up @@ -254,7 +271,7 @@ export const loadRstackConfig = async ({
return getConfigSessionStorage().run(session, async () => {
try {
const { filePath, dependencies } = await loadConfig({
loader: 'native',
loader: 'auto',
Comment thread
chenjiahan marked this conversation as resolved.
Comment thread
chenjiahan marked this conversation as resolved.
exportName: false,
fresh: true,
cwd,
Expand Down
6 changes: 6 additions & 0 deletions packages/rstack/tests/config/load-config/fallback.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { define } from 'rstack';

define.extends([{ fmt: { singleQuote: true } }]);
define.lib({});

await import('./jiti.config.ts');
18 changes: 18 additions & 0 deletions packages/rstack/tests/config/load-config/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ 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 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');

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',
Expand Down
7 changes: 7 additions & 0 deletions packages/rstack/tests/config/load-config/jiti.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { define } from 'rstack';

enum Title {
App = 'jiti config',
}

define.app({ html: { title: Title.App } });
Loading