diff --git a/packages/wxt/e2e/tests/zip.test.ts b/packages/wxt/e2e/tests/zip.test.ts index 5645db60c..713ad68ab 100644 --- a/packages/wxt/e2e/tests/zip.test.ts +++ b/packages/wxt/e2e/tests/zip.test.ts @@ -178,4 +178,73 @@ describe('Zipping', () => { true, ); }); + + it.each(['firefox', 'opera'])( + 'should create sources zip for "%s" browser when sourcesZip is undefined', + async (browser) => { + const project = new TestProject({ + name: 'test', + version: '1.0.0', + }); + project.addFile( + 'entrypoints/background.ts', + 'export default defineBackground(() => {});', + ); + const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip'); + + await project.zip({ + browser, + }); + + expect(await project.fileExists(sourcesZip)).toBe(true); + }, + ); + + it.each(['firefox', 'chrome'])( + 'should create sources zip for "%s" when sourcesZip is true', + async (browser) => { + const project = new TestProject({ + name: 'test', + version: '1.0.0', + }); + project.addFile( + 'entrypoints/background.ts', + 'export default defineBackground(() => {});', + ); + const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip'); + + await project.zip({ + browser, + zip: { + zipSources: true, + }, + }); + + expect(await project.fileExists(sourcesZip)).toBe(true); + }, + ); + + it.each(['firefox', 'chrome'])( + 'should not create sources zip for "%s" when sourcesZip is false', + async (browser) => { + const project = new TestProject({ + name: 'test', + version: '1.0.0', + }); + project.addFile( + 'entrypoints/background.ts', + 'export default defineBackground(() => {});', + ); + const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip'); + + await project.zip({ + browser, + zip: { + zipSources: false, + }, + }); + + expect(await project.fileExists(sourcesZip)).toBe(false); + }, + ); }); diff --git a/packages/wxt/src/cli/__tests__/index.test.ts b/packages/wxt/src/cli/__tests__/index.test.ts index 6419163b9..074934338 100644 --- a/packages/wxt/src/cli/__tests__/index.test.ts +++ b/packages/wxt/src/cli/__tests__/index.test.ts @@ -237,7 +237,9 @@ describe('CLI', () => { mockArgv('zip'); await importCli(); - expect(zipMock).toBeCalledWith({}); + expect(zipMock).toBeCalledWith({ + zip: {}, + }); }); it('should respect passing a custom root', async () => { @@ -246,6 +248,7 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ root: 'path/to/root', + zip: {}, }); }); @@ -255,6 +258,7 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ configFile: './path/to/config.ts', + zip: {}, }); }); @@ -264,6 +268,7 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ mode: 'development', + zip: {}, }); }); @@ -273,6 +278,7 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ browser: 'firefox', + zip: {}, }); }); @@ -282,6 +288,7 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ manifestVersion: 2, + zip: {}, }); }); @@ -291,6 +298,7 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ manifestVersion: 3, + zip: {}, }); }); @@ -300,6 +308,40 @@ describe('CLI', () => { expect(zipMock).toBeCalledWith({ debug: true, + zip: {}, + }); + }); + + it('should pass undefined for zipSources when --sources is not passed', async () => { + mockArgv('zip'); + await importCli(); + + expect(zipMock).toBeCalledWith({ + zip: { + zipSources: undefined, + }, + }); + }); + + it('should pass true for zipSources when --sources is passed', async () => { + mockArgv('zip', '--sources'); + await importCli(); + + expect(zipMock).toBeCalledWith({ + zip: { + zipSources: true, + }, + }); + }); + + it('should pass false for zipSources when --sources=false is passed', async () => { + mockArgv('zip', '--sources=false'); + await importCli(); + + expect(zipMock).toBeCalledWith({ + zip: { + zipSources: false, + }, }); }); }); diff --git a/packages/wxt/src/cli/commands.ts b/packages/wxt/src/cli/commands.ts index 75b02947d..a6159881a 100644 --- a/packages/wxt/src/cli/commands.ts +++ b/packages/wxt/src/cli/commands.ts @@ -95,6 +95,7 @@ cli .option('-b, --browser ', 'specify a browser') .option('--mv3', 'target manifest v3') .option('--mv2', 'target manifest v2') + .option('--sources', 'always create sources zip') .action( wrapAction(async (root, flags) => { await zip({ @@ -104,6 +105,9 @@ cli manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined, configFile: flags.config, debug: flags.debug, + zip: { + zipSources: flags.sources, + }, }); }), ); diff --git a/packages/wxt/src/core/resolve-config.ts b/packages/wxt/src/core/resolve-config.ts index b851ba25d..8269179ca 100644 --- a/packages/wxt/src/core/resolve-config.ts +++ b/packages/wxt/src/core/resolve-config.ts @@ -179,7 +179,7 @@ export async function resolveConfig( srcDir, typesDir, wxtDir, - zip: resolveZipConfig(root, outBaseDir, mergedConfig), + zip: resolveZipConfig(root, browser, outBaseDir, mergedConfig), transformManifest: mergedConfig.transformManifest, analysis: resolveAnalysisConfig(root, mergedConfig), userConfigMetadata: userConfigMetadata ?? {}, @@ -258,6 +258,7 @@ async function mergeInlineConfig( function resolveZipConfig( root: string, + browser: string, outBaseDir: string, mergedConfig: InlineConfig, ): NullablyRequired { @@ -270,6 +271,8 @@ function resolveZipConfig( includeSources: [], compressionLevel: 9, ...mergedConfig.zip, + zipSources: + mergedConfig.zip?.zipSources ?? ['firefox', 'opera'].includes(browser), exclude: mergedConfig.zip?.exclude ?? [], excludeSources: [ '**/node_modules', diff --git a/packages/wxt/src/core/utils/testing/fake-objects.ts b/packages/wxt/src/core/utils/testing/fake-objects.ts index 08844529d..c097aeab7 100644 --- a/packages/wxt/src/core/utils/testing/fake-objects.ts +++ b/packages/wxt/src/core/utils/testing/fake-objects.ts @@ -293,6 +293,7 @@ export const fakeResolvedConfig = fakeObjectCreator(() => { downloadedPackagesDir: fakeDir(), downloadPackages: [], compressionLevel: 9, + zipSources: false, }, transformManifest: () => {}, userConfigMetadata: {}, diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index bd9cdd209..de7b17b6f 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -52,8 +52,7 @@ export async function zip(config?: InlineConfig): Promise { zipFiles.push(outZipPath); await wxt.hooks.callHook('zip:extension:done', wxt, outZipPath); - // ZIP sources for Firefox - if (wxt.config.browser === 'firefox') { + if (wxt.config.zip.zipSources) { await wxt.hooks.callHook('zip:sources:start', wxt); const { overrides, files: downloadedPackages } = await downloadPrivatePackages(); diff --git a/packages/wxt/src/types.ts b/packages/wxt/src/types.ts index d556143e9..445f04476 100644 --- a/packages/wxt/src/types.ts +++ b/packages/wxt/src/types.ts @@ -130,6 +130,16 @@ export interface InlineConfig { * @default "{{name}}-{{version}}-{{browser}}.zip" */ artifactTemplate?: string; + /** + * When zipping the extension, also zip sources. + * + * - `undefined`: zip sources if the target browser is "firefox" or "opera" + * - `true`: always zip sources + * - `false`: never zip sources + * + * @default undefined + */ + zipSources?: boolean; /** * Configure the filename output when zipping files. * @@ -1285,6 +1295,10 @@ export interface ResolvedConfig { downloadPackages: string[]; compressionLevel: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; exclude: string[]; + /** + * If true, when zipping the extension, also zip the sources. + */ + zipSources: boolean; }; /** * @deprecated Use `build:manifestGenerated` hook instead.