diff --git a/src/core/utils/building/resolve-config.ts b/src/core/utils/building/resolve-config.ts index 22cf41f0..a0de77cc 100644 --- a/src/core/utils/building/resolve-config.ts +++ b/src/core/utils/building/resolve-config.ts @@ -10,6 +10,7 @@ import { WxtDevServer, WxtResolvedUnimportOptions, Logger, + WxtCommand, } from '~/types'; import path from 'node:path'; import { createFsCache } from '~/core/utils/cache'; @@ -30,7 +31,7 @@ import { normalizePath } from '../paths'; */ export async function resolveConfig( inlineConfig: InlineConfig, - command: 'build' | 'serve', + command: WxtCommand, server?: WxtDevServer, ): Promise { // Load user config @@ -65,8 +66,7 @@ export async function resolveConfig( const manifestVersion = mergedConfig.manifestVersion ?? (browser === 'firefox' || browser === 'safari' ? 2 : 3); - const mode = - mergedConfig.mode ?? (command === 'build' ? 'production' : 'development'); + const mode = mergedConfig.mode ?? COMMAND_MODES[command]; const env: ConfigEnv = { browser, command, manifestVersion, mode }; const root = path.resolve( @@ -113,13 +113,6 @@ export async function resolveConfig( }).map(([key, value]) => [key, path.resolve(root, value)]), ); - const analysisOutputFile = path.resolve( - root, - mergedConfig.analysis?.outputFile ?? 'stats.html', - ); - const analysisOutputDir = path.dirname(analysisOutputFile); - const analysisOutputName = path.parse(analysisOutputFile).name; - const finalConfig: Omit = { browser, command, @@ -142,26 +135,14 @@ export async function resolveConfig( srcDir, typesDir, wxtDir, - zip: resolveInternalZipConfig(root, mergedConfig), - transformManifest(manifest) { - userConfig.transformManifest?.(manifest); - inlineConfig.transformManifest?.(manifest); - }, - analysis: { - enabled: mergedConfig.analysis?.enabled ?? false, - open: mergedConfig.analysis?.open ?? false, - template: mergedConfig.analysis?.template ?? 'treemap', - outputFile: analysisOutputFile, - outputDir: analysisOutputDir, - outputName: analysisOutputName, - keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false, - }, + zip: resolveZipConfig(root, mergedConfig), + transformManifest: mergedConfig.transformManifest, + analysis: resolveAnalysisConfig(root, mergedConfig), userConfigMetadata: userConfigMetadata ?? {}, alias, - experimental: { - includeBrowserPolyfill: - mergedConfig.experimental?.includeBrowserPolyfill ?? true, - }, + experimental: defu(mergedConfig.experimental, { + includeBrowserPolyfill: true, + }), server, dev: { reloadCommand, @@ -196,65 +177,40 @@ async function resolveManifestConfig( function mergeInlineConfig( inlineConfig: InlineConfig, userConfig: UserConfig, -): NullablyRequired { - let imports: InlineConfig['imports']; - if (inlineConfig.imports === false || userConfig.imports === false) { - imports = false; - } else if (userConfig.imports == null && inlineConfig.imports == null) { - imports = undefined; - } else { - imports = defu(inlineConfig.imports ?? {}, userConfig.imports ?? {}); - } +): InlineConfig { + // Merge imports option + const imports: InlineConfig['imports'] = + inlineConfig.imports === false || userConfig.imports === false + ? false + : userConfig.imports == null && inlineConfig.imports == null + ? undefined + : defu(inlineConfig.imports ?? {}, userConfig.imports ?? {}); + + // Merge manifest option const manifest: UserManifestFn = async (env) => { const user = await resolveManifestConfig(env, userConfig.manifest); const inline = await resolveManifestConfig(env, inlineConfig.manifest); return defu(inline, user); }; - const runner: InlineConfig['runner'] = defu( - inlineConfig.runner ?? {}, - userConfig.runner ?? {}, - ); - const zip: InlineConfig['zip'] = defu( - inlineConfig.zip ?? {}, - userConfig.zip ?? {}, - ); - const hooks: InlineConfig['hooks'] = defu( - inlineConfig.hooks ?? {}, - userConfig.hooks ?? {}, - ); + + // Merge transformManifest option + const transformManifest: InlineConfig['transformManifest'] = (manifest) => { + userConfig.transformManifest?.(manifest); + inlineConfig.transformManifest?.(manifest); + }; return { - root: inlineConfig.root ?? userConfig.root, - browser: inlineConfig.browser ?? userConfig.browser, - manifestVersion: inlineConfig.manifestVersion ?? userConfig.manifestVersion, - configFile: inlineConfig.configFile, - debug: inlineConfig.debug ?? userConfig.debug, - entrypointsDir: inlineConfig.entrypointsDir ?? userConfig.entrypointsDir, - filterEntrypoints: - inlineConfig.filterEntrypoints ?? userConfig.filterEntrypoints, + ...defu(inlineConfig, userConfig), + // Custom merge values + transformManifest, imports, - logger: inlineConfig.logger ?? userConfig.logger, manifest, - mode: inlineConfig.mode ?? userConfig.mode, - publicDir: inlineConfig.publicDir ?? userConfig.publicDir, - runner, - srcDir: inlineConfig.srcDir ?? userConfig.srcDir, - outDir: inlineConfig.outDir ?? userConfig.outDir, - zip, - analysis: defu(inlineConfig.analysis ?? {}, userConfig.analysis ?? {}), - alias: defu(inlineConfig.alias ?? {}, userConfig.alias ?? {}), - experimental: defu( - inlineConfig.experimental ?? {}, - userConfig.experimental ?? {}, - ), + // Vite builder handles merging vite config internally vite: undefined, - transformManifest: undefined, - dev: defu(inlineConfig.dev ?? {}, userConfig.dev ?? {}), - hooks, }; } -function resolveInternalZipConfig( +function resolveZipConfig( root: string, mergedConfig: InlineConfig, ): NullablyRequired { @@ -283,6 +239,28 @@ function resolveInternalZipConfig( }; } +function resolveAnalysisConfig( + root: string, + mergedConfig: InlineConfig, +): NullablyRequired { + const analysisOutputFile = path.resolve( + root, + mergedConfig.analysis?.outputFile ?? 'stats.html', + ); + const analysisOutputDir = path.dirname(analysisOutputFile); + const analysisOutputName = path.parse(analysisOutputFile).name; + + return { + enabled: mergedConfig.analysis?.enabled ?? false, + open: mergedConfig.analysis?.open ?? false, + template: mergedConfig.analysis?.template ?? 'treemap', + outputFile: analysisOutputFile, + outputDir: analysisOutputDir, + outputName: analysisOutputName, + keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false, + }; +} + async function getUnimportOptions( wxtDir: string, logger: Logger, @@ -351,3 +329,11 @@ function logMissingDir(logger: Logger, name: string, expected: string) { )}`, ); } + +/** + * Map of `ConfigEnv` commands to their default modes. + */ +const COMMAND_MODES: Record = { + build: 'production', + serve: 'development', +}; diff --git a/src/core/utils/manifest.ts b/src/core/utils/manifest.ts index 15fe3f28..be3b3c91 100644 --- a/src/core/utils/manifest.ts +++ b/src/core/utils/manifest.ts @@ -111,7 +111,7 @@ export async function generateManifest( if (wxt.config.command === 'serve') addDevModePermissions(manifest); // TODO: Remove in v1 - wxt.config.transformManifest(manifest); + wxt.config.transformManifest?.(manifest); await wxt.hooks.callHook('build:manifestGenerated', wxt, manifest); if (wxt.config.manifestVersion === 2) { diff --git a/src/core/wxt.ts b/src/core/wxt.ts index 761072bb..8ae04c9e 100644 --- a/src/core/wxt.ts +++ b/src/core/wxt.ts @@ -1,4 +1,4 @@ -import { InlineConfig, Wxt, WxtDevServer, WxtHooks } from '~/types'; +import { InlineConfig, Wxt, WxtCommand, WxtDevServer, WxtHooks } from '~/types'; import { resolveConfig } from './utils/building'; import { createHooks } from 'hookable'; import { createWxtPackageManager } from './package-managers'; @@ -13,7 +13,7 @@ export let wxt: Wxt; * Create and register a global instance of the Wxt interface for use throughout the project. */ export async function registerWxt( - command: 'build' | 'serve', + command: WxtCommand, inlineConfig: InlineConfig = {}, server?: WxtDevServer, ): Promise { diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts index 5cf7be25..290d3447 100644 --- a/src/types/globals.d.ts +++ b/src/types/globals.d.ts @@ -4,7 +4,7 @@ declare const __DEV_SERVER_PORT__: string; // Globals defined by the vite-plugins/devServerGlobals.ts and utils/globals.ts interface ImportMetaEnv { - readonly COMMAND: 'build' | 'serve'; + readonly COMMAND: WxtCommand; readonly MANIFEST_VERSION: 2 | 3; readonly ENTRYPOINT: string; } diff --git a/src/types/index.ts b/src/types/index.ts index 13ff4c7d..5f3cb2cb 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -774,7 +774,7 @@ export interface ConfigEnv { /** * The command used to run WXT. `"serve"` during development and `"build"` for any other command. */ - command: 'build' | 'serve'; + command: WxtCommand; /** * Browser passed in from the CLI via the `-b` or `--browser` flag. Defaults to `"chrome"` when not passed. */ @@ -787,6 +787,8 @@ export interface ConfigEnv { manifestVersion: 2 | 3; } +export type WxtCommand = 'build' | 'serve'; + /** * Configure how the browser starts up. */ @@ -1018,7 +1020,7 @@ export interface ResolvedConfig { */ wxtModuleDir: string; mode: string; - command: 'build' | 'serve'; + command: WxtCommand; browser: TargetBrowser; manifestVersion: TargetManifestVersion; env: ConfigEnv; @@ -1038,7 +1040,10 @@ export interface ResolvedConfig { downloadedPackagesDir: string; downloadPackages: string[]; }; - transformManifest: (manifest: Manifest.WebExtensionManifest) => void; + /** + * @deprecated Use `build:manifestGenerated` hook instead. + */ + transformManifest?: (manifest: Manifest.WebExtensionManifest) => void; analysis: { enabled: boolean; open: boolean;