diff --git a/docs/guide/essentials/wxt-modules.md b/docs/guide/essentials/wxt-modules.md index 9ec0c43ff..9033df6a3 100644 --- a/docs/guide/essentials/wxt-modules.md +++ b/docs/guide/essentials/wxt-modules.md @@ -75,7 +75,7 @@ import { defineWxtModule } from 'wxt/modules'; export default defineWxtModule({ setup(wxt) { - wxt.hook('ready', () => { + wxt.hook('config:resolved', () => { wxt.config.outDir = 'dist'; }); }, diff --git a/packages/wxt/e2e/tests/hooks.test.ts b/packages/wxt/e2e/tests/hooks.test.ts index e91a2209f..0f9babc80 100644 --- a/packages/wxt/e2e/tests/hooks.test.ts +++ b/packages/wxt/e2e/tests/hooks.test.ts @@ -4,6 +4,7 @@ import { WxtHooks } from '../../src/types'; const hooks: WxtHooks = { ready: vi.fn(), + 'config:resolved': vi.fn(), 'prepare:types': vi.fn(), 'prepare:publicPaths': vi.fn(), 'build:before': vi.fn(), @@ -49,6 +50,7 @@ describe('Hooks', () => { expectHooksToBeCalled({ ready: true, + 'config:resolved': true, 'prepare:types': true, 'prepare:publicPaths': true, 'build:before': false, @@ -76,6 +78,7 @@ describe('Hooks', () => { expectHooksToBeCalled({ ready: true, + 'config:resolved': true, 'prepare:types': true, 'prepare:publicPaths': true, 'build:before': true, @@ -103,6 +106,7 @@ describe('Hooks', () => { expectHooksToBeCalled({ ready: true, + 'config:resolved': true, 'prepare:types': true, 'prepare:publicPaths': true, 'build:before': true, @@ -130,6 +134,7 @@ describe('Hooks', () => { expectHooksToBeCalled({ ready: true, + 'config:resolved': true, 'prepare:types': true, 'prepare:publicPaths': true, 'build:before': true, @@ -163,6 +168,7 @@ describe('Hooks', () => { expectHooksToBeCalled({ ready: true, + 'config:resolved': true, 'prepare:types': true, 'prepare:publicPaths': true, 'build:before': true, diff --git a/packages/wxt/src/__tests__/modules.test.ts b/packages/wxt/src/__tests__/modules.test.ts index 6e0982d13..a0455d0a0 100644 --- a/packages/wxt/src/__tests__/modules.test.ts +++ b/packages/wxt/src/__tests__/modules.test.ts @@ -15,7 +15,7 @@ describe('Module Utilities', () => { wxt.config.vite = () => Promise.resolve(userConfig); addViteConfig(wxt, () => moduleConfig); - await wxt.hooks.callHook('ready', wxt); + await wxt.hooks.callHook('config:resolved', wxt); const actual = await wxt.config.vite(wxt.config.env); expect(actual).toEqual(expected); @@ -31,7 +31,7 @@ describe('Module Utilities', () => { wxt.config.vite = () => userConfig; addViteConfig(wxt, () => moduleConfig); - await wxt.hooks.callHook('ready', wxt); + await wxt.hooks.callHook('config:resolved', wxt); const actual = await wxt.config.vite(wxt.config.env); expect(actual).toEqual(expected); @@ -44,7 +44,7 @@ describe('Module Utilities', () => { const wxt = fakeWxt({ hooks: createHooks() }); addImportPreset(wxt, preset); - await wxt.hooks.callHook('ready', wxt); + await wxt.hooks.callHook('config:resolved', wxt); expect(wxt.config.imports && wxt.config.imports.presets).toContain( preset, @@ -63,7 +63,7 @@ describe('Module Utilities', () => { }); addImportPreset(wxt, preset); - await wxt.hooks.callHook('ready', wxt); + await wxt.hooks.callHook('config:resolved', wxt); expect(wxt.config.imports && wxt.config.imports.presets).toHaveLength(2); }); @@ -78,7 +78,7 @@ describe('Module Utilities', () => { }); addImportPreset(wxt, preset); - await wxt.hooks.callHook('ready', wxt); + await wxt.hooks.callHook('config:resolved', wxt); expect(wxt.config.imports).toBe(false); }); diff --git a/packages/wxt/src/builtin-modules/unimport.ts b/packages/wxt/src/builtin-modules/unimport.ts index a915e6653..df6bf351c 100644 --- a/packages/wxt/src/builtin-modules/unimport.ts +++ b/packages/wxt/src/builtin-modules/unimport.ts @@ -18,7 +18,7 @@ export default defineWxtModule({ let unimport: Unimport; // Add user module imports to config - wxt.hooks.hook('ready', () => { + wxt.hooks.hook('config:resolved', () => { const addModuleImports = (module: WxtModule) => { if (!module.imports) return; @@ -30,10 +30,10 @@ export default defineWxtModule({ wxt.config.userModules.forEach(addModuleImports); }); - // Create unimport instance AFTER "ready" so any modifications to the - // config inside "ready" are applied. + // Create unimport instance AFTER "config:resolved" so any modifications to the + // config inside "config:resolved" are applied. wxt.hooks.afterEach((event) => { - if (event.name === 'ready') { + if (event.name === 'config:resolved') { unimport = createUnimport(options); } }); diff --git a/packages/wxt/src/core/generate-wxt-dir.ts b/packages/wxt/src/core/generate-wxt-dir.ts index a96c6353f..4fe3c535c 100644 --- a/packages/wxt/src/core/generate-wxt-dir.ts +++ b/packages/wxt/src/core/generate-wxt-dir.ts @@ -177,7 +177,7 @@ declare module "wxt/browser" { message.message, ), ), - // Include a final union-based override so TS accepts valid string templates or concatinations + // Include a final union-based override so TS accepts valid string templates or concatenations // ie: browser.i18n.getMessage(`some_enum_${enumValue}`) renderGetMessageOverload( messages.map((message) => `"${message.name}"`).join(' | '), diff --git a/packages/wxt/src/core/wxt.ts b/packages/wxt/src/core/wxt.ts index a95c27ae4..5c6c5194e 100644 --- a/packages/wxt/src/core/wxt.ts +++ b/packages/wxt/src/core/wxt.ts @@ -47,6 +47,7 @@ export async function registerWxt( }, async reloadConfig() { wxt.config = await resolveConfig(inlineConfig, command); + await wxt.hooks.callHook('config:resolved', wxt); }, pm, builder, @@ -82,6 +83,7 @@ export async function registerWxt( } await wxt.hooks.callHook('ready', wxt); + await wxt.hooks.callHook('config:resolved', wxt); } /** diff --git a/packages/wxt/src/modules.ts b/packages/wxt/src/modules.ts index f96db6194..d04c9b6ff 100644 --- a/packages/wxt/src/modules.ts +++ b/packages/wxt/src/modules.ts @@ -28,7 +28,7 @@ export function defineWxtModule( /** * Adds a TS/JS file as an entrypoint to the project. This file will be bundled * along with the other entrypoints. - + * * If you're publishing the module to NPM, you should probably pre-build the * entrypoint and use `addPublicAssets` instead to copy pre-bundled assets into * the output directory. This will speed up project builds since it just has to @@ -53,7 +53,7 @@ export function defineWxtModule( * }); */ export function addEntrypoint(wxt: Wxt, entrypoint: Entrypoint): void { - wxt.hooks.hook('entrypoints:resolved', (wxt, entrypoints) => { + wxt.hooks.hook('entrypoints:resolved', (_, entrypoints) => { entrypoints.push(entrypoint); }); } @@ -106,7 +106,7 @@ export function addViteConfig( wxt: Wxt, viteConfig: (env: vite.ConfigEnv) => vite.UserConfig | undefined, ): void { - wxt.hooks.hook('ready', (wxt) => { + wxt.hooks.hook('config:resolved', (wxt) => { const userVite = wxt.config.vite; wxt.config.vite = async (env) => { const fromUser = await userVite(env); @@ -130,7 +130,7 @@ export function addViteConfig( * }); */ export function addWxtPlugin(wxt: Wxt, plugin: string): void { - wxt.hooks.hook('ready', (wxt) => { + wxt.hooks.hook('config:resolved', (wxt) => { wxt.config.plugins.push(plugin); }); } @@ -166,7 +166,7 @@ export function addImportPreset( wxt: Wxt, preset: UnimportOptions['presets'][0], ): void { - wxt.hooks.hook('ready', (wxt) => { + wxt.hooks.hook('config:resolved', (wxt) => { if (!wxt.config.imports) return; wxt.config.imports.presets ??= []; @@ -205,12 +205,13 @@ export function addImportPreset( * }); */ export function addAlias(wxt: Wxt, alias: string, path: string) { - wxt.hooks.hook('ready', (wxt) => { + wxt.hooks.hook('config:resolved', (wxt) => { const target = resolve(wxt.config.root, path); - if (wxt.config.alias[alias] != null) { + if (wxt.config.alias[alias] != null && wxt.config.alias[alias] !== target) { wxt.logger.warn( `Skipped adding alias (${alias} => ${target}) because an alias with the same name already exists: ${alias} => ${wxt.config.alias[alias]}`, ); + return; } wxt.config.alias[alias] = target; }); diff --git a/packages/wxt/src/types.ts b/packages/wxt/src/types.ts index 3ad48acfe..90da349e1 100644 --- a/packages/wxt/src/types.ts +++ b/packages/wxt/src/types.ts @@ -1100,11 +1100,15 @@ export type HookResult = Promise | void; export interface WxtHooks { /** - * Called after WXT initialization, when the WXT instance is ready to work. + * Called only one time after WXT initialization, when the WXT instance is ready to work. * @param wxt The configured WXT object - * @returns Promise */ ready: (wxt: Wxt) => HookResult; + /** + * Called whenever config is loaded or reloaded. Use this hook to modify config by modifying `wxt.config`. + * @param wxt The configured WXT object + */ + 'config:resolved': (wxt: Wxt) => HookResult; /** * Called before WXT writes .wxt/tsconfig.json and .wxt/wxt.d.ts, allowing * addition of custom references and declarations in wxt.d.ts, or directly