wxt 0.21.0 → 0.21.1

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.
Files changed (153) hide show
  1. package/README.md +0 -1
  2. package/bin/wxt-publish-extension.mjs +4 -3
  3. package/dist/browser.d.mts +7 -6
  4. package/dist/browser.mjs +6 -5
  5. package/dist/builtin-modules/favicon-permission.mjs +28 -0
  6. package/dist/builtin-modules/index.mjs +3 -4
  7. package/dist/builtin-modules/unimport.mjs +1 -3
  8. package/dist/cli/cli-utils.mjs +8 -9
  9. package/dist/cli/commands.mjs +1 -3
  10. package/dist/cli/index.mjs +1 -3
  11. package/dist/core/build.d.mts +9 -8
  12. package/dist/core/build.mjs +10 -11
  13. package/dist/core/builders/vite/index.mjs +123 -75
  14. package/dist/core/builders/vite/plugins/bundleAnalysis.mjs +1 -3
  15. package/dist/core/builders/vite/plugins/cssEntrypoints.mjs +6 -6
  16. package/dist/core/builders/vite/plugins/defineImportMeta.mjs +3 -4
  17. package/dist/core/builders/vite/plugins/devHtmlPrerender.mjs +34 -26
  18. package/dist/core/builders/vite/plugins/devServerGlobals.mjs +3 -3
  19. package/dist/core/builders/vite/plugins/entrypointGroupGlobals.mjs +2 -6
  20. package/dist/core/builders/vite/plugins/extensionApiMock.mjs +13 -8
  21. package/dist/core/builders/vite/plugins/globals.mjs +1 -3
  22. package/dist/core/builders/vite/plugins/iifeAnonymous.mjs +1 -2
  23. package/dist/core/builders/vite/plugins/iifeFooter.mjs +14 -7
  24. package/dist/core/builders/vite/plugins/index.mjs +17 -19
  25. package/dist/core/builders/vite/plugins/noopBackground.mjs +14 -9
  26. package/dist/core/builders/vite/plugins/removeEntrypointMainFunction.mjs +10 -12
  27. package/dist/core/builders/vite/plugins/resolveAppConfig.mjs +14 -10
  28. package/dist/core/builders/vite/plugins/resolveVirtualModules.mjs +15 -13
  29. package/dist/core/builders/vite/plugins/tsconfigPaths.mjs +1 -2
  30. package/dist/core/builders/vite/plugins/wxtPluginLoader.mjs +22 -17
  31. package/dist/core/clean.d.mts +3 -14
  32. package/dist/core/clean.mjs +19 -13
  33. package/dist/core/create-server.d.mts +6 -5
  34. package/dist/core/create-server.mjs +21 -117
  35. package/dist/core/define-config.mjs +1 -2
  36. package/dist/core/define-web-ext-config.d.mts +3 -6
  37. package/dist/core/define-web-ext-config.mjs +3 -12
  38. package/dist/core/generate-wxt-dir.mjs +53 -35
  39. package/dist/core/index.d.mts +3 -2
  40. package/dist/core/index.mjs +11 -11
  41. package/dist/core/initialize.mjs +28 -29
  42. package/dist/core/keyboard-shortcuts.mjs +4 -8
  43. package/dist/core/package-managers/bun.mjs +1 -3
  44. package/dist/core/package-managers/deno.mjs +1 -2
  45. package/dist/core/package-managers/index.mjs +1 -3
  46. package/dist/core/package-managers/npm.mjs +3 -5
  47. package/dist/core/package-managers/pnpm.mjs +1 -3
  48. package/dist/core/package-managers/yarn.mjs +1 -3
  49. package/dist/core/prepare.mjs +1 -3
  50. package/dist/core/resolve-config.mjs +63 -43
  51. package/dist/core/runners/manual.mjs +2 -6
  52. package/dist/core/runners/safari.mjs +3 -4
  53. package/dist/core/runners/web-ext.mjs +8 -11
  54. package/dist/core/runners/wsl.mjs +3 -4
  55. package/dist/core/utils/arrays.mjs +4 -11
  56. package/dist/core/utils/building/build-entrypoints.mjs +10 -11
  57. package/dist/core/utils/building/detect-dev-changes.mjs +37 -19
  58. package/dist/core/utils/building/find-entrypoints.mjs +40 -21
  59. package/dist/core/utils/building/group-entrypoints.mjs +3 -4
  60. package/dist/core/utils/building/index.mjs +7 -8
  61. package/dist/core/utils/building/internal-build.mjs +21 -21
  62. package/dist/core/utils/building/rebuild.mjs +10 -10
  63. package/dist/core/utils/cache.mjs +6 -8
  64. package/dist/core/utils/constants.mjs +3 -4
  65. package/dist/core/utils/content-scripts.mjs +3 -4
  66. package/dist/core/utils/content-security-policy.mjs +2 -5
  67. package/dist/core/utils/create-file-reloader.mjs +158 -0
  68. package/dist/core/utils/entrypoints.d.mts +10 -0
  69. package/dist/core/utils/entrypoints.mjs +6 -10
  70. package/dist/core/utils/env.mjs +24 -19
  71. package/dist/core/utils/environments/browser-environment.mjs +1 -3
  72. package/dist/core/utils/environments/environment.mjs +1 -2
  73. package/dist/core/utils/environments/extension-environment.mjs +1 -3
  74. package/dist/core/utils/environments/index.mjs +3 -4
  75. package/dist/core/utils/eslint.mjs +1 -2
  76. package/dist/core/utils/fs.mjs +23 -14
  77. package/dist/core/utils/globals.mjs +1 -2
  78. package/dist/core/utils/i18n.mjs +2 -3
  79. package/dist/core/utils/index.d.mts +2 -0
  80. package/dist/core/utils/index.mjs +3 -3
  81. package/dist/core/utils/log/index.mjs +5 -6
  82. package/dist/core/utils/log/printBuildSummary.mjs +1 -3
  83. package/dist/core/utils/log/printFileList.mjs +25 -21
  84. package/dist/core/utils/log/printHeader.mjs +3 -5
  85. package/dist/core/utils/log/printTable.mjs +1 -2
  86. package/dist/core/utils/manifest.mjs +39 -46
  87. package/dist/core/utils/number.mjs +1 -2
  88. package/dist/core/utils/package.mjs +3 -5
  89. package/dist/core/utils/paths.d.mts +2 -2
  90. package/dist/core/utils/paths.mjs +7 -9
  91. package/dist/core/utils/strings.mjs +4 -7
  92. package/dist/core/utils/syntax-errors.mjs +3 -5
  93. package/dist/core/utils/theme-icons.mjs +71 -0
  94. package/dist/core/utils/time.mjs +1 -13
  95. package/dist/core/utils/transform.mjs +9 -7
  96. package/dist/core/utils/validation.mjs +1 -2
  97. package/dist/core/utils/virtual-modules.mjs +9 -15
  98. package/dist/core/wxt.mjs +11 -12
  99. package/dist/core/zip.d.mts +1 -0
  100. package/dist/core/zip.mjs +25 -20
  101. package/dist/index.d.mts +4 -4
  102. package/dist/index.mjs +3 -3
  103. package/dist/modules.d.mts +64 -61
  104. package/dist/modules.mjs +70 -66
  105. package/dist/testing/fake-browser.mjs +1 -2
  106. package/dist/testing/wxt-vitest-plugin.d.mts +4 -2
  107. package/dist/testing/wxt-vitest-plugin.mjs +5 -7
  108. package/dist/types.d.mts +636 -450
  109. package/dist/utils/app-config.d.mts +1 -0
  110. package/dist/utils/app-config.mjs +3 -3
  111. package/dist/utils/content-script-context.d.mts +49 -39
  112. package/dist/utils/content-script-context.mjs +37 -32
  113. package/dist/utils/content-script-ui/iframe.d.mts +14 -15
  114. package/dist/utils/content-script-ui/iframe.mjs +1 -3
  115. package/dist/utils/content-script-ui/integrated.d.mts +8 -7
  116. package/dist/utils/content-script-ui/integrated.mjs +1 -3
  117. package/dist/utils/content-script-ui/shadow-root.d.mts +37 -25
  118. package/dist/utils/content-script-ui/shadow-root.mjs +5 -8
  119. package/dist/utils/content-script-ui/shared.mjs +1 -3
  120. package/dist/utils/content-script-ui/types.d.mts +29 -34
  121. package/dist/utils/content-script-ui/types.mjs +1 -1
  122. package/dist/utils/define-app-config.d.mts +4 -3
  123. package/dist/utils/define-app-config.mjs +5 -5
  124. package/dist/utils/define-background.mjs +1 -2
  125. package/dist/utils/define-content-script.mjs +1 -2
  126. package/dist/utils/define-unlisted-script.mjs +1 -2
  127. package/dist/utils/define-wxt-plugin.mjs +1 -2
  128. package/dist/utils/inject-script.d.mts +2 -2
  129. package/dist/utils/inject-script.mjs +4 -5
  130. package/dist/utils/internal/custom-events.mjs +3 -4
  131. package/dist/utils/internal/location-watcher.mjs +4 -6
  132. package/dist/utils/internal/logger.mjs +2 -5
  133. package/dist/utils/match-patterns.mjs +2 -3
  134. package/dist/utils/split-shadow-root-css.d.mts +6 -2
  135. package/dist/utils/split-shadow-root-css.mjs +7 -4
  136. package/dist/utils/storage.mjs +2 -3
  137. package/dist/version.mjs +2 -3
  138. package/dist/virtual/background-entrypoint.mjs +4 -16
  139. package/dist/virtual/content-script-isolated-world-entrypoint.mjs +2 -7
  140. package/dist/virtual/content-script-main-world-entrypoint.mjs +2 -7
  141. package/dist/virtual/mock-browser.d.mts +1 -1
  142. package/dist/virtual/mock-browser.mjs +2 -4
  143. package/dist/virtual/reload-html.mjs +3 -10
  144. package/dist/virtual/unlisted-script-entrypoint.mjs +2 -7
  145. package/package.json +56 -49
  146. package/LICENSE +0 -21
  147. package/dist/core/builders/vite/plugins/download.mjs +0 -25
  148. package/dist/core/runners/index.mjs +0 -17
  149. package/dist/core/utils/minimatch-multiple.mjs +0 -28
  150. package/dist/core/utils/network.mjs +0 -38
  151. package/dist/core/utils/wsl.mjs +0 -12
  152. package/dist/testing/index.d.mts +0 -3
  153. package/dist/testing/index.mjs +0 -4
