diff --git a/docs/assets/init-demo.gif b/docs/assets/init-demo.gif index dda435d4..474db34c 100644 Binary files a/docs/assets/init-demo.gif and b/docs/assets/init-demo.gif differ diff --git a/packages/wxt/e2e/tests/hooks.test.ts b/packages/wxt/e2e/tests/hooks.test.ts index a00b986a..e91a2209 100644 --- a/packages/wxt/e2e/tests/hooks.test.ts +++ b/packages/wxt/e2e/tests/hooks.test.ts @@ -14,6 +14,12 @@ const hooks: WxtHooks = { 'entrypoints:grouped': vi.fn(), 'vite:build:extendConfig': vi.fn(), 'vite:devServer:extendConfig': vi.fn(), + 'zip:start': vi.fn(), + 'zip:extension:start': vi.fn(), + 'zip:extension:done': vi.fn(), + 'zip:sources:start': vi.fn(), + 'zip:sources:done': vi.fn(), + 'zip:done': vi.fn(), }; function expectHooksToBeCalled( @@ -53,6 +59,12 @@ describe('Hooks', () => { 'entrypoints:resolved': true, 'vite:build:extendConfig': false, 'vite:devServer:extendConfig': false, + 'zip:start': false, + 'zip:extension:start': false, + 'zip:extension:done': false, + 'zip:sources:start': false, + 'zip:sources:done': false, + 'zip:done': false, }); }); @@ -74,6 +86,12 @@ describe('Hooks', () => { 'entrypoints:resolved': true, 'vite:build:extendConfig': 1, 'vite:devServer:extendConfig': false, + 'zip:start': false, + 'zip:extension:start': false, + 'zip:extension:done': false, + 'zip:sources:start': false, + 'zip:sources:done': false, + 'zip:done': false, }); }); @@ -95,6 +113,39 @@ describe('Hooks', () => { 'entrypoints:resolved': true, 'vite:build:extendConfig': 1, 'vite:devServer:extendConfig': false, + 'zip:start': true, + 'zip:extension:start': true, + 'zip:extension:done': true, + 'zip:sources:start': false, + 'zip:sources:done': false, + 'zip:done': true, + }); + }); + + it('zip -b firefox should call hooks', async () => { + const project = new TestProject(); + project.addFile('entrypoints/popup.html', ''); + + await project.zip({ hooks, browser: 'firefox' }); + + expectHooksToBeCalled({ + ready: true, + 'prepare:types': true, + 'prepare:publicPaths': true, + 'build:before': true, + 'build:done': true, + 'build:publicAssets': true, + 'build:manifestGenerated': true, + 'entrypoints:grouped': true, + 'entrypoints:resolved': true, + 'vite:build:extendConfig': 1, + 'vite:devServer:extendConfig': false, + 'zip:start': true, + 'zip:extension:start': true, + 'zip:extension:done': true, + 'zip:sources:start': true, + 'zip:sources:done': true, + 'zip:done': true, }); }); @@ -122,6 +173,12 @@ describe('Hooks', () => { 'entrypoints:resolved': true, 'vite:build:extendConfig': 2, 'vite:devServer:extendConfig': 1, + 'zip:start': false, + 'zip:extension:start': false, + 'zip:extension:done': false, + 'zip:sources:start': false, + 'zip:sources:done': false, + 'zip:done': false, }); }); }); diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index 9226a48f..bd9cdd20 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -20,6 +20,7 @@ import { normalizePath } from './utils/paths'; export async function zip(config?: InlineConfig): Promise { await registerWxt('build', config); const output = await internalBuild(); + await wxt.hooks.callHook('zip:start', wxt); const start = Date.now(); wxt.logger.info('Zipping extension...'); @@ -42,17 +43,18 @@ export async function zip(config?: InlineConfig): Promise { await fs.ensureDir(wxt.config.outBaseDir); // ZIP output directory - + await wxt.hooks.callHook('zip:extension:start', wxt); const outZipFilename = applyTemplate(wxt.config.zip.artifactTemplate); const outZipPath = path.resolve(wxt.config.outBaseDir, outZipFilename); await zipDir(wxt.config.outDir, outZipPath, { exclude: wxt.config.zip.exclude, }); zipFiles.push(outZipPath); + await wxt.hooks.callHook('zip:extension:done', wxt, outZipPath); // ZIP sources for Firefox - if (wxt.config.browser === 'firefox') { + await wxt.hooks.callHook('zip:sources:start', wxt); const { overrides, files: downloadedPackages } = await downloadPrivatePackages(); const sourcesZipFilename = applyTemplate(wxt.config.zip.sourcesTemplate); @@ -71,6 +73,7 @@ export async function zip(config?: InlineConfig): Promise { additionalFiles: downloadedPackages, }); zipFiles.push(sourcesZipPath); + await wxt.hooks.callHook('zip:sources:done', wxt, sourcesZipPath); } await printFileList( @@ -80,8 +83,11 @@ export async function zip(config?: InlineConfig): Promise { zipFiles, ); + await wxt.hooks.callHook('zip:done', wxt, zipFiles); + return zipFiles; } + async function zipDir( directory: string, outputPath: string, diff --git a/packages/wxt/src/types.ts b/packages/wxt/src/types.ts index 2986f9f9..d556143e 100644 --- a/packages/wxt/src/types.ts +++ b/packages/wxt/src/types.ts @@ -1164,6 +1164,44 @@ export interface WxtHooks { * @param entrypoints The list of files that will be copied into the output directory */ 'build:publicAssets': (wxt: Wxt, files: ResolvedPublicFile[]) => HookResult; + /** + * Called before the zip process starts. + * @param wxt The configured WXT object + */ + 'zip:start': (wxt: Wxt) => HookResult; + + /** + * Called before zipping the extension files. + * @param wxt The configured WXT object + */ + 'zip:extension:start': (wxt: Wxt) => HookResult; + + /** + * Called after zipping the extension files. + * @param wxt The configured WXT object + * @param zipPath The path to the created extension zip file + */ + 'zip:extension:done': (wxt: Wxt, zipPath: string) => HookResult; + + /** + * Called before zipping the source files (for Firefox). + * @param wxt The configured WXT object + */ + 'zip:sources:start': (wxt: Wxt) => HookResult; + + /** + * Called after zipping the source files (for Firefox). + * @param wxt The configured WXT object + * @param zipPath The path to the created sources zip file + */ + 'zip:sources:done': (wxt: Wxt, zipPath: string) => HookResult; + + /** + * Called after the entire zip process is complete. + * @param wxt The configured WXT object + * @param zipFiles An array of paths to all created zip files + */ + 'zip:done': (wxt: Wxt, zipFiles: string[]) => HookResult; } export interface Wxt {