wxt 0.17.4 → 0.17.6

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/dist/cli.js CHANGED
@@ -13,21 +13,229 @@ import glob from "fast-glob";
13
13
  // src/core/utils/paths.ts
14
14
  import systemPath from "node:path";
15
15
  import normalize from "normalize-path";
16
- function normalizePath(path8) {
17
- return normalize(path8);
16
+ function normalizePath(path10) {
17
+ return normalize(path10);
18
18
  }
19
- function unnormalizePath(path8) {
20
- return systemPath.normalize(path8);
19
+ function unnormalizePath(path10) {
20
+ return systemPath.normalize(path10);
21
21
  }
22
22
  var CSS_EXTENSIONS = ["css", "scss", "sass", "less", "styl", "stylus"];
23
23
  var CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
24
24
 
25
25
  // src/core/wxt.ts
26
26
  import { createHooks } from "hookable";
27
+
28
+ // src/core/package-managers/index.ts
29
+ import {
30
+ detectPackageManager,
31
+ addDependency,
32
+ addDevDependency,
33
+ ensureDependencyInstalled,
34
+ installDependencies,
35
+ removeDependency
36
+ } from "nypm";
37
+
38
+ // src/core/package-managers/npm.ts
39
+ import path from "node:path";
40
+ import { ensureDir } from "fs-extra";
41
+ var npm = {
42
+ overridesKey: "overrides",
43
+ async downloadDependency(id, downloadDir) {
44
+ await ensureDir(downloadDir);
45
+ const { execa } = await import("./execa-Y2EWTC4S.js");
46
+ const res = await execa("npm", ["pack", id, "--json"], {
47
+ cwd: downloadDir
48
+ });
49
+ const packed = JSON.parse(res.stdout);
50
+ return path.resolve(downloadDir, packed[0].filename);
51
+ },
52
+ async listDependencies(options) {
53
+ const args = ["ls", "--json"];
54
+ if (options?.all) {
55
+ args.push("--depth", "Infinity");
56
+ }
57
+ const { execa } = await import("./execa-Y2EWTC4S.js");
58
+ const res = await execa("npm", args, { cwd: options?.cwd });
59
+ const project = JSON.parse(res.stdout);
60
+ return flattenNpmListOutput([project]);
61
+ }
62
+ };
63
+ function flattenNpmListOutput(projects) {
64
+ const queue = projects.flatMap(
65
+ (project) => {
66
+ const acc = [];
67
+ if (project.dependencies)
68
+ acc.push(project.dependencies);
69
+ if (project.devDependencies)
70
+ acc.push(project.devDependencies);
71
+ return acc;
72
+ }
73
+ );
74
+ const dependencies = [];
75
+ while (queue.length > 0) {
76
+ Object.entries(queue.pop()).forEach(([name, meta]) => {
77
+ dependencies.push({
78
+ name,
79
+ version: meta.version
80
+ });
81
+ if (meta.dependencies)
82
+ queue.push(meta.dependencies);
83
+ if (meta.devDependencies)
84
+ queue.push(meta.devDependencies);
85
+ });
86
+ }
87
+ return dedupeDependencies(dependencies);
88
+ }
89
+ function dedupeDependencies(dependencies) {
90
+ const hashes = /* @__PURE__ */ new Set();
91
+ return dependencies.filter((dep) => {
92
+ const hash = `${dep.name}@${dep.version}`;
93
+ if (hashes.has(hash)) {
94
+ return false;
95
+ } else {
96
+ hashes.add(hash);
97
+ return true;
98
+ }
99
+ });
100
+ }
101
+
102
+ // src/core/package-managers/bun.ts
103
+ var bun = {
104
+ overridesKey: "overrides",
105
+ // But also supports "resolutions"
106
+ downloadDependency(...args) {
107
+ return npm.downloadDependency(...args);
108
+ },
109
+ async listDependencies(options) {
110
+ const args = ["pm", "ls"];
111
+ if (options?.all) {
112
+ args.push("--all");
113
+ }
114
+ const { execa } = await import("./execa-Y2EWTC4S.js");
115
+ const res = await execa("bun", args, { cwd: options?.cwd });
116
+ return dedupeDependencies(
117
+ res.stdout.split("\n").slice(1).map((line) => line.trim()).map((line) => /.* (@?\S+)@(\S+)$/.exec(line)).filter((match) => !!match).map(([_, name, version2]) => ({ name, version: version2 }))
118
+ );
119
+ }
120
+ };
121
+
122
+ // src/core/package-managers/yarn.ts
123
+ var yarn = {
124
+ overridesKey: "resolutions",
125
+ downloadDependency(...args) {
126
+ return npm.downloadDependency(...args);
127
+ },
128
+ async listDependencies(options) {
129
+ const args = ["list", "--json"];
130
+ if (options?.all) {
131
+ args.push("--depth", "Infinity");
132
+ }
133
+ const { execa } = await import("./execa-Y2EWTC4S.js");
134
+ const res = await execa("yarn", args, { cwd: options?.cwd });
135
+ const tree = res.stdout.split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
136
+ if (tree == null)
137
+ throw Error("'yarn list --json' did not output a tree");
138
+ const queue = [...tree.trees];
139
+ const dependencies = [];
140
+ while (queue.length > 0) {
141
+ const { name: treeName, children } = queue.pop();
142
+ const match = /(@?\S+)@(\S+)$/.exec(treeName);
143
+ if (match) {
144
+ const [_, name, version2] = match;
145
+ dependencies.push({ name, version: version2 });
146
+ }
147
+ if (children != null) {
148
+ queue.push(...children);
149
+ }
150
+ }
151
+ return dedupeDependencies(dependencies);
152
+ }
153
+ };
154
+
155
+ // src/core/package-managers/pnpm.ts
156
+ var pnpm = {
157
+ overridesKey: "resolutions",
158
+ // "pnpm.overrides" has a higher priority, but I don't want to deal with nesting
159
+ downloadDependency(...args) {
160
+ return npm.downloadDependency(...args);
161
+ },
162
+ async listDependencies(options) {
163
+ const args = ["ls", "-r", "--json"];
164
+ if (options?.all) {
165
+ args.push("--depth", "Infinity");
166
+ }
167
+ if (typeof process !== "undefined" && process.env.WXT_PNPM_IGNORE_WORKSPACE === "true") {
168
+ args.push("--ignore-workspace");
169
+ }
170
+ const { execa } = await import("./execa-Y2EWTC4S.js");
171
+ const res = await execa("pnpm", args, { cwd: options?.cwd });
172
+ const projects = JSON.parse(res.stdout);
173
+ return flattenNpmListOutput(projects);
174
+ }
175
+ };
176
+
177
+ // src/core/package-managers/index.ts
178
+ async function createWxtPackageManager(root) {
179
+ const pm = await detectPackageManager(root, {
180
+ includeParentDirs: true
181
+ });
182
+ const requirePm = (cb) => {
183
+ if (pm == null)
184
+ throw Error("Could not detect package manager");
185
+ return cb(pm);
186
+ };
187
+ return {
188
+ get name() {
189
+ return requirePm((pm2) => pm2.name);
190
+ },
191
+ get command() {
192
+ return requirePm((pm2) => pm2.command);
193
+ },
194
+ get version() {
195
+ return requirePm((pm2) => pm2.version);
196
+ },
197
+ get majorVersion() {
198
+ return requirePm((pm2) => pm2.majorVersion);
199
+ },
200
+ get lockFile() {
201
+ return requirePm((pm2) => pm2.lockFile);
202
+ },
203
+ get files() {
204
+ return requirePm((pm2) => pm2.files);
205
+ },
206
+ addDependency,
207
+ addDevDependency,
208
+ ensureDependencyInstalled,
209
+ installDependencies,
210
+ removeDependency,
211
+ get overridesKey() {
212
+ return requirePm((pm2) => packageManagers[pm2.name].overridesKey);
213
+ },
214
+ downloadDependency(...args) {
215
+ return requirePm(
216
+ (pm2) => packageManagers[pm2.name].downloadDependency(...args)
217
+ );
218
+ },
219
+ listDependencies(...args) {
220
+ return requirePm(
221
+ (pm2) => packageManagers[pm2.name].listDependencies(...args)
222
+ );
223
+ }
224
+ };
225
+ }
226
+ var packageManagers = {
227
+ npm,
228
+ pnpm,
229
+ bun,
230
+ yarn
231
+ };
232
+
233
+ // src/core/wxt.ts
27
234
  var wxt;
28
235
  async function registerWxt(command, inlineConfig = {}, server) {
29
236
  const config = await resolveConfig(inlineConfig, command, server);
30
237
  const hooks = createHooks();
238
+ const pm = await createWxtPackageManager(config.root);
31
239
  wxt = {
32
240
  config,
33
241
  hooks,
@@ -36,7 +244,8 @@ async function registerWxt(command, inlineConfig = {}, server) {
36
244
  },
37
245
  async reloadConfig() {
38
246
  wxt.config = await resolveConfig(inlineConfig, command, server);
39
- }
247
+ },
248
+ pm
40
249
  };
41
250
  wxt.hooks.addHooks(config.hooks);
42
251
  await wxt.hooks.callHook("ready", wxt);
@@ -212,9 +421,9 @@ import JSON5 from "json5";
212
421
  import glob2 from "fast-glob";
213
422
 
214
423
  // src/core/utils/entrypoints.ts
215
- import path, { relative, resolve as resolve2 } from "node:path";
424
+ import path2, { relative, resolve as resolve2 } from "node:path";
216
425
  function getEntrypointName(entrypointsDir, inputPath) {
217
- const relativePath = path.relative(entrypointsDir, inputPath);
426
+ const relativePath = path2.relative(entrypointsDir, inputPath);
218
427
  const name = relativePath.split(/[\.\/\\]/, 2)[0];
219
428
  return name;
220
429
  }
@@ -258,7 +467,7 @@ async function findEntrypoints() {
258
467
  const inputPath = resolve3(wxt.config.entrypointsDir, relativePath);
259
468
  const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
260
469
  const matchingGlob = pathGlobs.find(
261
- (glob5) => minimatch(relativePath, glob5)
470
+ (glob6) => minimatch(relativePath, glob6)
262
471
  );
263
472
  if (matchingGlob) {
264
473
  const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
@@ -673,7 +882,7 @@ function getEntrypointGlobals(entrypointName) {
673
882
  }
674
883
 
675
884
  // src/core/utils/building/generate-wxt-dir.ts
676
- import path2 from "node:path";
885
+ import path3 from "node:path";
677
886
 
678
887
  // src/core/utils/i18n.ts
679
888
  var predefinedMessages = {
@@ -756,7 +965,7 @@ async function writePathsDeclarationFile(entrypoints) {
756
965
  wxt.config.outDir,
757
966
  isHtmlEntrypoint(entry) ? ".html" : ".js"
758
967
  )
759
- ).concat(await getPublicFiles()).map(normalizePath).map((path8) => ` | "/${path8}"`).sort().join("\n");
968
+ ).concat(await getPublicFiles()).map(normalizePath).map((path10) => ` | "/${path10}"`).sort().join("\n");
760
969
  const template = `// Generated by wxt
761
970
  import "wxt/browser";
762
971
 
@@ -800,7 +1009,7 @@ declare module "wxt/browser" {
800
1009
  `;
801
1010
  let messages;
802
1011
  if (defaultLocale) {
803
- const defaultLocalePath = path2.resolve(
1012
+ const defaultLocalePath = path3.resolve(
804
1013
  wxt.config.publicDir,
805
1014
  "_locales",
806
1015
  defaultLocale,
@@ -864,7 +1073,7 @@ async function writeMainDeclarationFile(references) {
864
1073
  }
865
1074
  async function writeTsConfigFile(mainReference) {
866
1075
  const dir = wxt.config.wxtDir;
867
- const getTsconfigPath = (path8) => normalizePath(relative3(dir, path8));
1076
+ const getTsconfigPath = (path10) => normalizePath(relative3(dir, path10));
868
1077
  const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
869
1078
  const aliasPath = getTsconfigPath(absolutePath);
870
1079
  return [
@@ -900,23 +1109,23 @@ ${paths}
900
1109
 
901
1110
  // src/core/utils/building/resolve-config.ts
902
1111
  import { loadConfig } from "c12";
903
- import path4 from "node:path";
1112
+ import path5 from "node:path";
904
1113
 
905
1114
  // src/core/utils/cache.ts
906
- import fs5, { ensureDir } from "fs-extra";
1115
+ import fs5, { ensureDir as ensureDir2 } from "fs-extra";
907
1116
  import { dirname as dirname2, resolve as resolve5 } from "path";
908
1117
  function createFsCache(wxtDir) {
909
1118
  const getPath = (key) => resolve5(wxtDir, "cache", encodeURIComponent(key));
910
1119
  return {
911
1120
  async set(key, value) {
912
- const path8 = getPath(key);
913
- await ensureDir(dirname2(path8));
914
- await writeFileIfDifferent(path8, value);
1121
+ const path10 = getPath(key);
1122
+ await ensureDir2(dirname2(path10));
1123
+ await writeFileIfDifferent(path10, value);
915
1124
  },
916
1125
  async get(key) {
917
- const path8 = getPath(key);
1126
+ const path10 = getPath(key);
918
1127
  try {
919
- return await fs5.readFile(path8, "utf-8");
1128
+ return await fs5.readFile(path10, "utf-8");
920
1129
  } catch {
921
1130
  return void 0;
922
1131
  }
@@ -1050,10 +1259,10 @@ function pointToDevServer(config, server, id, document, querySelector, attr) {
1050
1259
  relative4(config.root, resolvedAbsolutePath)
1051
1260
  );
1052
1261
  if (relativePath.startsWith(".")) {
1053
- let path8 = normalizePath(resolvedAbsolutePath);
1054
- if (!path8.startsWith("/"))
1055
- path8 = "/" + path8;
1056
- element.setAttribute(attr, `${server.origin}/@fs${path8}`);
1262
+ let path10 = normalizePath(resolvedAbsolutePath);
1263
+ if (!path10.startsWith("/"))
1264
+ path10 = "/" + path10;
1265
+ element.setAttribute(attr, `${server.origin}/@fs${path10}`);
1057
1266
  } else {
1058
1267
  const url = new URL(relativePath, server.origin);
1059
1268
  element.setAttribute(attr, url.href);
@@ -1168,7 +1377,7 @@ function download(config) {
1168
1377
 
1169
1378
  // src/core/builders/vite/plugins/multipageMove.ts
1170
1379
  import { dirname as dirname4, extname, resolve as resolve7, join } from "node:path";
1171
- import fs6, { ensureDir as ensureDir2 } from "fs-extra";
1380
+ import fs6, { ensureDir as ensureDir3 } from "fs-extra";
1172
1381
  function multipageMove(entrypoints, config) {
1173
1382
  return {
1174
1383
  name: "wxt:multipage-move",
@@ -1197,7 +1406,7 @@ function multipageMove(entrypoints, config) {
1197
1406
  }
1198
1407
  const oldAbsPath = resolve7(config.outDir, oldBundlePath);
1199
1408
  const newAbsPath = resolve7(config.outDir, newBundlePath);
1200
- await ensureDir2(dirname4(newAbsPath));
1409
+ await ensureDir3(dirname4(newAbsPath));
1201
1410
  await fs6.move(oldAbsPath, newAbsPath, { overwrite: true });
1202
1411
  const renamedChunk = {
1203
1412
  ...bundle[oldBundlePath],
@@ -1347,12 +1556,12 @@ function cssEntrypoints(entrypoint, config) {
1347
1556
 
1348
1557
  // src/core/builders/vite/plugins/bundleAnalysis.ts
1349
1558
  import { visualizer } from "@aklinker1/rollup-plugin-visualizer";
1350
- import path3 from "node:path";
1559
+ import path4 from "node:path";
1351
1560
  var increment = 0;
1352
1561
  function bundleAnalysis(config) {
1353
1562
  return visualizer({
1354
1563
  template: "raw-data",
1355
- filename: path3.resolve(
1564
+ filename: path4.resolve(
1356
1565
  config.analysis.outputDir,
1357
1566
  `${config.analysis.outputName}-${increment++}.json`
1358
1567
  )
@@ -1672,6 +1881,7 @@ function isModuleInstalled(name) {
1672
1881
  }
1673
1882
 
1674
1883
  // src/core/utils/building/resolve-config.ts
1884
+ import fs9 from "fs-extra";
1675
1885
  async function resolveConfig(inlineConfig, command, server) {
1676
1886
  let userConfig = {};
1677
1887
  let userConfigMetadata;
@@ -1697,21 +1907,27 @@ async function resolveConfig(inlineConfig, command, server) {
1697
1907
  const manifestVersion = mergedConfig.manifestVersion ?? (browser === "firefox" || browser === "safari" ? 2 : 3);
1698
1908
  const mode = mergedConfig.mode ?? (command === "build" ? "production" : "development");
1699
1909
  const env = { browser, command, manifestVersion, mode };
1700
- const root = path4.resolve(
1910
+ const root = path5.resolve(
1701
1911
  inlineConfig.root ?? userConfig.root ?? process.cwd()
1702
1912
  );
1703
- const wxtDir = path4.resolve(root, ".wxt");
1913
+ const wxtDir = path5.resolve(root, ".wxt");
1704
1914
  const wxtModuleDir = await resolveWxtModuleDir();
1705
- const srcDir = path4.resolve(root, mergedConfig.srcDir ?? root);
1706
- const entrypointsDir = path4.resolve(
1915
+ const srcDir = path5.resolve(root, mergedConfig.srcDir ?? root);
1916
+ const entrypointsDir = path5.resolve(
1707
1917
  srcDir,
1708
1918
  mergedConfig.entrypointsDir ?? "entrypoints"
1709
1919
  );
1920
+ if (await isDirMissing(entrypointsDir)) {
1921
+ logMissingDir(logger, "Entrypoints", entrypointsDir);
1922
+ }
1710
1923
  const filterEntrypoints = !!mergedConfig.filterEntrypoints?.length ? new Set(mergedConfig.filterEntrypoints) : void 0;
1711
- const publicDir = path4.resolve(srcDir, mergedConfig.publicDir ?? "public");
1712
- const typesDir = path4.resolve(wxtDir, "types");
1713
- const outBaseDir = path4.resolve(root, mergedConfig.outDir ?? ".output");
1714
- const outDir = path4.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
1924
+ const publicDir = path5.resolve(srcDir, mergedConfig.publicDir ?? "public");
1925
+ if (await isDirMissing(publicDir)) {
1926
+ logMissingDir(logger, "Public", publicDir);
1927
+ }
1928
+ const typesDir = path5.resolve(wxtDir, "types");
1929
+ const outBaseDir = path5.resolve(root, mergedConfig.outDir ?? ".output");
1930
+ const outDir = path5.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
1715
1931
  const reloadCommand = mergedConfig.dev?.reloadCommand ?? "Alt+R";
1716
1932
  const runnerConfig = await loadConfig({
1717
1933
  name: "web-ext",
@@ -1728,14 +1944,14 @@ async function resolveConfig(inlineConfig, command, server) {
1728
1944
  "~": srcDir,
1729
1945
  "@@": root,
1730
1946
  "~~": root
1731
- }).map(([key, value]) => [key, path4.resolve(root, value)])
1947
+ }).map(([key, value]) => [key, path5.resolve(root, value)])
1732
1948
  );
1733
- const analysisOutputFile = path4.resolve(
1949
+ const analysisOutputFile = path5.resolve(
1734
1950
  root,
1735
1951
  mergedConfig.analysis?.outputFile ?? "stats.html"
1736
1952
  );
1737
- const analysisOutputDir = path4.dirname(analysisOutputFile);
1738
- const analysisOutputName = path4.parse(analysisOutputFile).name;
1953
+ const analysisOutputDir = path5.dirname(analysisOutputFile);
1954
+ const analysisOutputName = path5.parse(analysisOutputFile).name;
1739
1955
  const finalConfig = {
1740
1956
  browser,
1741
1957
  command,
@@ -1860,6 +2076,7 @@ function mergeInlineConfig(inlineConfig, userConfig) {
1860
2076
  };
1861
2077
  }
1862
2078
  function resolveInternalZipConfig(root, mergedConfig) {
2079
+ const downloadedPackagesDir = path5.resolve(root, ".wxt/local_modules");
1863
2080
  return {
1864
2081
  name: void 0,
1865
2082
  sourcesTemplate: "{{name}}-{{version}}-sources.zip",
@@ -1878,7 +2095,9 @@ function resolveInternalZipConfig(root, mergedConfig) {
1878
2095
  "**/*.+(test|spec).?(c|m)+(j|t)s?(x)",
1879
2096
  // From user
1880
2097
  ...mergedConfig.zip?.excludeSources ?? []
1881
- ]
2098
+ ],
2099
+ downloadPackages: mergedConfig.zip?.downloadPackages ?? [],
2100
+ downloadedPackagesDir
1882
2101
  };
1883
2102
  }
1884
2103
  async function getUnimportOptions(wxtDir, logger, config) {
@@ -1910,7 +2129,7 @@ async function getUnimportOptions(wxtDir, logger, config) {
1910
2129
  dirs: ["components", "composables", "hooks", "utils"],
1911
2130
  eslintrc: {
1912
2131
  enabled,
1913
- filePath: path4.resolve(wxtDir, "eslintrc-auto-import.json"),
2132
+ filePath: path5.resolve(wxtDir, "eslintrc-auto-import.json"),
1914
2133
  globalsPropValue: true
1915
2134
  }
1916
2135
  };
@@ -1921,7 +2140,17 @@ async function getUnimportOptions(wxtDir, logger, config) {
1921
2140
  }
1922
2141
  async function resolveWxtModuleDir() {
1923
2142
  const requireResolve = __require?.resolve ?? (await import("node:module")).default.createRequire(import.meta.url).resolve;
1924
- return path4.resolve(requireResolve("wxt"), "../..");
2143
+ return path5.resolve(requireResolve("wxt"), "../..");
2144
+ }
2145
+ async function isDirMissing(dir) {
2146
+ return !await fs9.exists(dir);
2147
+ }
2148
+ function logMissingDir(logger, name, expected) {
2149
+ logger.warn(
2150
+ `${name} directory not found: ./${normalizePath(
2151
+ path5.relative(process.cwd(), expected)
2152
+ )}`
2153
+ );
1925
2154
  }
1926
2155
 
1927
2156
  // src/core/utils/building/group-entrypoints.ts
@@ -1966,7 +2195,7 @@ var ENTRY_TYPE_TO_GROUP_MAP = {
1966
2195
  // src/core/utils/building/import-entrypoint.ts
1967
2196
  import createJITI from "jiti";
1968
2197
  import { createUnimport as createUnimport3 } from "unimport";
1969
- import fs9 from "fs-extra";
2198
+ import fs10 from "fs-extra";
1970
2199
  import { relative as relative5, resolve as resolve10 } from "node:path";
1971
2200
 
1972
2201
  // src/core/utils/strings.ts
@@ -1989,16 +2218,16 @@ ${noImports}`;
1989
2218
  // src/core/utils/building/import-entrypoint.ts
1990
2219
  import { transformSync } from "esbuild";
1991
2220
  import { fileURLToPath } from "node:url";
1992
- async function importEntrypointFile(path8) {
1993
- wxt.logger.debug("Loading file metadata:", path8);
1994
- const normalPath = normalizePath(path8);
2221
+ async function importEntrypointFile(path10) {
2222
+ wxt.logger.debug("Loading file metadata:", path10);
2223
+ const normalPath = normalizePath(path10);
1995
2224
  const unimport2 = createUnimport3({
1996
2225
  ...wxt.config.imports,
1997
2226
  // Only allow specific imports, not all from the project
1998
2227
  dirs: []
1999
2228
  });
2000
2229
  await unimport2.init();
2001
- const text = await fs9.readFile(path8, "utf-8");
2230
+ const text = await fs10.readFile(path10, "utf-8");
2002
2231
  const textNoImports = removeProjectImportStatements(text);
2003
2232
  const { code } = await unimport2.injectImports(textNoImports);
2004
2233
  wxt.logger.debug(
@@ -2041,10 +2270,10 @@ async function importEntrypointFile(path8) {
2041
2270
  }
2042
2271
  );
2043
2272
  try {
2044
- const res = await jiti(path8);
2273
+ const res = await jiti(path10);
2045
2274
  return res.default;
2046
2275
  } catch (err) {
2047
- const filePath = relative5(wxt.config.root, path8);
2276
+ const filePath = relative5(wxt.config.root, path10);
2048
2277
  if (err instanceof ReferenceError) {
2049
2278
  const variableName = err.message.replace(" is not defined", "");
2050
2279
  throw Error(
@@ -2073,15 +2302,15 @@ function getEsbuildOptions(opts) {
2073
2302
 
2074
2303
  // src/core/utils/building/internal-build.ts
2075
2304
  import pc5 from "picocolors";
2076
- import fs12 from "fs-extra";
2305
+ import fs13 from "fs-extra";
2077
2306
 
2078
2307
  // src/core/utils/log/printBuildSummary.ts
2079
2308
  import { resolve as resolve11 } from "path";
2080
2309
 
2081
2310
  // src/core/utils/log/printFileList.ts
2082
- import path5 from "node:path";
2311
+ import path6 from "node:path";
2083
2312
  import pc3 from "picocolors";
2084
- import fs10 from "fs-extra";
2313
+ import fs11 from "fs-extra";
2085
2314
  import { filesize } from "filesize";
2086
2315
 
2087
2316
  // src/core/utils/log/printTable.ts
@@ -2117,12 +2346,12 @@ async function printFileList(log, header, baseDir, files) {
2117
2346
  const fileRows = await Promise.all(
2118
2347
  files.map(async (file, i) => {
2119
2348
  const parts = [
2120
- path5.relative(process.cwd(), baseDir) + path5.sep,
2121
- path5.relative(baseDir, file)
2349
+ path6.relative(process.cwd(), baseDir) + path6.sep,
2350
+ path6.relative(baseDir, file)
2122
2351
  ];
2123
2352
  const prefix = i === files.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
2124
2353
  const color = getChunkColor(file);
2125
- const stats = await fs10.lstat(file);
2354
+ const stats = await fs11.lstat(file);
2126
2355
  totalSize += stats.size;
2127
2356
  const size = String(filesize(stats.size));
2128
2357
  return [
@@ -2186,7 +2415,7 @@ function getChunkSortWeight(filename) {
2186
2415
  import pc4 from "picocolors";
2187
2416
 
2188
2417
  // package.json
2189
- var version = "0.17.4";
2418
+ var version = "0.17.6";
2190
2419
 
2191
2420
  // src/core/utils/log/printHeader.ts
2192
2421
  import { consola as consola2 } from "consola";
@@ -2199,7 +2428,7 @@ function printHeader() {
2199
2428
  import glob3 from "fast-glob";
2200
2429
 
2201
2430
  // src/core/utils/manifest.ts
2202
- import fs11 from "fs-extra";
2431
+ import fs12 from "fs-extra";
2203
2432
  import { resolve as resolve12 } from "path";
2204
2433
 
2205
2434
  // src/core/utils/content-security-policy.ts
@@ -2310,7 +2539,7 @@ function mapWxtOptionsToRegisteredContentScript(options, js, css) {
2310
2539
  import defu2 from "defu";
2311
2540
  async function writeManifest(manifest, output) {
2312
2541
  const str = wxt.config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
2313
- await fs11.ensureDir(wxt.config.outDir);
2542
+ await fs12.ensureDir(wxt.config.outDir);
2314
2543
  await writeFileIfDifferent(resolve12(wxt.config.outDir, "manifest.json"), str);
2315
2544
  output.publicAssets.unshift({
2316
2545
  type: "asset",
@@ -2366,11 +2595,14 @@ async function generateManifest(entrypoints, buildOutput) {
2366
2595
  addDevModePermissions(manifest);
2367
2596
  wxt.config.transformManifest(manifest);
2368
2597
  await wxt.hooks.callHook("build:manifestGenerated", wxt, manifest);
2369
- if (wxt.config.manifestVersion === 2)
2598
+ if (wxt.config.manifestVersion === 2) {
2370
2599
  convertWebAccessibleResourcesToMv2(manifest);
2600
+ convertActionToMv2(manifest);
2601
+ }
2371
2602
  if (wxt.config.manifestVersion === 3) {
2372
2603
  validateMv3WebAccessbileResources(manifest);
2373
2604
  }
2605
+ stripKeys(manifest);
2374
2606
  if (manifest.name == null)
2375
2607
  throw Error(
2376
2608
  "Manifest 'name' is missing. Either:\n1. Set the name in your <rootDir>/package.json\n2. Set a name via the manifest option in your wxt.config.ts"
@@ -2746,6 +2978,11 @@ function convertWebAccessibleResourcesToMv2(manifest) {
2746
2978
  )
2747
2979
  );
2748
2980
  }
2981
+ function convertActionToMv2(manifest) {
2982
+ if (manifest.action == null || manifest.browser_action != null || manifest.page_action != null)
2983
+ return;
2984
+ manifest.browser_action = manifest.action;
2985
+ }
2749
2986
  function validateMv3WebAccessbileResources(manifest) {
2750
2987
  if (manifest.web_accessible_resources == null)
2751
2988
  return;
@@ -2760,6 +2997,46 @@ function validateMv3WebAccessbileResources(manifest) {
2760
2997
  );
2761
2998
  }
2762
2999
  }
3000
+ function stripKeys(manifest) {
3001
+ let keysToRemove = [];
3002
+ if (wxt.config.manifestVersion === 2) {
3003
+ keysToRemove.push(...mv3OnlyKeys);
3004
+ if (wxt.config.browser === "firefox")
3005
+ keysToRemove.push(...firefoxMv3OnlyKeys);
3006
+ } else {
3007
+ keysToRemove.push(...mv2OnlyKeys);
3008
+ }
3009
+ keysToRemove.forEach((key) => {
3010
+ delete manifest[key];
3011
+ });
3012
+ }
3013
+ var mv2OnlyKeys = [
3014
+ "page_action",
3015
+ "browser_action",
3016
+ "automation",
3017
+ "content_capabilities",
3018
+ "converted_from_user_script",
3019
+ "current_locale",
3020
+ "differential_fingerprint",
3021
+ "event_rules",
3022
+ "file_browser_handlers",
3023
+ "file_system_provider_capabilities",
3024
+ "input_components",
3025
+ "nacl_modules",
3026
+ "natively_connectable",
3027
+ "offline_enabled",
3028
+ "platforms",
3029
+ "replacement_web_app",
3030
+ "system_indicator",
3031
+ "user_scripts"
3032
+ ];
3033
+ var mv3OnlyKeys = [
3034
+ "action",
3035
+ "export",
3036
+ "optional_host_permissions",
3037
+ "side_panel"
3038
+ ];
3039
+ var firefoxMv3OnlyKeys = ["host_permissions"];
2763
3040
 
2764
3041
  // src/core/utils/building/rebuild.ts
2765
3042
  async function rebuild(allEntrypoints, entrypointGroups, existingOutput = {
@@ -2874,8 +3151,8 @@ async function internalBuild() {
2874
3151
  )}`
2875
3152
  );
2876
3153
  const startTime = Date.now();
2877
- await fs12.rm(wxt.config.outDir, { recursive: true, force: true });
2878
- await fs12.ensureDir(wxt.config.outDir);
3154
+ await fs13.rm(wxt.config.outDir, { recursive: true, force: true });
3155
+ await fs13.ensureDir(wxt.config.outDir);
2879
3156
  const entrypoints = await findEntrypoints();
2880
3157
  wxt.logger.debug("Detected entrypoints:", entrypoints);
2881
3158
  const validationResults = validateEntrypoints(entrypoints);
@@ -2921,7 +3198,7 @@ async function combineAnalysisStats() {
2921
3198
  filename: wxt.config.analysis.outputFile
2922
3199
  });
2923
3200
  if (!wxt.config.analysis.keepArtifacts) {
2924
- await Promise.all(absolutePaths.map((statsFile) => fs12.remove(statsFile)));
3201
+ await Promise.all(absolutePaths.map((statsFile) => fs13.remove(statsFile)));
2925
3202
  }
2926
3203
  }
2927
3204
  function printValidationResults({
@@ -2958,9 +3235,9 @@ async function build(config) {
2958
3235
  }
2959
3236
 
2960
3237
  // src/core/clean.ts
2961
- import path6 from "node:path";
3238
+ import path7 from "node:path";
2962
3239
  import glob4 from "fast-glob";
2963
- import fs13 from "fs-extra";
3240
+ import fs14 from "fs-extra";
2964
3241
  import { consola as consola4 } from "consola";
2965
3242
  import pc6 from "picocolors";
2966
3243
  async function clean(root = process.cwd()) {
@@ -2973,7 +3250,7 @@ async function clean(root = process.cwd()) {
2973
3250
  ];
2974
3251
  consola4.debug("Looking for:", tempDirs.map(pc6.cyan).join(", "));
2975
3252
  const directories = await glob4(tempDirs, {
2976
- cwd: path6.resolve(root),
3253
+ cwd: path7.resolve(root),
2977
3254
  absolute: true,
2978
3255
  onlyDirectories: true,
2979
3256
  deep: 2
@@ -2984,11 +3261,11 @@ async function clean(root = process.cwd()) {
2984
3261
  }
2985
3262
  consola4.debug(
2986
3263
  "Found:",
2987
- directories.map((dir) => pc6.cyan(path6.relative(root, dir))).join(", ")
3264
+ directories.map((dir) => pc6.cyan(path7.relative(root, dir))).join(", ")
2988
3265
  );
2989
3266
  for (const directory of directories) {
2990
- await fs13.rm(directory, { force: true, recursive: true });
2991
- consola4.debug("Deleted " + pc6.cyan(path6.relative(root, directory)));
3267
+ await fs14.rm(directory, { force: true, recursive: true });
3268
+ consola4.debug("Deleted " + pc6.cyan(path7.relative(root, directory)));
2992
3269
  }
2993
3270
  }
2994
3271
 
@@ -3192,8 +3469,8 @@ async function createServer(inlineConfig) {
3192
3469
  reloadContentScript(payload) {
3193
3470
  server.ws.send("wxt:reload-content-script", payload);
3194
3471
  },
3195
- reloadPage(path8) {
3196
- server.ws.send("wxt:reload-page", path8);
3472
+ reloadPage(path10) {
3473
+ server.ws.send("wxt:reload-page", path10);
3197
3474
  },
3198
3475
  reloadExtension() {
3199
3476
  server.ws.send("wxt:reload-extension");
@@ -3224,11 +3501,11 @@ async function getPort() {
3224
3501
  function createFileReloader(server) {
3225
3502
  const fileChangedMutex = new Mutex();
3226
3503
  const changeQueue = [];
3227
- return async (event, path8) => {
3504
+ return async (event, path10) => {
3228
3505
  await wxt.reloadConfig();
3229
- if (path8.startsWith(wxt.config.outBaseDir))
3506
+ if (path10.startsWith(wxt.config.outBaseDir))
3230
3507
  return;
3231
- changeQueue.push([event, path8]);
3508
+ changeQueue.push([event, path10]);
3232
3509
  await fileChangedMutex.runExclusive(async () => {
3233
3510
  if (server.currentOutput == null)
3234
3511
  return;
@@ -3307,8 +3584,8 @@ function reloadContentScripts(steps, server) {
3307
3584
  function reloadHtmlPages(groups, server) {
3308
3585
  const htmlEntries = groups.flat().filter(isHtmlEntrypoint);
3309
3586
  htmlEntries.forEach((entry) => {
3310
- const path8 = getEntrypointBundlePath(entry, wxt.config.outDir, ".html");
3311
- server.reloadPage(path8);
3587
+ const path10 = getEntrypointBundlePath(entry, wxt.config.outDir, ".html");
3588
+ server.reloadPage(path10);
3312
3589
  });
3313
3590
  return {
3314
3591
  reloadedNames: htmlEntries.map((entry) => entry.name)
@@ -3338,8 +3615,8 @@ function getExternalOutputDependencies(server) {
3338
3615
  import prompts from "prompts";
3339
3616
  import { consola as consola6 } from "consola";
3340
3617
  import { downloadTemplate } from "giget";
3341
- import fs14 from "fs-extra";
3342
- import path7 from "node:path";
3618
+ import fs15 from "fs-extra";
3619
+ import path8 from "node:path";
3343
3620
  import pc8 from "picocolors";
3344
3621
  async function initialize(options) {
3345
3622
  consola6.info("Initalizing new project");
@@ -3387,7 +3664,7 @@ async function initialize(options) {
3387
3664
  input.template ??= defaultTemplate;
3388
3665
  input.packageManager ??= options.packageManager;
3389
3666
  await cloneProject(input);
3390
- const cdPath = path7.relative(process.cwd(), path7.resolve(input.directory));
3667
+ const cdPath = path8.relative(process.cwd(), path8.resolve(input.directory));
3391
3668
  console.log();
3392
3669
  consola6.log(
3393
3670
  `\u2728 WXT project created with the ${TEMPLATE_COLORS[input.template.name]?.(input.template.name) ?? input.template.name} template.`
@@ -3430,9 +3707,9 @@ async function cloneProject({
3430
3707
  dir: directory,
3431
3708
  force: true
3432
3709
  });
3433
- await fs14.move(
3434
- path7.join(directory, "_gitignore"),
3435
- path7.join(directory, ".gitignore")
3710
+ await fs15.move(
3711
+ path8.join(directory, "_gitignore"),
3712
+ path8.join(directory, ".gitignore")
3436
3713
  ).catch(
3437
3714
  (err) => consola6.warn("Failed to move _gitignore to .gitignore:", err)
3438
3715
  );
@@ -3464,10 +3741,11 @@ async function prepare(config) {
3464
3741
  }
3465
3742
 
3466
3743
  // src/core/zip.ts
3467
- import zipdir from "zip-dir";
3468
- import { dirname as dirname5, relative as relative11, resolve as resolve13 } from "node:path";
3469
- import fs15 from "fs-extra";
3744
+ import path9 from "node:path";
3745
+ import fs16 from "fs-extra";
3470
3746
  import { minimatch as minimatch2 } from "minimatch";
3747
+ import JSZip from "jszip";
3748
+ import glob5 from "fast-glob";
3471
3749
  async function zip(config) {
3472
3750
  await registerWxt("build", config);
3473
3751
  const output = await internalBuild();
@@ -3475,32 +3753,33 @@ async function zip(config) {
3475
3753
  wxt.logger.info("Zipping extension...");
3476
3754
  const zipFiles = [];
3477
3755
  const projectName = wxt.config.zip.name ?? kebabCaseAlphanumeric(
3478
- (await getPackageJson())?.name || dirname5(process.cwd())
3756
+ (await getPackageJson())?.name || path9.dirname(process.cwd())
3479
3757
  );
3480
3758
  const applyTemplate = (template) => template.replaceAll("{{name}}", projectName).replaceAll("{{browser}}", wxt.config.browser).replaceAll(
3481
3759
  "{{version}}",
3482
3760
  output.manifest.version_name ?? output.manifest.version
3483
3761
  ).replaceAll("{{manifestVersion}}", `mv${wxt.config.manifestVersion}`);
3484
- await fs15.ensureDir(wxt.config.outBaseDir);
3762
+ await fs16.ensureDir(wxt.config.outBaseDir);
3485
3763
  const outZipFilename = applyTemplate(wxt.config.zip.artifactTemplate);
3486
- const outZipPath = resolve13(wxt.config.outBaseDir, outZipFilename);
3487
- await zipdir(wxt.config.outDir, {
3488
- saveTo: outZipPath
3489
- });
3764
+ const outZipPath = path9.resolve(wxt.config.outBaseDir, outZipFilename);
3765
+ await zipDir(wxt.config.outDir, outZipPath);
3490
3766
  zipFiles.push(outZipPath);
3491
3767
  if (wxt.config.browser === "firefox") {
3768
+ const { overrides, files: downloadedPackages } = await downloadPrivatePackages();
3492
3769
  const sourcesZipFilename = applyTemplate(wxt.config.zip.sourcesTemplate);
3493
- const sourcesZipPath = resolve13(wxt.config.outBaseDir, sourcesZipFilename);
3494
- await zipdir(wxt.config.zip.sourcesRoot, {
3495
- saveTo: sourcesZipPath,
3496
- filter(path8) {
3497
- const relativePath = relative11(wxt.config.zip.sourcesRoot, path8);
3498
- return wxt.config.zip.includeSources.some(
3499
- (pattern) => minimatch2(relativePath, pattern)
3500
- ) || !wxt.config.zip.excludeSources.some(
3501
- (pattern) => minimatch2(relativePath, pattern)
3502
- );
3503
- }
3770
+ const sourcesZipPath = path9.resolve(
3771
+ wxt.config.outBaseDir,
3772
+ sourcesZipFilename
3773
+ );
3774
+ await zipDir(wxt.config.zip.sourcesRoot, sourcesZipPath, {
3775
+ include: wxt.config.zip.includeSources,
3776
+ exclude: wxt.config.zip.excludeSources,
3777
+ transform(file, content) {
3778
+ if (file.endsWith("package.json")) {
3779
+ return addOverridesToPackageJson(content, overrides);
3780
+ }
3781
+ },
3782
+ additionalFiles: downloadedPackages
3504
3783
  });
3505
3784
  zipFiles.push(sourcesZipPath);
3506
3785
  }
@@ -3512,6 +3791,81 @@ async function zip(config) {
3512
3791
  );
3513
3792
  return zipFiles;
3514
3793
  }
3794
+ async function zipDir(directory, outputPath, options) {
3795
+ const archive = new JSZip();
3796
+ const files = (await glob5("**/*", {
3797
+ cwd: directory,
3798
+ // Ignore node_modules, otherwise this glob step takes forever
3799
+ ignore: ["**/node_modules"],
3800
+ onlyFiles: true
3801
+ })).filter((relativePath) => {
3802
+ return wxt.config.zip.includeSources.some(
3803
+ (pattern) => minimatch2(relativePath, pattern)
3804
+ ) || !wxt.config.zip.excludeSources.some(
3805
+ (pattern) => minimatch2(relativePath, pattern)
3806
+ );
3807
+ });
3808
+ const filesToZip = [
3809
+ ...files,
3810
+ ...(options?.additionalFiles ?? []).map(
3811
+ (file) => path9.relative(directory, file)
3812
+ )
3813
+ ];
3814
+ for (const file of filesToZip) {
3815
+ const absolutePath = path9.resolve(directory, file);
3816
+ if (file.endsWith(".json")) {
3817
+ const content = await fs16.readFile(absolutePath, "utf-8");
3818
+ archive.file(
3819
+ file,
3820
+ await options?.transform?.(file, content) || content
3821
+ );
3822
+ } else {
3823
+ const content = await fs16.readFile(absolutePath);
3824
+ archive.file(file, content);
3825
+ }
3826
+ }
3827
+ await options?.additionalWork?.(archive);
3828
+ const buffer = await archive.generateAsync({ type: "base64" });
3829
+ await fs16.writeFile(outputPath, buffer, "base64");
3830
+ }
3831
+ async function downloadPrivatePackages() {
3832
+ const overrides = {};
3833
+ const files = [];
3834
+ if (wxt.config.zip.downloadPackages.length > 0) {
3835
+ const _downloadPackages = new Set(wxt.config.zip.downloadPackages);
3836
+ const allPackages = await wxt.pm.listDependencies({
3837
+ all: true,
3838
+ cwd: wxt.config.root
3839
+ });
3840
+ const downloadPackages = allPackages.filter(
3841
+ (pkg) => _downloadPackages.has(pkg.name)
3842
+ );
3843
+ for (const pkg of downloadPackages) {
3844
+ wxt.logger.info(`Downloading package: ${pkg.name}@${pkg.version}`);
3845
+ const id = `${pkg.name}@${pkg.version}`;
3846
+ const tgzPath = await wxt.pm.downloadDependency(
3847
+ id,
3848
+ wxt.config.zip.downloadedPackagesDir
3849
+ );
3850
+ files.push(tgzPath);
3851
+ overrides[id] = "file://./" + normalizePath(path9.relative(wxt.config.root, tgzPath));
3852
+ }
3853
+ }
3854
+ return { overrides, files };
3855
+ }
3856
+ function addOverridesToPackageJson(content, overrides) {
3857
+ if (Object.keys(overrides).length === 0)
3858
+ return content;
3859
+ const oldPackage = JSON.parse(content);
3860
+ const newPackage = {
3861
+ ...oldPackage,
3862
+ [wxt.pm.overridesKey]: {
3863
+ ...oldPackage[wxt.pm.overridesKey],
3864
+ ...overrides
3865
+ }
3866
+ };
3867
+ return JSON.stringify(newPackage, null, 2);
3868
+ }
3515
3869
 
3516
3870
  // src/cli/cli-utils.ts
3517
3871
  import consola7, { LogLevels as LogLevels2 } from "consola";