wxt 0.19.10 → 0.19.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -71,7 +71,7 @@ Or see the [installation guide](https://wxt.dev/guide/installation.html) to get
71
71
  - 🦾 Auto-imports
72
72
  - 🤖 Automated publishing
73
73
  - 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
74
- - 📦 Modular architecture with [WXT modules](https://wxt.dev/guide/go-further/reusable-modules.html#overview)
74
+ - 📦 [Module system](https://wxt.dev/guide/essentials/wxt-modules.html#overview) for reusing code between extensions
75
75
  - 🖍️ Quickly bootstrap a new project
76
76
  - 📏 Bundle analysis
77
77
  - ⬇️ Download and bundle remote URL imports
@@ -8,8 +8,16 @@ export type AugmentedBrowser = Omit<Browser, 'runtime' | 'i18n'> & {
8
8
  runtime: WxtRuntime & Omit<Browser['runtime'], 'getURL'>;
9
9
  i18n: WxtI18n & Omit<Browser['i18n'], 'getMessage'>;
10
10
  };
11
+ /**
12
+ * This interface is empty because it is generated per-project when running `wxt prepare`. See:
13
+ * - `.wxt/types/paths.d.ts`
14
+ */
11
15
  export interface WxtRuntime {
12
16
  }
17
+ /**
18
+ * This interface is empty because it is generated per-project when running `wxt prepare`. See:
19
+ * - `.wxt/types/i18n.d.ts`
20
+ */
13
21
  export interface WxtI18n {
14
22
  }
15
23
  export declare const browser: AugmentedBrowser;
@@ -4,6 +4,7 @@ import { printHeader } from "../core/utils/log/index.mjs";
4
4
  import { formatDuration } from "../core/utils/time.mjs";
5
5
  import { ValidationError } from "../core/utils/validation.mjs";
6
6
  import { registerWxt } from "../core/wxt.mjs";
7
+ import spawn from "nano-spawn";
7
8
  export function wrapAction(cb, options) {
8
9
  return async (...args) => {
9
10
  const isDebug = !!args.find((arg) => arg?.debug);
@@ -43,8 +44,7 @@ export function createAliasedCommand(base, name, alias, bin, docsUrl) {
43
44
  const args = process.argv.slice(
44
45
  process.argv.indexOf(aliasedCommand.name) + 1
45
46
  );
46
- const { execa } = await import("execa");
47
- await execa(bin, args, {
47
+ await spawn(bin, args, {
48
48
  stdio: "inherit"
49
49
  });
50
50
  } catch {
@@ -56,7 +56,7 @@ cli.command("build [root]", "build for production").option("-c, --config <file>"
56
56
  });
57
57
  })
58
58
  );
59
- cli.command("zip [root]", "build for production and zip output").option("-c, --config <file>", "use specified config file").option("-m, --mode <mode>", "set env mode").option("-b, --browser <browser>", "specify a browser").option("--mv3", "target manifest v3").option("--mv2", "target manifest v2").action(
59
+ cli.command("zip [root]", "build for production and zip output").option("-c, --config <file>", "use specified config file").option("-m, --mode <mode>", "set env mode").option("-b, --browser <browser>", "specify a browser").option("--mv3", "target manifest v3").option("--mv2", "target manifest v2").option("--sources", "always create sources zip").action(
60
60
  wrapAction(async (root, flags) => {
61
61
  await zip({
62
62
  root,
@@ -64,7 +64,10 @@ cli.command("zip [root]", "build for production and zip output").option("-c, --c
64
64
  browser: flags.browser,
65
65
  manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : void 0,
66
66
  configFile: flags.config,
67
- debug: flags.debug
67
+ debug: flags.debug,
68
+ zip: {
69
+ zipSources: flags.sources
70
+ }
68
71
  });
69
72
  })
70
73
  );
@@ -4,13 +4,13 @@ export * from './types';
4
4
  /**
5
5
  * Create a content script UI without any isolation.
6
6
  *
7
- * @see https://wxt.dev/guide/key-concepts/content-script-ui.html#integrated
7
+ * @see https://wxt.dev/guide/essentials/content-scripts.html#integrated
8
8
  */
9
9
  export declare function createIntegratedUi<TMounted>(ctx: ContentScriptContext, options: IntegratedContentScriptUiOptions<TMounted>): IntegratedContentScriptUi<TMounted>;
10
10
  /**
11
11
  * Create a content script UI using an iframe.
12
12
  *
13
- * @see https://wxt.dev/guide/key-concepts/content-script-ui.html#iframe
13
+ * @see https://wxt.dev/guide/essentials/content-scripts.html#iframe
14
14
  */
15
15
  export declare function createIframeUi<TMounted>(ctx: ContentScriptContext, options: IframeContentScriptUiOptions<TMounted>): IframeContentScriptUi<TMounted>;
16
16
  /**
@@ -18,6 +18,6 @@ export declare function createIframeUi<TMounted>(ctx: ContentScriptContext, opti
18
18
  *
19
19
  * > This function is async because it has to load the CSS via a network call.
20
20
  *
21
- * @see https://wxt.dev/guide/key-concepts/content-script-ui.html#shadowroot
21
+ * @see https://wxt.dev/guide/essentials/content-scripts.html#shadowroot
22
22
  */
23
23
  export declare function createShadowRootUi<TMounted>(ctx: ContentScriptContext, options: ShadowRootContentScriptUiOptions<TMounted>): Promise<ShadowRootContentScriptUi<TMounted>>;
@@ -17,6 +17,7 @@ export async function createViteBuilder(wxtConfig, hooks, server) {
17
17
  config.configFile = false;
18
18
  config.logLevel = "warn";
19
19
  config.mode = wxtConfig.mode;
20
+ config.envPrefix ??= ["VITE_", "WXT_"];
20
21
  config.build ??= {};
21
22
  config.publicDir = wxtConfig.publicDir;
22
23
  config.build.copyPublicDir = false;
@@ -67,7 +68,7 @@ export async function createViteBuilder(wxtConfig, hooks, server) {
67
68
  plugins,
68
69
  esbuild: {
69
70
  // Add a footer with the returned value so it can return values to `scripting.executeScript`
70
- // Footer is added apart of esbuild to make sure it's not minified. It
71
+ // Footer is added a part of esbuild to make sure it's not minified. It
71
72
  // get's removed if added to `build.rollupOptions.output.footer`
72
73
  // See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/executeScript#return_value
73
74
  footer: iifeReturnValueName + ";"
@@ -0,0 +1,5 @@
1
+ import { Entrypoint } from '../types';
2
+ /**
3
+ * Generate and write all the files inside the `InternalConfig.typesDir` directory.
4
+ */
5
+ export declare function generateWxtDir(entrypoints: Entrypoint[]): Promise<void>;
@@ -1,16 +1,13 @@
1
1
  import fs from "fs-extra";
2
2
  import { dirname, relative, resolve } from "node:path";
3
- import {
4
- getEntrypointBundlePath,
5
- isHtmlEntrypoint
6
- } from "../../utils/entrypoints.mjs";
7
- import { getEntrypointGlobals, getGlobals } from "../../utils/globals.mjs";
8
- import { normalizePath } from "../../utils/paths.mjs";
3
+ import { getEntrypointBundlePath, isHtmlEntrypoint } from "./utils/entrypoints.mjs";
4
+ import { getEntrypointGlobals, getGlobals } from "./utils/globals.mjs";
5
+ import { normalizePath } from "./utils/paths.mjs";
9
6
  import path from "node:path";
10
- import { parseI18nMessages } from "../../utils/i18n.mjs";
11
- import { writeFileIfDifferent, getPublicFiles } from "../../utils/fs.mjs";
12
- import { wxt } from "../../wxt.mjs";
13
- export async function generateTypesDir(entrypoints) {
7
+ import { parseI18nMessages } from "./utils/i18n.mjs";
8
+ import { writeFileIfDifferent, getPublicFiles } from "./utils/fs.mjs";
9
+ import { wxt } from "./wxt.mjs";
10
+ export async function generateWxtDir(entrypoints) {
14
11
  await fs.ensureDir(wxt.config.typesDir);
15
12
  const entries = [
16
13
  // Hard-coded entries
@@ -1,4 +1,5 @@
1
1
  import { dedupeDependencies, npm } from "./npm.mjs";
2
+ import spawn from "nano-spawn";
2
3
  export const bun = {
3
4
  overridesKey: "overrides",
4
5
  // But also supports "resolutions"
@@ -10,8 +11,7 @@ export const bun = {
10
11
  if (options?.all) {
11
12
  args.push("--all");
12
13
  }
13
- const { execa } = await import("execa");
14
- const res = await execa("bun", args, { cwd: options?.cwd });
14
+ const res = await spawn("bun", args, { cwd: options?.cwd });
15
15
  return dedupeDependencies(
16
16
  res.stdout.split("\n").slice(1).map((line) => line.trim()).map((line) => /.* (@?\S+)@(\S+)$/.exec(line)).filter((match) => !!match).map(([_, name, version]) => ({ name, version }))
17
17
  );
@@ -1,11 +1,11 @@
1
1
  import path from "node:path";
2
2
  import { ensureDir } from "fs-extra";
3
+ import spawn from "nano-spawn";
3
4
  export const npm = {
4
5
  overridesKey: "overrides",
5
6
  async downloadDependency(id, downloadDir) {
6
7
  await ensureDir(downloadDir);
7
- const { execa } = await import("execa");
8
- const res = await execa("npm", ["pack", id, "--json"], {
8
+ const res = await spawn("npm", ["pack", id, "--json"], {
9
9
  cwd: downloadDir
10
10
  });
11
11
  const packed = JSON.parse(res.stdout);
@@ -16,8 +16,7 @@ export const npm = {
16
16
  if (options?.all) {
17
17
  args.push("--depth", "Infinity");
18
18
  }
19
- const { execa } = await import("execa");
20
- const res = await execa("npm", args, { cwd: options?.cwd });
19
+ const res = await spawn("npm", args, { cwd: options?.cwd });
21
20
  const project = JSON.parse(res.stdout);
22
21
  return flattenNpmListOutput([project]);
23
22
  }
@@ -1,4 +1,5 @@
1
1
  import { flattenNpmListOutput, npm } from "./npm.mjs";
2
+ import spawn from "nano-spawn";
2
3
  export const pnpm = {
3
4
  overridesKey: "resolutions",
4
5
  // "pnpm.overrides" has a higher priority, but I don't want to deal with nesting
@@ -13,8 +14,7 @@ export const pnpm = {
13
14
  if (typeof process !== "undefined" && process.env.WXT_PNPM_IGNORE_WORKSPACE === "true") {
14
15
  args.push("--ignore-workspace");
15
16
  }
16
- const { execa } = await import("execa");
17
- const res = await execa("pnpm", args, { cwd: options?.cwd });
17
+ const res = await spawn("pnpm", args, { cwd: options?.cwd });
18
18
  const projects = JSON.parse(res.stdout);
19
19
  return flattenNpmListOutput(projects);
20
20
  }
@@ -1,4 +1,5 @@
1
1
  import { dedupeDependencies, npm } from "./npm.mjs";
2
+ import spawn from "nano-spawn";
2
3
  export const yarn = {
3
4
  overridesKey: "resolutions",
4
5
  downloadDependency(...args) {
@@ -9,8 +10,7 @@ export const yarn = {
9
10
  if (options?.all) {
10
11
  args.push("--depth", "Infinity");
11
12
  }
12
- const { execa } = await import("execa");
13
- const res = await execa("yarn", args, { cwd: options?.cwd });
13
+ const res = await spawn("yarn", args, { cwd: options?.cwd });
14
14
  const tree = res.stdout.split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
15
15
  if (tree == null) throw Error("'yarn list --json' did not output a tree");
16
16
  const queue = [...tree.trees];
@@ -1,8 +1,9 @@
1
- import { findEntrypoints, generateTypesDir } from "./utils/building/index.mjs";
1
+ import { findEntrypoints } from "./utils/building/index.mjs";
2
+ import { generateWxtDir } from "./generate-wxt-dir.mjs";
2
3
  import { registerWxt, wxt } from "./wxt.mjs";
3
4
  export async function prepare(config) {
4
5
  await registerWxt("build", config);
5
6
  wxt.logger.info("Generating types...");
6
7
  const entrypoints = await findEntrypoints();
7
- await generateTypesDir(entrypoints);
8
+ await generateWxtDir(entrypoints);
8
9
  }
@@ -1,4 +1,4 @@
1
- import { InlineConfig, ResolvedConfig, UserConfig, Logger, WxtCommand, WxtModuleWithMetadata } from '../../../types';
1
+ import { InlineConfig, ResolvedConfig, UserConfig, Logger, WxtCommand, WxtModuleWithMetadata } from '../types';
2
2
  /**
3
3
  * Given an inline config, discover the config file if necessary, merge the results, resolve any
4
4
  * relative paths, and apply any defaults.
@@ -1,15 +1,15 @@
1
1
  import { loadConfig } from "c12";
2
2
  import path from "node:path";
3
- import { createFsCache } from "../../utils/cache.mjs";
3
+ import { createFsCache } from "./utils/cache.mjs";
4
4
  import consola, { LogLevels } from "consola";
5
5
  import defu from "defu";
6
6
  import fs from "fs-extra";
7
- import { normalizePath } from "../paths.mjs";
7
+ import { normalizePath } from "./utils/paths.mjs";
8
8
  import glob from "fast-glob";
9
- import { builtinModules } from "../../../builtin-modules/index.mjs";
10
- import { getEslintVersion } from "../eslint.mjs";
11
- import { safeStringToNumber } from "../number.mjs";
12
- import { loadEnv } from "../env.mjs";
9
+ import { builtinModules } from "../builtin-modules/index.mjs";
10
+ import { getEslintVersion } from "./utils/eslint.mjs";
11
+ import { safeStringToNumber } from "./utils/number.mjs";
12
+ import { loadEnv } from "./utils/env.mjs";
13
13
  export async function resolveConfig(inlineConfig, command) {
14
14
  let userConfig = {};
15
15
  let userConfigMetadata;
@@ -53,7 +53,12 @@ export async function resolveConfig(inlineConfig, command) {
53
53
  const publicDir = path.resolve(srcDir, mergedConfig.publicDir ?? "public");
54
54
  const typesDir = path.resolve(wxtDir, "types");
55
55
  const outBaseDir = path.resolve(root, mergedConfig.outDir ?? ".output");
56
- const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
56
+ const modeSuffixes = {
57
+ production: "",
58
+ development: "-dev"
59
+ };
60
+ const outDirTemplate = (mergedConfig.outDirTemplate ?? `${browser}-mv${manifestVersion}`).replaceAll("{{browser}}", browser).replaceAll("{{manifestVersion}}", manifestVersion.toString()).replaceAll("{{modeSuffix}}", modeSuffixes[mode] ?? `-${mode}`).replaceAll("{{mode}}", mode).replaceAll("{{command}}", command);
61
+ const outDir = path.resolve(outBaseDir, outDirTemplate);
57
62
  const reloadCommand = mergedConfig.dev?.reloadCommand ?? "Alt+R";
58
63
  const runnerConfig = await loadConfig({
59
64
  name: "web-ext",
@@ -129,7 +134,7 @@ export async function resolveConfig(inlineConfig, command) {
129
134
  srcDir,
130
135
  typesDir,
131
136
  wxtDir,
132
- zip: resolveZipConfig(root, outBaseDir, mergedConfig),
137
+ zip: resolveZipConfig(root, browser, outBaseDir, mergedConfig),
133
138
  transformManifest: mergedConfig.transformManifest,
134
139
  analysis: resolveAnalysisConfig(root, mergedConfig),
135
140
  userConfigMetadata: userConfigMetadata ?? {},
@@ -178,7 +183,7 @@ async function mergeInlineConfig(inlineConfig, userConfig) {
178
183
  ...builderConfig
179
184
  };
180
185
  }
181
- function resolveZipConfig(root, outBaseDir, mergedConfig) {
186
+ function resolveZipConfig(root, browser, outBaseDir, mergedConfig) {
182
187
  const downloadedPackagesDir = path.resolve(root, ".wxt/local_modules");
183
188
  return {
184
189
  name: void 0,
@@ -188,6 +193,7 @@ function resolveZipConfig(root, outBaseDir, mergedConfig) {
188
193
  includeSources: [],
189
194
  compressionLevel: 9,
190
195
  ...mergedConfig.zip,
196
+ zipSources: mergedConfig.zip?.zipSources ?? ["firefox", "opera"].includes(browser),
191
197
  exclude: mergedConfig.zip?.exclude ?? [],
192
198
  excludeSources: [
193
199
  "**/node_modules",
@@ -338,6 +344,7 @@ export async function resolveWxtUserModules(modulesDir, modules = []) {
338
344
  cwd: modulesDir,
339
345
  onlyFiles: true
340
346
  }).catch(() => []);
347
+ localModulePaths.sort();
341
348
  const localModules = await Promise.all(
342
349
  localModulePaths.map(async (file) => {
343
350
  const absolutePath = normalizePath(path.resolve(modulesDir, file));
@@ -1,8 +1,6 @@
1
1
  export * from './build-entrypoints';
2
2
  export * from './detect-dev-changes';
3
3
  export * from './find-entrypoints';
4
- export * from './generate-wxt-dir';
5
- export * from './resolve-config';
6
4
  export * from './group-entrypoints';
7
5
  export * from './import-entrypoint';
8
6
  export * from './internal-build';
@@ -1,8 +1,6 @@
1
1
  export * from "./build-entrypoints.mjs";
2
2
  export * from "./detect-dev-changes.mjs";
3
3
  export * from "./find-entrypoints.mjs";
4
- export * from "./generate-wxt-dir.mjs";
5
- export * from "./resolve-config.mjs";
6
4
  export * from "./group-entrypoints.mjs";
7
5
  export * from "./import-entrypoint.mjs";
8
6
  export * from "./internal-build.mjs";
@@ -1,4 +1,4 @@
1
- import { generateTypesDir } from "./generate-wxt-dir.mjs";
1
+ import { generateWxtDir } from "../../generate-wxt-dir.mjs";
2
2
  import { buildEntrypoints } from "./build-entrypoints.mjs";
3
3
  import { generateManifest, writeManifest } from "../../utils/manifest.mjs";
4
4
  import { wxt } from "../../wxt.mjs";
@@ -8,7 +8,7 @@ export async function rebuild(allEntrypoints, entrypointGroups, existingOutput =
8
8
  }) {
9
9
  const { default: ora } = await import("ora");
10
10
  const spinner = ora(`Preparing...`).start();
11
- await generateTypesDir(allEntrypoints).catch((err) => {
11
+ await generateWxtDir(allEntrypoints).catch((err) => {
12
12
  wxt.logger.warn("Failed to update .wxt directory:", err);
13
13
  if (wxt.config.command === "build") throw err;
14
14
  });
@@ -1,6 +1,6 @@
1
1
  import { config } from "dotenv";
2
2
  export function loadEnv(mode) {
3
3
  return config({
4
- path: [`.env`, `.env.local`, `.env.${mode}`, `.env.${mode}.local`]
4
+ path: [`.env.${mode}.local`, `.env.${mode}`, `.env.local`, `.env`]
5
5
  });
6
6
  }