wxt 0.18.4 → 0.18.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
@@ -46,7 +46,7 @@ var npm = {
46
46
  overridesKey: "overrides",
47
47
  async downloadDependency(id, downloadDir) {
48
48
  await ensureDir(downloadDir);
49
- const { execa } = await import("./execa-6HO2IY2B.js");
49
+ const { execa } = await import("./execa-QQUOQNS3.js");
50
50
  const res = await execa("npm", ["pack", id, "--json"], {
51
51
  cwd: downloadDir
52
52
  });
@@ -58,7 +58,7 @@ var npm = {
58
58
  if (options?.all) {
59
59
  args.push("--depth", "Infinity");
60
60
  }
61
- const { execa } = await import("./execa-6HO2IY2B.js");
61
+ const { execa } = await import("./execa-QQUOQNS3.js");
62
62
  const res = await execa("npm", args, { cwd: options?.cwd });
63
63
  const project = JSON.parse(res.stdout);
64
64
  return flattenNpmListOutput([project]);
@@ -115,7 +115,7 @@ var bun = {
115
115
  if (options?.all) {
116
116
  args.push("--all");
117
117
  }
118
- const { execa } = await import("./execa-6HO2IY2B.js");
118
+ const { execa } = await import("./execa-QQUOQNS3.js");
119
119
  const res = await execa("bun", args, { cwd: options?.cwd });
120
120
  return dedupeDependencies(
121
121
  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 }))
@@ -134,7 +134,7 @@ var yarn = {
134
134
  if (options?.all) {
135
135
  args.push("--depth", "Infinity");
136
136
  }
137
- const { execa } = await import("./execa-6HO2IY2B.js");
137
+ const { execa } = await import("./execa-QQUOQNS3.js");
138
138
  const res = await execa("yarn", args, { cwd: options?.cwd });
139
139
  const tree = res.stdout.split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
140
140
  if (tree == null)
@@ -171,7 +171,7 @@ var pnpm = {
171
171
  if (typeof process !== "undefined" && process.env.WXT_PNPM_IGNORE_WORKSPACE === "true") {
172
172
  args.push("--ignore-workspace");
173
173
  }
174
- const { execa } = await import("./execa-6HO2IY2B.js");
174
+ const { execa } = await import("./execa-QQUOQNS3.js");
175
175
  const res = await execa("pnpm", args, { cwd: options?.cwd });
176
176
  const projects = JSON.parse(res.stdout);
177
177
  return flattenNpmListOutput(projects);
@@ -901,6 +901,62 @@ function removeEntrypointMainFunction(config, path11) {
901
901
  };
902
902
  }
903
903
 
904
+ // src/core/builders/vite/plugins/wxtPluginLoader.ts
905
+ import { parseHTML as parseHTML2 } from "linkedom";
906
+ function wxtPluginLoader(config) {
907
+ const virtualModuleId = "virtual:wxt-plugins";
908
+ const resolvedVirtualModuleId = "\0" + virtualModuleId;
909
+ const virtualHtmlModuleId = "virtual:wxt-html-plugins";
910
+ const resolvedVirtualHtmlModuleId = "\0" + virtualHtmlModuleId;
911
+ return {
912
+ name: "wxt:plugin-loader",
913
+ resolveId(id) {
914
+ if (id === virtualModuleId)
915
+ return resolvedVirtualModuleId;
916
+ if (id === virtualHtmlModuleId)
917
+ return resolvedVirtualHtmlModuleId;
918
+ },
919
+ load(id) {
920
+ if (id === resolvedVirtualModuleId) {
921
+ const imports = config.plugins.map(
922
+ (plugin, i) => `import initPlugin${i} from '${normalizePath(plugin)}';`
923
+ ).join("\n");
924
+ const initCalls = config.plugins.map((_, i) => ` initPlugin${i}();`).join("\n");
925
+ return `${imports}
926
+
927
+ export function initPlugins() {
928
+ ${initCalls}
929
+ }`;
930
+ }
931
+ if (id === resolvedVirtualHtmlModuleId) {
932
+ return `import { initPlugins } from '${virtualModuleId}';
933
+
934
+ try {
935
+ initPlugins();
936
+ } catch (err) {
937
+ console.error("[wxt] Failed to initialize plugins", err);
938
+ }`;
939
+ }
940
+ },
941
+ transformIndexHtml: {
942
+ // Use "pre" so the new script is added before vite bundles all the scripts
943
+ order: "pre",
944
+ handler(html, _ctx) {
945
+ const { document } = parseHTML2(html);
946
+ const script = document.createElement("script");
947
+ script.type = "module";
948
+ script.src = "virtual:wxt-html-plugins";
949
+ if (document.head == null) {
950
+ const newHead = document.createElement("head");
951
+ document.documentElement.prepend(newHead);
952
+ }
953
+ document.head.prepend(script);
954
+ return document.toString();
955
+ }
956
+ }
957
+ };
958
+ }
959
+
904
960
  // src/core/utils/arrays.ts
905
961
  function every(array, predicate) {
906
962
  for (let i = 0; i < array.length; i++)
@@ -972,7 +1028,8 @@ async function createViteBuilder(wxtConfig, hooks, server) {
972
1028
  noopBackground(),
973
1029
  globals(wxtConfig),
974
1030
  excludeBrowserPolyfill(wxtConfig),
975
- defineImportMeta()
1031
+ defineImportMeta(),
1032
+ wxtPluginLoader(wxtConfig)
976
1033
  );
977
1034
  if (wxtConfig.analysis.enabled) {
978
1035
  config.plugins.push(bundleAnalysis(wxtConfig));
@@ -1208,6 +1265,19 @@ async function registerWxt(command, inlineConfig = {}, getServer) {
1208
1265
  builder,
1209
1266
  server
1210
1267
  };
1268
+ for (const module of config.modules) {
1269
+ if (module.hooks)
1270
+ wxt.hooks.addHooks(module.hooks);
1271
+ if (wxt.config.imports !== false && module.imports) {
1272
+ wxt.config.imports.imports ??= [];
1273
+ wxt.config.imports.imports.push(...module.imports);
1274
+ }
1275
+ await module.setup?.(
1276
+ wxt,
1277
+ // @ts-expect-error: Untyped configKey field
1278
+ module.configKey ? config[module.configKey] : void 0
1279
+ );
1280
+ }
1211
1281
  wxt.hooks.addHooks(config.hooks);
1212
1282
  await wxt.hooks.callHook("ready", wxt);
1213
1283
  }
@@ -1249,18 +1319,21 @@ async function buildEntrypoints(groups, spinner) {
1249
1319
  return { publicAssets, steps };
1250
1320
  }
1251
1321
  async function copyPublicDirectory() {
1252
- const files = await getPublicFiles();
1322
+ const files = (await getPublicFiles()).map((file) => ({
1323
+ absoluteSrc: resolve6(wxt.config.publicDir, file),
1324
+ relativeDest: file
1325
+ }));
1326
+ await wxt.hooks.callHook("build:publicAssets", wxt, files);
1253
1327
  if (files.length === 0)
1254
1328
  return [];
1255
1329
  const publicAssets = [];
1256
- for (const file of files) {
1257
- const srcPath = resolve6(wxt.config.publicDir, file);
1258
- const outPath = resolve6(wxt.config.outDir, file);
1259
- await fs4.ensureDir(dirname3(outPath));
1260
- await fs4.copyFile(srcPath, outPath);
1330
+ for (const { absoluteSrc, relativeDest } of files) {
1331
+ const absoluteDest = resolve6(wxt.config.outDir, relativeDest);
1332
+ await fs4.ensureDir(dirname3(absoluteDest));
1333
+ await fs4.copyFile(absoluteSrc, absoluteDest);
1261
1334
  publicAssets.push({
1262
1335
  type: "asset",
1263
- fileName: file
1336
+ fileName: relativeDest
1264
1337
  });
1265
1338
  }
1266
1339
  return publicAssets;
@@ -1364,7 +1437,7 @@ function findEffectedSteps(changedFile, currentOutput) {
1364
1437
  import { relative as relative4, resolve as resolve8 } from "path";
1365
1438
  import fs6 from "fs-extra";
1366
1439
  import { minimatch } from "minimatch";
1367
- import { parseHTML as parseHTML2 } from "linkedom";
1440
+ import { parseHTML as parseHTML3 } from "linkedom";
1368
1441
  import JSON5 from "json5";
1369
1442
  import glob2 from "fast-glob";
1370
1443
  import pc2 from "picocolors";
@@ -1435,7 +1508,7 @@ async function importEntrypointFile(path11) {
1435
1508
  if (err instanceof ReferenceError) {
1436
1509
  const variableName = err.message.replace(" is not defined", "");
1437
1510
  throw Error(
1438
- `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/entrypoints.html#side-effects`,
1511
+ `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/go-further/entrypoint-side-effects.html`,
1439
1512
  { cause: err }
1440
1513
  );
1441
1514
  } else {
@@ -1471,7 +1544,7 @@ async function findEntrypoints() {
1471
1544
  const inputPath = resolve8(wxt.config.entrypointsDir, relativePath);
1472
1545
  const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
1473
1546
  const matchingGlob = pathGlobs.find(
1474
- (glob6) => minimatch(relativePath, glob6)
1547
+ (glob7) => minimatch(relativePath, glob7)
1475
1548
  );
1476
1549
  if (matchingGlob) {
1477
1550
  const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
@@ -1765,7 +1838,7 @@ async function getSidepanelEntrypoint(info) {
1765
1838
  }
1766
1839
  async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
1767
1840
  const content = await fs6.readFile(info.inputPath, "utf-8");
1768
- const { document } = parseHTML2(content);
1841
+ const { document } = parseHTML3(content);
1769
1842
  const options = {};
1770
1843
  const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
1771
1844
  Object.entries(keyMap).forEach(([_key, manifestKey]) => {
@@ -2016,7 +2089,14 @@ async function writeMainDeclarationFile(references) {
2016
2089
  `/// <reference types="wxt/vite-builder-env" />`,
2017
2090
  ...references.map(
2018
2091
  (ref) => `/// <reference types="./${normalizePath(relative5(dir, ref))}" />`
2019
- )
2092
+ ),
2093
+ // Add references to modules installed from NPM to the TS project so
2094
+ // their type augmentation can update InlineConfig correctly. Local
2095
+ // modules defined in <root>/modules are already apart of the project, so
2096
+ // we don't need to add them.
2097
+ ...wxt.config.modules.filter(
2098
+ (module) => module.type === "node_module" && module.configKey != null
2099
+ ).map((module) => `/// <reference types="${module.id}" />`)
2020
2100
  ].join("\n") + "\n"
2021
2101
  );
2022
2102
  return filePath;
@@ -2109,6 +2189,7 @@ function isModuleInstalled(name) {
2109
2189
 
2110
2190
  // src/core/utils/building/resolve-config.ts
2111
2191
  import fs10 from "fs-extra";
2192
+ import glob3 from "fast-glob";
2112
2193
  async function resolveConfig(inlineConfig, command) {
2113
2194
  let userConfig = {};
2114
2195
  let userConfigMetadata;
@@ -2144,6 +2225,7 @@ async function resolveConfig(inlineConfig, command) {
2144
2225
  srcDir,
2145
2226
  mergedConfig.entrypointsDir ?? "entrypoints"
2146
2227
  );
2228
+ const modulesDir = path6.resolve(srcDir, mergedConfig.modulesDir ?? "modules");
2147
2229
  if (await isDirMissing(entrypointsDir)) {
2148
2230
  logMissingDir(logger, "Entrypoints", entrypointsDir);
2149
2231
  }
@@ -2185,11 +2267,20 @@ async function resolveConfig(inlineConfig, command) {
2185
2267
  hostname: "localhost"
2186
2268
  };
2187
2269
  }
2270
+ const modules = await resolveWxtModules(modulesDir, mergedConfig.modules);
2271
+ const moduleOptions = modules.reduce((map, module) => {
2272
+ if (module.configKey) {
2273
+ map[module.configKey] = // @ts-expect-error
2274
+ mergedConfig[module.configKey];
2275
+ }
2276
+ return map;
2277
+ }, {});
2188
2278
  return {
2189
2279
  browser,
2190
2280
  command,
2191
2281
  debug,
2192
2282
  entrypointsDir,
2283
+ modulesDir,
2193
2284
  filterEntrypoints,
2194
2285
  env,
2195
2286
  fsCache: createFsCache(wxtDir),
@@ -2221,7 +2312,10 @@ async function resolveConfig(inlineConfig, command) {
2221
2312
  reloadCommand
2222
2313
  },
2223
2314
  hooks: mergedConfig.hooks ?? {},
2224
- vite: mergedConfig.vite ?? (() => ({}))
2315
+ vite: mergedConfig.vite ?? (() => ({})),
2316
+ modules,
2317
+ plugins: [],
2318
+ ...moduleOptions
2225
2319
  };
2226
2320
  }
2227
2321
  async function resolveManifestConfig(env, manifest) {
@@ -2360,6 +2454,52 @@ async function mergeBuilderConfig(inlineConfig, userConfig) {
2360
2454
  }
2361
2455
  throw Error("Builder not found. Make sure vite is installed.");
2362
2456
  }
2457
+ async function resolveWxtModules(modulesDir, modules = []) {
2458
+ const npmModules = await Promise.all(
2459
+ modules.map(async (moduleId) => {
2460
+ const mod = await import(
2461
+ /* @vite-ignore */
2462
+ moduleId
2463
+ );
2464
+ if (mod.default == null) {
2465
+ throw Error("Module missing default export: " + moduleId);
2466
+ }
2467
+ return {
2468
+ ...mod.default,
2469
+ type: "node_module",
2470
+ id: moduleId
2471
+ };
2472
+ })
2473
+ );
2474
+ const localModulePaths = await glob3(["*.[tj]s", "*/index.[tj]s"], {
2475
+ cwd: modulesDir,
2476
+ onlyFiles: true
2477
+ }).catch(() => []);
2478
+ const localModules = await Promise.all(
2479
+ localModulePaths.map(async (file) => {
2480
+ const absolutePath = normalizePath(path6.resolve(modulesDir, file));
2481
+ const { config } = await loadConfig({
2482
+ configFile: absolutePath,
2483
+ globalRc: false,
2484
+ rcFile: false,
2485
+ packageJson: false,
2486
+ envName: false,
2487
+ dotenv: false
2488
+ });
2489
+ if (config == null)
2490
+ throw Error(
2491
+ `No config found for ${file}. Did you forget to add a default export?`
2492
+ );
2493
+ config.name ??= file;
2494
+ return {
2495
+ ...config,
2496
+ type: "local",
2497
+ id: absolutePath
2498
+ };
2499
+ })
2500
+ );
2501
+ return [...npmModules, ...localModules];
2502
+ }
2363
2503
 
2364
2504
  // src/core/utils/building/group-entrypoints.ts
2365
2505
  function groupEntrypoints(entrypoints) {
@@ -2515,7 +2655,7 @@ function getChunkSortWeight(filename) {
2515
2655
  import pc4 from "picocolors";
2516
2656
 
2517
2657
  // package.json
2518
- var version = "0.18.3";
2658
+ var version = "0.18.6";
2519
2659
 
2520
2660
  // src/core/utils/log/printHeader.ts
2521
2661
  function printHeader() {
@@ -2524,7 +2664,7 @@ function printHeader() {
2524
2664
  }
2525
2665
 
2526
2666
  // src/core/utils/building/internal-build.ts
2527
- import glob3 from "fast-glob";
2667
+ import glob4 from "fast-glob";
2528
2668
 
2529
2669
  // src/core/utils/manifest.ts
2530
2670
  import fs12 from "fs-extra";
@@ -3316,7 +3456,7 @@ async function internalBuild() {
3316
3456
  return output;
3317
3457
  }
3318
3458
  async function combineAnalysisStats() {
3319
- const unixFiles = await glob3(`${wxt.config.analysis.outputName}-*.json`, {
3459
+ const unixFiles = await glob4(`${wxt.config.analysis.outputName}-*.json`, {
3320
3460
  cwd: wxt.config.analysis.outputDir,
3321
3461
  absolute: true
3322
3462
  });
@@ -3365,7 +3505,7 @@ async function build(config) {
3365
3505
 
3366
3506
  // src/core/clean.ts
3367
3507
  import path8 from "node:path";
3368
- import glob4 from "fast-glob";
3508
+ import glob5 from "fast-glob";
3369
3509
  import fs14 from "fs-extra";
3370
3510
  import pc6 from "picocolors";
3371
3511
  async function clean(root = process.cwd()) {
@@ -3377,7 +3517,7 @@ async function clean(root = process.cwd()) {
3377
3517
  ".output/*"
3378
3518
  ];
3379
3519
  consola.debug("Looking for:", tempDirs.map(pc6.cyan).join(", "));
3380
- const directories = await glob4(tempDirs, {
3520
+ const directories = await glob5(tempDirs, {
3381
3521
  cwd: path8.resolve(root),
3382
3522
  absolute: true,
3383
3523
  onlyDirectories: true,
@@ -3883,7 +4023,7 @@ import path10 from "node:path";
3883
4023
  import fs16 from "fs-extra";
3884
4024
  import { minimatch as minimatch2 } from "minimatch";
3885
4025
  import JSZip from "jszip";
3886
- import glob5 from "fast-glob";
4026
+ import glob6 from "fast-glob";
3887
4027
  async function zip(config) {
3888
4028
  await registerWxt("build", config);
3889
4029
  const output = await internalBuild();
@@ -3931,7 +4071,7 @@ async function zip(config) {
3931
4071
  }
3932
4072
  async function zipDir(directory, outputPath, options) {
3933
4073
  const archive = new JSZip();
3934
- const files = (await glob5("**/*", {
4074
+ const files = (await glob6("**/*", {
3935
4075
  cwd: directory,
3936
4076
  // Ignore node_modules, otherwise this glob step takes forever
3937
4077
  ignore: ["**/node_modules"],
@@ -4049,7 +4189,7 @@ function createAliasedCommand(base, name, alias, bin, docsUrl) {
4049
4189
  const args = process.argv.slice(
4050
4190
  process.argv.indexOf(aliasedCommand.name) + 1
4051
4191
  );
4052
- const { execa } = await import("./execa-6HO2IY2B.js");
4192
+ const { execa } = await import("./execa-QQUOQNS3.js");
4053
4193
  await execa(bin, args, {
4054
4194
  stdio: "inherit"
4055
4195
  });
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ContentScriptContext } from './index-CiL7hzu6.js';
1
+ import { a as ContentScriptContext } from './index-Bk-a0SkY.js';
2
2
  import 'webextension-polyfill';
3
3
 
4
4
  interface IntegratedContentScriptUi<TMounted> extends ContentScriptUi<TMounted> {
@@ -179,13 +179,13 @@ interface ContentScriptAnchoredOptions {
179
179
  /**
180
180
  * Create a content script UI without any isolation.
181
181
  *
182
- * @see https://wxt.dev/guide/content-script-ui.html#integrated
182
+ * @see https://wxt.dev/guide/key-concepts/content-script-ui.html#integrated
183
183
  */
184
184
  declare function createIntegratedUi<TMounted>(ctx: ContentScriptContext, options: IntegratedContentScriptUiOptions<TMounted>): IntegratedContentScriptUi<TMounted>;
185
185
  /**
186
186
  * Create a content script UI using an iframe.
187
187
  *
188
- * @see https://wxt.dev/guide/content-script-ui.html#iframe
188
+ * @see https://wxt.dev/guide/key-concepts/content-script-ui.html#iframe
189
189
  */
190
190
  declare function createIframeUi<TMounted>(ctx: ContentScriptContext, options: IframeContentScriptUiOptions<TMounted>): IframeContentScriptUi<TMounted>;
191
191
  /**
@@ -193,7 +193,7 @@ declare function createIframeUi<TMounted>(ctx: ContentScriptContext, options: If
193
193
  *
194
194
  * > This function is async because it has to load the CSS via a network call.
195
195
  *
196
- * @see https://wxt.dev/guide/content-script-ui.html#shadowroot
196
+ * @see https://wxt.dev/guide/key-concepts/content-script-ui.html#shadowroot
197
197
  */
198
198
  declare function createShadowRootUi<TMounted>(ctx: ContentScriptContext, options: ShadowRootContentScriptUiOptions<TMounted>): Promise<ShadowRootContentScriptUi<TMounted>>;
199
199