@@ -1,5 +1,4 @@
1
1
  import { parseHTML } from "linkedom";
2
-
3
2
  //#region src/core/utils/environments/browser-environment.ts
4
3
  function getBrowserEnvironmentGlobals() {
5
4
  const { window, document, global } = parseHTML(`
@@ -15,6 +14,5 @@ function getBrowserEnvironmentGlobals() {
15
14
  self: global
16
15
  };
17
16
  }
18
-
19
17
  //#endregion
20
- export { getBrowserEnvironmentGlobals };
18
+ export { getBrowserEnvironmentGlobals };
@@ -34,6 +34,5 @@ function applyGlobals(globals) {
34
34
  } catch {}
35
35
  });
36
36
  }
37
-
38
37
  //#endregion
39
- export { createEnvironment };
38
+ export { createEnvironment };
@@ -1,7 +1,6 @@
1
1
  import { createEnvironment } from "./environment.mjs";
2
2
  import { getBrowserEnvironmentGlobals } from "./browser-environment.mjs";
3
3
  import { fakeBrowser } from "@webext-core/fake-browser";
4
-
5
4
  //#region src/core/utils/environments/extension-environment.ts
6
5
  function createExtensionEnvironment() {
7
6
  return createEnvironment(getExtensionEnvironmentGlobals);
@@ -13,6 +12,5 @@ function getExtensionEnvironmentGlobals() {
13
12
  browser: fakeBrowser
14
13
  };
15
14
  }
16
-
17
15
  //#endregion
18
- export { createExtensionEnvironment, getExtensionEnvironmentGlobals };
16
+ export { createExtensionEnvironment, getExtensionEnvironmentGlobals };
@@ -1,4 +1,3 @@
1
- import { getBrowserEnvironmentGlobals } from "./browser-environment.mjs";
2
- import { createExtensionEnvironment, getExtensionEnvironmentGlobals } from "./extension-environment.mjs";
3
-
4
- export { };
1
+ import "./browser-environment.mjs";
2
+ import "./extension-environment.mjs";
3
+ export {};
@@ -7,6 +7,5 @@ async function getEslintVersion() {
7
7
  return [];
8
8
  }
9
9
  }
10
-
11
10
  //#endregion
12
- export { getEslintVersion };
11
+ export { getEslintVersion };
@@ -1,27 +1,36 @@
1
1
  import { unnormalizePath } from "./paths.mjs";
2
2
  import { wxt } from "../wxt.mjs";
3
- import fs from "fs-extra";
4
- import glob from "fast-glob";
5
-
3
+ import { access, readFile, writeFile } from "node:fs/promises";
4
+ import { glob } from "tinyglobby";
6
5
  //#region src/core/utils/fs.ts
6
+ async function pathExists(path) {
7
+ try {
8
+ await access(path);
9
+ return true;
10
+ } catch {
11
+ return false;
12
+ }
13
+ }
14
+ async function readJson(path) {
15
+ return JSON.parse(await readFile(path, "utf-8"));
16
+ }
7
17
  /**
8
- * Only write the contents to a file if it results in a change. This prevents unnecessary file
9
- * watchers from being triggered, like WXT's dev server or the TS language server in editors.
18
+ * Only write the contents to a file if it results in a change. This prevents
19
+ * unnecessary file watchers from being triggered, like WXT's dev server or the
20
+ * TS language server in editors.
10
21
  *
11
22
  * @param file The file to write to.
12
23
  * @param newContents The new text content to write.
13
24
  */
14
25
  async function writeFileIfDifferent(file, newContents) {
15
- if (await fs.readFile(file, "utf-8").catch(() => void 0) !== newContents) await fs.writeFile(file, newContents);
26
+ if (await readFile(file, "utf-8").catch(() => void 0) !== newContents) await writeFile(file, newContents);
16
27
  }
17
- /**
18
- * Get all the files in the project's public directory. Returned paths are relative to the
19
- * `config.publicDir`.
20
- */
21
28
  async function getPublicFiles() {
22
- if (!await fs.pathExists(wxt.config.publicDir)) return [];
23
- return (await glob("**/*", { cwd: wxt.config.publicDir })).map(unnormalizePath);
29
+ if (!await pathExists(wxt.config.publicDir)) return [];
30
+ return (await glob("**/*", {
31
+ cwd: wxt.config.publicDir,
32
+ expandDirectories: false
33
+ })).map(unnormalizePath);
24
34
  }
25
-
26
35
  //#endregion
27
- export { getPublicFiles, writeFileIfDifferent };
36
+ export { getPublicFiles, pathExists, readJson, writeFileIfDifferent };
@@ -50,6 +50,5 @@ function getEntrypointGlobals(entrypointName) {
50
50
  type: `string`
51
51
  }];
52
52
  }
53
-
54
53
  //#endregion
55
- export { getEntrypointGlobals, getGlobals };
54
+ export { getEntrypointGlobals, getGlobals };
@@ -2,7 +2,7 @@
2
2
  const predefinedMessages = {
3
3
  "@@extension_id": {
4
4
  message: "<browser.runtime.id>",
5
- description: "The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message.\nNote: You can't use this message in a manifest file."
5
+ description: "The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even non-localized extensions can use this message.\nNote: You can't use this message in a manifest file."
6
6
  },
7
7
  "@@ui_locale": {
8
8
  message: "<browser.i18n.getUiLocale()>",
@@ -39,6 +39,5 @@ function parseI18nMessages(messagesJson) {
39
39
  ...details
40
40
  }));
41
41
  }
42
-
43
42
  //#endregion
44
- export { parseI18nMessages };
43
+ export { parseI18nMessages };
@@ -0,0 +1,2 @@
1
+ import { normalizePath } from "./paths.mjs";
2
+ import { getEntrypointBundlePath } from "./entrypoints.mjs";
@@ -1,3 +1,3 @@
1
- import { normalizePath } from "./paths.mjs";
2
-
3
- export { };
1
+ import "./paths.mjs";
2
+ import "./entrypoints.mjs";
3
+ export {};
@@ -1,6 +1,5 @@
1
- import { printTable } from "./printTable.mjs";
2
- import { printFileList } from "./printFileList.mjs";
3
- import { printBuildSummary } from "./printBuildSummary.mjs";
4
- import { printHeader } from "./printHeader.mjs";
5
-
6
- export { };
1
+ import "./printTable.mjs";
2
+ import "./printFileList.mjs";
3
+ import "./printBuildSummary.mjs";
4
+ import "./printHeader.mjs";
5
+ export {};
@@ -1,7 +1,6 @@
1
1
  import { wxt } from "../../wxt.mjs";
2
2
  import { printFileList } from "./printFileList.mjs";
3
3
  import { resolve } from "path";
4
-
5
4
  //#region src/core/utils/log/printBuildSummary.ts
6
5
  async function printBuildSummary(log, header, output) {
7
6
  const files = [...output.steps.flatMap((step) => step.chunks), ...output.publicAssets].sort((l, r) => {
@@ -22,6 +21,5 @@ const CHUNK_SORT_WEIGHTS = {
22
21
  function getChunkSortWeight(filename) {
23
22
  return Object.entries(CHUNK_SORT_WEIGHTS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_SORT_WEIGHT;
24
23
  }
25
-
26
24
  //#endregion
27
- export { printBuildSummary };
25
+ export { printBuildSummary };
@@ -1,39 +1,43 @@
1
+ import { wxt } from "../../wxt.mjs";
1
2
  import { printTable } from "./printTable.mjs";
2
- import fs from "fs-extra";
3
+ import { lstat } from "node:fs/promises";
3
4
  import path from "node:path";
4
- import pc from "picocolors";
5
+ import { styleText } from "node:util";
5
6
  import { filesize } from "filesize";
6
-
7
7
  //#region src/core/utils/log/printFileList.ts
8
8
  async function printFileList(log, header, baseDir, files) {
9
9
  let totalSize = 0;
10
10
  const fileRows = await Promise.all(files.map(async (file, i) => {
11
11
  const parts = [path.relative(process.cwd(), baseDir) + path.sep, path.relative(baseDir, file)];
12
12
  const prefix = i === files.length - 1 ? " └─" : " ├─";
13
- const color = getChunkColor(file);
14
- const stats = await fs.lstat(file);
15
- totalSize += stats.size;
16
- const size = String(filesize(stats.size));
17
- return [`${pc.gray(prefix)} ${pc.dim(parts[0])}${color(parts[1])}`, pc.dim(size)];
13
+ const chunkColor = getChunkColor(file);
14
+ let size = "";
15
+ try {
16
+ const stats = await lstat(file);
17
+ totalSize += stats.size;
18
+ size = String(filesize(stats.size));
19
+ } catch (ex) {
20
+ wxt.logger.warn(`Could not get stats of '${file}' error: ${ex}`);
21
+ }
22
+ return [`${styleText("gray", prefix)} ${styleText("dim", parts[0])}${styleText(chunkColor, parts[1])}`, styleText("dim", size)];
18
23
  }));
19
- fileRows.push([`${pc.cyan("Σ Total size:")} ${String(filesize(totalSize))}`]);
24
+ fileRows.push([`${styleText("cyan", "Σ Total size:")} ${String(filesize(totalSize))}`]);
20
25
  printTable(log, header, fileRows);
21
26
  }
22
- const DEFAULT_COLOR = pc.blue;
27
+ const DEFAULT_COLOR = "blue";
23
28
  const CHUNK_COLORS = {
24
- ".js.map": pc.gray,
25
- ".cjs.map": pc.gray,
26
- ".mjs.map": pc.gray,
27
- ".html": pc.green,
28
- ".css": pc.magenta,
29
- ".js": pc.cyan,
30
- ".cjs": pc.cyan,
31
- ".mjs": pc.cyan,
32
- ".zip": pc.yellow
29
+ ".js.map": "gray",
30
+ ".cjs.map": "gray",
31
+ ".mjs.map": "gray",
32
+ ".html": "green",
33
+ ".css": "magenta",
34
+ ".js": "cyan",
35
+ ".cjs": "cyan",
36
+ ".mjs": "cyan",
37
+ ".zip": "yellow"
33
38
  };
34
39
  function getChunkColor(filename) {
35
40
  return Object.entries(CHUNK_COLORS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_COLOR;
36
41
  }
37
-
38
42
  //#endregion
39
- export { printFileList };
43
+ export { printFileList };
@@ -1,11 +1,9 @@
1
1
  import { version } from "../../../version.mjs";
2
2
  import { consola as consola$1 } from "consola";
3
- import pc from "picocolors";
4
-
3
+ import { styleText } from "node:util";
5
4
  //#region src/core/utils/log/printHeader.ts
6
5
  function printHeader() {
7
- consola$1.log(`\n${pc.gray("WXT")} ${pc.gray(pc.bold(version))}`);
6
+ consola$1.log(`\n${styleText("gray", "WXT")} ${styleText(["bold", "gray"], version)}`);
8
7
  }
9
-
10
8
  //#endregion
11
- export { printHeader };
9
+ export { printHeader };
@@ -15,6 +15,5 @@ function printTable(log, header, rows, gap = 2) {
15
15
  });
16
16
  log(`${header}\n${str}`);
17
17
  }
18
-
19
18
  //#endregion
20
- export { printTable };
19
+ export { printTable };
@@ -5,26 +5,22 @@ import { writeFileIfDifferent } from "./fs.mjs";
5
5
  import { ContentSecurityPolicy } from "./content-security-policy.mjs";
6
6
  import { hashContentScriptOptions, mapWxtOptionsToContentScript } from "./content-scripts.mjs";
7
7
  import { getPackageJson } from "./package.mjs";
8
- import fs from "fs-extra";
8
+ import { addDiscoveredThemeIcons } from "./theme-icons.mjs";
9
+ import { mkdir } from "node:fs/promises";
9
10
  import { resolve } from "path";
10
11
  import defu from "defu";
11
-
12
12
  //#region src/core/utils/manifest.ts
13
- /**
14
- * Writes the manifest to the output directory and the build output.
15
- */
13
+ /** Writes the manifest to the output directory and the build output. */
16
14
  async function writeManifest(manifest, output) {
17
15
  const str = wxt.config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
18
- await fs.ensureDir(wxt.config.outDir);
16
+ await mkdir(wxt.config.outDir, { recursive: true });
19
17
  await writeFileIfDifferent(resolve(wxt.config.outDir, "manifest.json"), str);
20
18
  output.publicAssets.unshift({
21
19
  type: "asset",
22
20
  fileName: "manifest.json"
23
21
  });
24
22
  }
25
- /**
26
- * Generates the manifest based on the config and entrypoints.
27
- */
23
+ /** Generates the manifest based on the config and entrypoints. */
28
24
  async function generateManifest(allEntrypoints, buildOutput) {
29
25
  const entrypoints = allEntrypoints.filter((entry) => !entry.skipped);
30
26
  const warnings = [];
@@ -59,7 +55,10 @@ async function generateManifest(allEntrypoints, buildOutput) {
59
55
  }
60
56
  manifest.version = version;
61
57
  manifest.version_name = wxt.config.browser === "firefox" || versionName === version ? void 0 : versionName;
58
+ if (wxt.config.browser === "firefox" && !userManifest.browser_specific_settings?.gecko?.data_collection_permissions && !wxt.config.suppressWarnings?.firefoxDataCollection) wxt.logger.warn("Firefox requires `data_collection_permissions` for new extensions from November 3, 2025. Existing extensions are exempt for now.\nFor more details, see: https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/\nTo suppress this warning, set `suppressWarnings.firefoxDataCollection` to `true` in your wxt config.\n");
59
+ if (wxt.config.browser === "firefox" && !manifest.browser_specific_settings?.gecko?.id && !wxt.config.suppressWarnings?.firefoxId) wxt.logger.warn("Firefox requires extension ID for MV3 and recommends it for MV2.\nFor more details, see: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings#id");
62
60
  addEntrypoints(manifest, entrypoints, buildOutput);
61
+ if (wxt.config.browser === "firefox") addDiscoveredThemeIcons(manifest, buildOutput);
63
62
  if (wxt.config.command === "serve") addDevModeCsp(manifest);
64
63
  if (wxt.config.command === "serve") addDevModePermissions(manifest);
65
64
  await wxt.hooks.callHook("build:manifestGenerated", wxt, manifest);
@@ -79,8 +78,9 @@ async function generateManifest(allEntrypoints, buildOutput) {
79
78
  };
80
79
  }
81
80
  /**
82
- * Removes suffixes from the version, like X.Y.Z-alpha1 (which browsers don't allow), so it's a
83
- * simple version number, like X or X.Y or X.Y.Z, which browsers allow.
81
+ * Removes suffixes from the version, like X.Y.Z-alpha1 (which browsers don't
82
+ * allow), so it's a simple version number, like X or X.Y or X.Y.Z, which
83
+ * browsers allow.
84
84
  */
85
85
  function simplifyVersion(versionName) {
86
86
  const version = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(versionName)?.[1];
@@ -137,28 +137,22 @@ function addEntrypoints(manifest, entrypoints, buildOutput) {
137
137
  const options = {};
138
138
  if (popup.options.defaultIcon) options.default_icon = popup.options.defaultIcon;
139
139
  if (popup.options.defaultTitle) options.default_title = popup.options.defaultTitle;
140
+ if (popup.options.defaultState && wxt.config.manifestVersion === 3) options.default_state = popup.options.defaultState;
140
141
  if (popup.options.browserStyle) options.browser_style = popup.options.browserStyle;
141
142
  if (popup.options.defaultArea) options.default_area = popup.options.defaultArea;
142
143
  if (popup.options.themeIcons) options.theme_icons = popup.options.themeIcons;
143
- if (manifest.manifest_version === 3) manifest.action = {
144
- ...manifest.action,
144
+ const actionKey = wxt.config.manifestVersion === 2 ? popup.options.actionType ?? "browser_action" : wxt.config.browser === "firefox" && popup.options.actionType === "page_action" ? "page_action" : "action";
145
+ manifest[actionKey] = {
146
+ ...manifest[actionKey],
145
147
  ...options,
146
148
  default_popup
147
149
  };
148
- else {
149
- const key = popup.options.mv2Key ?? "browser_action";
150
- manifest[key] = {
151
- ...manifest[key],
152
- ...options,
153
- default_popup
154
- };
155
- }
156
150
  }
157
151
  if (devtools) manifest.devtools_page = getEntrypointBundlePath(devtools, wxt.config.outDir, ".html");
158
152
  if (options) {
159
153
  const page = getEntrypointBundlePath(options, wxt.config.outDir, ".html");
160
154
  manifest.options_ui = {
161
- open_in_tab: options.options.openInTab,
155
+ ...wxt.config.browser !== "safari" && { open_in_tab: options.options.openInTab ?? false },
162
156
  browser_style: wxt.config.browser === "firefox" ? options.options.browserStyle : void 0,
163
157
  chrome_style: wxt.config.browser !== "firefox" ? options.options.chromeStyle : void 0,
164
158
  page
@@ -247,9 +241,9 @@ function addDevModeCsp(manifest) {
247
241
  }
248
242
  const permission = `${permissionUrl}*`;
249
243
  const allowedCsp = wxt.server?.origin ?? "http://localhost:*";
250
- if (manifest.manifest_version === 3) addHostPermission(manifest, permission);
244
+ if (wxt.config.manifestVersion === 3) addHostPermission(manifest, permission);
251
245
  else addPermission(manifest, permission);
252
- const extensionPagesCsp = new ContentSecurityPolicy(manifest.content_security_policy?.extension_pages ?? (manifest.manifest_version === 3 ? DEFAULT_MV3_EXTENSION_PAGES_CSP : DEFAULT_MV2_CSP));
246
+ const extensionPagesCsp = new ContentSecurityPolicy(manifest.content_security_policy?.extension_pages ?? (wxt.config.manifestVersion === 3 ? DEFAULT_MV3_EXTENSION_PAGES_CSP : DEFAULT_MV2_CSP));
253
247
  const sandboxCsp = new ContentSecurityPolicy(manifest.content_security_policy?.sandbox ?? DEFAULT_MV3_SANDBOX_CSP);
254
248
  if (wxt.config.command === "serve") {
255
249
  extensionPagesCsp.add("script-src", allowedCsp);
@@ -264,8 +258,8 @@ function addDevModePermissions(manifest) {
264
258
  if (wxt.config.manifestVersion === 3) addPermission(manifest, "scripting");
265
259
  }
266
260
  /**
267
- * Returns the bundle paths to CSS files associated with a list of content scripts, or undefined if
268
- * there is no associated CSS.
261
+ * Returns the bundle paths to CSS files associated with a list of content
262
+ * scripts, or undefined if there is no associated CSS.
269
263
  */
270
264
  function getContentScriptCssFiles(contentScripts, contentScriptCssMap) {
271
265
  const css = [];
@@ -278,9 +272,9 @@ function getContentScriptCssFiles(contentScripts, contentScriptCssMap) {
278
272
  if (css.length > 0) return css;
279
273
  }
280
274
  /**
281
- * Content scripts configured with `cssInjectionMode: "ui"` need to add their CSS files to web
282
- * accessible resources so they can be fetched as text and added to shadow roots that the UI is
283
- * added to.
275
+ * Content scripts configured with `cssInjectionMode: "ui"` need to add their
276
+ * CSS files to web accessible resources so they can be fetched as text and
277
+ * added to shadow roots that the UI is added to.
284
278
  */
285
279
  function getContentScriptCssWebAccessibleResources(contentScripts, contentScriptCssMap) {
286
280
  const resources = [];
@@ -297,8 +291,8 @@ function getContentScriptCssWebAccessibleResources(contentScripts, contentScript
297
291
  return resources;
298
292
  }
299
293
  /**
300
- * Based on the build output, return a Record of each content script's name to it CSS file if the
301
- * script includes one.
294
+ * Based on the build output, return a Record of each content script's name to
295
+ * it CSS file if the script includes one.
302
296
  */
303
297
  function getContentScriptsCssMap(buildOutput, scripts) {
304
298
  const map = {};
@@ -320,8 +314,8 @@ function addHostPermission(manifest, hostPermission) {
320
314
  manifest.host_permissions.push(hostPermission);
321
315
  }
322
316
  /**
323
- * - "<all_urls>" &rarr; "<all_urls>"
324
- * - "*://play.google.com/books/*" &rarr; "*://play.google.com/*"
317
+ * - "<all_urls>" "<all_urls>"
318
+ * - "_://play.google.com/books/_" "_://play.google.com/_"
325
319
  */
326
320
  function stripPathFromMatchPattern(pattern) {
327
321
  const protocolSepIndex = pattern.indexOf("://");
@@ -330,9 +324,10 @@ function stripPathFromMatchPattern(pattern) {
330
324
  return pattern.substring(0, startOfPath) + "/*";
331
325
  }
332
326
  /**
333
- * Converts all MV3 web accessible resources to their MV2 forms. MV3 web accessible resources are
334
- * generated in this file, and may be defined by the user in their manifest. In both cases, when
335
- * targeting MV2, automatically convert their definitions down to the basic MV2 array.
327
+ * Converts all MV3 web accessible resources to their MV2 forms. MV3 web
328
+ * accessible resources are generated in this file, and may be defined by the
329
+ * user in their manifest. In both cases, when targeting MV2, automatically
330
+ * convert their definitions down to the basic MV2 array.
336
331
  */
337
332
  function convertWebAccessibleResourcesToMv2(manifest) {
338
333
  if (manifest.web_accessible_resources == null) return;
@@ -354,29 +349,27 @@ function convertCspToMv2(manifest) {
354
349
  if (typeof manifest.content_security_policy === "string" || manifest.content_security_policy?.extension_pages == null) return;
355
350
  manifest.content_security_policy = manifest.content_security_policy.extension_pages;
356
351
  }
357
- /**
358
- * Make sure all resources are in MV3 format. If not, add a warning.
359
- */
352
+ /** Make sure all resources are in MV3 format. If not, add a warning. */
360
353
  function validateMv3WebAccessibleResources(manifest) {
361
354
  if (manifest.web_accessible_resources == null) return;
362
355
  const stringResources = manifest.web_accessible_resources.filter((item) => typeof item === "string");
363
356
  if (stringResources.length > 0) throw Error(`Non-MV3 web_accessible_resources detected: ${JSON.stringify(stringResources)}. When manually defining web_accessible_resources, define them as MV3 objects ({ matches: [...], resources: [...] }), and WXT will automatically convert them to MV2 when necessary.`);
364
357
  }
365
- /**
366
- * Remove keys from the manifest based on the build target.
367
- */
358
+ /** Remove keys from the manifest based on the build target. */
368
359
  function stripKeys(manifest) {
369
360
  let keysToRemove = [];
370
361
  if (wxt.config.manifestVersion === 2) {
371
362
  keysToRemove.push(...mv3OnlyKeys);
372
363
  if (wxt.config.browser === "firefox") keysToRemove.push(...firefoxMv3OnlyKeys);
373
- } else keysToRemove.push(...mv2OnlyKeys);
364
+ } else {
365
+ keysToRemove.push(...mv2OnlyKeys);
366
+ if (wxt.config.browser !== "firefox") keysToRemove.push(...chromeMv2OnlyKeys);
367
+ }
374
368
  keysToRemove.forEach((key) => {
375
369
  delete manifest[key];
376
370
  });
377
371
  }
378
372
  const mv2OnlyKeys = [
379
- "page_action",
380
373
  "browser_action",
381
374
  "automation",
382
375
  "content_capabilities",
@@ -400,10 +393,10 @@ const mv3OnlyKeys = [
400
393
  "optional_host_permissions",
401
394
  "side_panel"
402
395
  ];
396
+ const chromeMv2OnlyKeys = ["page_action"];
403
397
  const firefoxMv3OnlyKeys = ["host_permissions"];
404
398
  const DEFAULT_MV3_EXTENSION_PAGES_CSP = "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';";
405
399
  const DEFAULT_MV3_SANDBOX_CSP = "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';";
406
400
  const DEFAULT_MV2_CSP = "script-src 'self'; object-src 'self';";
407
-
408
401
  //#endregion
409
- export { generateManifest, getContentScriptCssFiles, getContentScriptsCssMap, writeManifest };
402
+ export { generateManifest, getContentScriptCssFiles, getContentScriptsCssMap, writeManifest };
@@ -3,6 +3,5 @@ function safeStringToNumber(str) {
3
3
  const num = Number(str);
4
4
  return isNaN(num) ? null : num;
5
5
  }
6
-
7
6
  //#endregion
8
- export { safeStringToNumber };
7
+ export { safeStringToNumber };
@@ -1,7 +1,6 @@
1
1
  import { wxt } from "../wxt.mjs";
2
- import fs from "fs-extra";
2
+ import { readJson } from "./fs.mjs";
3
3
  import { resolve } from "node:path";
4
-
5
4
  //#region src/core/utils/package.ts
6
5
  /**
7
6
  * Read the project's package.json.
@@ -11,12 +10,11 @@ import { resolve } from "node:path";
11
10
  async function getPackageJson() {
12
11
  const file = resolve(wxt.config.root, "package.json");
13
12
  try {
14
- return await fs.readJson(file);
13
+ return await readJson(file);
15
14
  } catch (err) {
16
15
  wxt.logger.debug(`Failed to read package.json at: ${file}. Returning undefined.`, err);
17
16
  return {};
18
17
  }
19
18
  }
20
-
21
19
  //#endregion
22
- export { getPackageJson };
20
+ export { getPackageJson };
@@ -1,7 +1,7 @@
1
1
  //#region src/core/utils/paths.d.ts
2
2
  /**
3
- * Converts system paths to normalized bundler path.
4
- * On Windows, this returns paths with `/` instead of `\`.
3
+ * Converts system paths to normalized bundler path. On Windows, this returns
4
+ * paths with `/` instead of `\`.
5
5
  */
6
6
  declare function normalizePath(path: string): string;
7
7
  //#endregion
@@ -1,29 +1,27 @@
1
1
  import path from "node:path";
2
2
  import normalize from "normalize-path";
3
-
4
3
  //#region src/core/utils/paths.ts
5
4
  /**
6
- * Converts system paths to normalized bundler path.
7
- * On Windows, this returns paths with `/` instead of `\`.
5
+ * Converts system paths to normalized bundler path. On Windows, this returns
6
+ * paths with `/` instead of `\`.
8
7
  */
9
8
  function normalizePath(path) {
10
9
  return normalize(path);
11
10
  }
12
11
  /**
13
- * Given a normalized path, convert it to the system path style. On Windows, switch to \, otherwise use /.
12
+ * Given a normalized path, convert it to the system path style. On Windows,
13
+ * switch to , otherwise use /.
14
14
  */
15
15
  function unnormalizePath(path$1) {
16
16
  return path.normalize(path$1);
17
17
  }
18
- const CSS_EXTENSIONS = [
18
+ const CSS_EXTENSIONS_PATTERN = `+(${[
19
19
  "css",
20
20
  "scss",
21
21
  "sass",
22
22
  "less",
23
23
  "styl",
24
24
  "stylus"
25
- ];
26
- const CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
27
-
25
+ ].join("|")})`;
28
26
  //#endregion
29
- export { CSS_EXTENSIONS_PATTERN, normalizePath, unnormalizePath };
27
+ export { CSS_EXTENSIONS_PATTERN, normalizePath, unnormalizePath };
@@ -1,23 +1,20 @@
1
1
  import { camelCase } from "scule";
2
-
3
2
  //#region src/core/utils/strings.ts
4
3
  function kebabCaseAlphanumeric(str) {
5
4
  return str.toLowerCase().replace(/[^a-z0-9-\s]/g, "").replace(/\s+/g, "-");
6
5
  }
7
- /**
8
- * Return a safe variable name for a given string.
9
- */
6
+ /** Return a safe variable name for a given string. */
10
7
  function safeVarName(str) {
11
8
  const name = camelCase(kebabCaseAlphanumeric(str));
12
9
  if (name.match(/^[a-z]/)) return name;
13
10
  return "_" + name;
14
11
  }
15
12
  /**
16
- * Converts a string to a valid filename (NOT path), stripping out invalid characters.
13
+ * Converts a string to a valid filename (NOT path), stripping out invalid
14
+ * characters.
17
15
  */
18
16
  function safeFilename(str) {
19
17
  return kebabCaseAlphanumeric(str);
20
18
  }
21
-
22
19
  //#endregion
23
- export { safeFilename, safeVarName };
20
+ export { safeFilename, safeVarName };
@@ -1,7 +1,6 @@
1
1
  import { wxt } from "../wxt.mjs";
2
2
  import { relative } from "node:path";
3
- import pc from "picocolors";
4
-
3
+ import { styleText } from "node:util";
5
4
  //#region src/core/utils/syntax-errors.ts
6
5
  function isBabelSyntaxError(error) {
7
6
  return error instanceof SyntaxError && error.code === "BABEL_PARSER_SYNTAX_ERROR";
@@ -10,9 +9,8 @@ function logBabelSyntaxError(error) {
10
9
  let filename = relative(wxt.config.root, error.id);
11
10
  if (filename.startsWith("..")) filename = error.id;
12
11
  let message = error.message.replace(/\(\d+:\d+\)$/, `(${filename}:${error.loc.line}:${error.loc.column + 1})`);
13
- if (error.frame) message += "\n\n" + pc.red(error.frame);
12
+ if (error.frame) message += "\n\n" + styleText("red", error.frame);
14
13
  wxt.logger.error(message);
15
14
  }
16
-
17
15
  //#endregion
18
- export { isBabelSyntaxError, logBabelSyntaxError };
16
+ export { isBabelSyntaxError, logBabelSyntaxError };