diff --git a/packages/rstack/src/config.ts b/packages/rstack/src/config.ts index 81fa02f..c086e64 100644 --- a/packages/rstack/src/config.ts +++ b/packages/rstack/src/config.ts @@ -1,3 +1,4 @@ +import { resolve } from 'node:path'; import { loadConfig } from '@rstackjs/load-config'; import type { RsbuildConfigDefinition } from '@rsbuild/core'; import type { RslibConfigDefinition } from '@rslib/core'; @@ -24,6 +25,15 @@ type LoadedRstackConfig = { dependencies: string[]; }; +type LoadRstackConfigOptions = { + /** + * The path to the Rstack config file, can be a relative or absolute path. + * If `configFilePath` is not provided, the config path set by the CLI is used. + * If neither path is provided, the function will search for the config file in the current working directory. + */ + configFilePath?: string; +}; + type ConfigState = { configs: Configs; configPath?: string; @@ -108,8 +118,11 @@ export const define: Define = { staged: (config) => setConfig('staged', config), }; -export const loadRstackConfig = async (): Promise => { +export const loadRstackConfig = async ({ + configFilePath, +}: LoadRstackConfigOptions = {}): Promise => { const state = getConfigState(); + const configPath = configFilePath ?? state.configPath; state.configs = {}; try { @@ -117,8 +130,8 @@ export const loadRstackConfig = async (): Promise => { loader: 'native', exportName: false, fresh: true, - ...(state.configPath !== undefined - ? { path: state.configPath } + ...(configPath !== undefined + ? { path: resolve(configPath) } : { configFileNames: [ 'rstack.config.ts', diff --git a/packages/rstack/tests/config/load-config/explicit-dependency.ts b/packages/rstack/tests/config/load-config/explicit-dependency.ts new file mode 100644 index 0000000..1cc9cc9 --- /dev/null +++ b/packages/rstack/tests/config/load-config/explicit-dependency.ts @@ -0,0 +1 @@ +export const title = 'explicit config works'; diff --git a/packages/rstack/tests/config/load-config/explicit.config.ts b/packages/rstack/tests/config/load-config/explicit.config.ts new file mode 100644 index 0000000..c77b982 --- /dev/null +++ b/packages/rstack/tests/config/load-config/explicit.config.ts @@ -0,0 +1,8 @@ +import { define } from 'rstack'; +import { title } from './explicit-dependency.ts'; + +define.app({ + html: { + title, + }, +}); diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts new file mode 100644 index 0000000..059fad9 --- /dev/null +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -0,0 +1,48 @@ +import path from 'node:path'; +import { afterEach, expect, test } from 'rstack/test'; +import { getConfigState, loadRstackConfig } from '../../../src/config.ts'; + +const state = getConfigState(); + +afterEach(() => { + state.configs = {}; + delete state.configPath; +}); + +test('should reset config state before and after loading', async () => { + state.configs = { app: {} }; + state.configPath = path.join(import.meta.dirname, 'rstack.config.ts'); + + await expect(loadRstackConfig()).rejects.toThrow('test config error'); + expect(state.configs).toEqual({}); +}); + +test('should load an explicit config path before the legacy state path', async () => { + const configFilePath = path.join(import.meta.dirname, 'explicit.config.ts'); + const dependencyPath = path.join(import.meta.dirname, 'explicit-dependency.ts'); + const relativeConfigPath = path.relative(process.cwd(), configFilePath); + state.configPath = path.join(import.meta.dirname, 'rstack.config.ts'); + + const loaded = await loadRstackConfig({ + configFilePath: relativeConfigPath, + }); + + expect(loaded.configs.app).toEqual({ + html: { + title: 'explicit config works', + }, + }); + expect(loaded.filePath).toBe(configFilePath); + expect(loaded.dependencies).toEqual([dependencyPath]); + expect(state.configs).toEqual({}); +}); + +test('should report the resolved path when an explicit config is missing', async () => { + const configFilePath = path.join(import.meta.dirname, 'missing.config.ts'); + state.configs = { app: {} }; + + await expect(loadRstackConfig({ configFilePath })).rejects.toThrow( + `Cannot find config file: ${configFilePath}`, + ); + expect(state.configs).toEqual({}); +}); diff --git a/packages/rstack/tests/config/load-state/rstack.config.ts b/packages/rstack/tests/config/load-config/rstack.config.ts similarity index 100% rename from packages/rstack/tests/config/load-state/rstack.config.ts rename to packages/rstack/tests/config/load-config/rstack.config.ts diff --git a/packages/rstack/tests/config/load-state/index.test.ts b/packages/rstack/tests/config/load-state/index.test.ts deleted file mode 100644 index 1f4e34f..0000000 --- a/packages/rstack/tests/config/load-state/index.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import path from 'node:path'; -import { expect, test } from 'rstack/test'; -import { getConfigState, loadRstackConfig } from '../../../src/config.ts'; - -test('should reset config state before and after loading', async () => { - const state = getConfigState(); - state.configs = { app: {} }; - state.configPath = path.join(import.meta.dirname, 'rstack.config.ts'); - - try { - await expect(loadRstackConfig()).rejects.toThrow('test config error'); - expect(state.configs).toEqual({}); - } finally { - state.configs = {}; - delete state.configPath; - } -});