wxt 0.18.3 → 0.18.5

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.
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-VBXJIVYU.js";
13
13
 
14
14
  // package.json
15
- var version = "0.18.2";
15
+ var version = "0.18.5";
16
16
 
17
17
  // src/core/utils/paths.ts
18
18
  import systemPath from "node:path";
@@ -691,6 +691,62 @@ function removeEntrypointMainFunction(config, path8) {
691
691
  };
692
692
  }
693
693
 
694
+ // src/core/builders/vite/plugins/wxtPluginLoader.ts
695
+ import { parseHTML as parseHTML2 } from "linkedom";
696
+ function wxtPluginLoader(config) {
697
+ const virtualModuleId = "virtual:wxt-plugins";
698
+ const resolvedVirtualModuleId = "\0" + virtualModuleId;
699
+ const virtualHtmlModuleId = "virtual:wxt-html-plugins";
700
+ const resolvedVirtualHtmlModuleId = "\0" + virtualHtmlModuleId;
701
+ return {
702
+ name: "wxt:plugin-loader",
703
+ resolveId(id) {
704
+ if (id === virtualModuleId)
705
+ return resolvedVirtualModuleId;
706
+ if (id === virtualHtmlModuleId)
707
+ return resolvedVirtualHtmlModuleId;
708
+ },
709
+ load(id) {
710
+ if (id === resolvedVirtualModuleId) {
711
+ const imports = config.plugins.map(
712
+ (plugin, i) => `import initPlugin${i} from '${normalizePath(plugin)}';`
713
+ ).join("\n");
714
+ const initCalls = config.plugins.map((_, i) => ` initPlugin${i}();`).join("\n");
715
+ return `${imports}
716
+
717
+ export function initPlugins() {
718
+ ${initCalls}
719
+ }`;
720
+ }
721
+ if (id === resolvedVirtualHtmlModuleId) {
722
+ return `import { initPlugins } from '${virtualModuleId}';
723
+
724
+ try {
725
+ initPlugins();
726
+ } catch (err) {
727
+ console.error("[wxt] Failed to initialize plugins", err);
728
+ }`;
729
+ }
730
+ },
731
+ transformIndexHtml: {
732
+ // Use "pre" so the new script is added before vite bundles all the scripts
733
+ order: "pre",
734
+ handler(html, _ctx) {
735
+ const { document } = parseHTML2(html);
736
+ const script = document.createElement("script");
737
+ script.type = "module";
738
+ script.src = "virtual:wxt-html-plugins";
739
+ if (document.head == null) {
740
+ const newHead = document.createElement("head");
741
+ document.documentElement.prepend(newHead);
742
+ }
743
+ document.head.prepend(script);
744
+ return document.toString();
745
+ }
746
+ }
747
+ };
748
+ }
749
+
694
750
  // src/core/utils/strings.ts
695
751
  function kebabCaseAlphanumeric(str) {
696
752
  return str.toLowerCase().replace(/[^a-z0-9-\s]/g, "").replace(/\s+/g, "-");
@@ -750,18 +806,21 @@ async function buildEntrypoints(groups, spinner) {
750
806
  return { publicAssets, steps };
751
807
  }
752
808
  async function copyPublicDirectory() {
753
- const files = await getPublicFiles();
809
+ const files = (await getPublicFiles()).map((file) => ({
810
+ absoluteSrc: resolve6(wxt.config.publicDir, file),
811
+ relativeDest: file
812
+ }));
813
+ await wxt.hooks.callHook("build:publicAssets", wxt, files);
754
814
  if (files.length === 0)
755
815
  return [];
756
816
  const publicAssets = [];
757
- for (const file of files) {
758
- const srcPath = resolve6(wxt.config.publicDir, file);
759
- const outPath = resolve6(wxt.config.outDir, file);
760
- await fs4.ensureDir(dirname3(outPath));
761
- await fs4.copyFile(srcPath, outPath);
817
+ for (const { absoluteSrc, relativeDest } of files) {
818
+ const absoluteDest = resolve6(wxt.config.outDir, relativeDest);
819
+ await fs4.ensureDir(dirname3(absoluteDest));
820
+ await fs4.copyFile(absoluteSrc, absoluteDest);
762
821
  publicAssets.push({
763
822
  type: "asset",
764
- fileName: file
823
+ fileName: relativeDest
765
824
  });
766
825
  }
767
826
  return publicAssets;
@@ -865,7 +924,7 @@ function findEffectedSteps(changedFile, currentOutput) {
865
924
  import { relative as relative4, resolve as resolve8 } from "path";
866
925
  import fs6 from "fs-extra";
867
926
  import { minimatch } from "minimatch";
868
- import { parseHTML as parseHTML2 } from "linkedom";
927
+ import { parseHTML as parseHTML3 } from "linkedom";
869
928
  import JSON5 from "json5";
870
929
  import glob2 from "fast-glob";
871
930
  import pc2 from "picocolors";
@@ -936,7 +995,7 @@ async function importEntrypointFile(path8) {
936
995
  if (err instanceof ReferenceError) {
937
996
  const variableName = err.message.replace(" is not defined", "");
938
997
  throw Error(
939
- `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/entrypoints.html#side-effects`,
998
+ `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/go-further/entrypoint-side-effects.html`,
940
999
  { cause: err }
941
1000
  );
942
1001
  } else {
@@ -972,7 +1031,7 @@ async function findEntrypoints() {
972
1031
  const inputPath = resolve8(wxt.config.entrypointsDir, relativePath);
973
1032
  const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
974
1033
  const matchingGlob = pathGlobs.find(
975
- (glob4) => minimatch(relativePath, glob4)
1034
+ (glob5) => minimatch(relativePath, glob5)
976
1035
  );
977
1036
  if (matchingGlob) {
978
1037
  const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
@@ -1266,7 +1325,7 @@ async function getSidepanelEntrypoint(info) {
1266
1325
  }
1267
1326
  async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
1268
1327
  const content = await fs6.readFile(info.inputPath, "utf-8");
1269
- const { document } = parseHTML2(content);
1328
+ const { document } = parseHTML3(content);
1270
1329
  const options = {};
1271
1330
  const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
1272
1331
  Object.entries(keyMap).forEach(([_key, manifestKey]) => {
@@ -1610,6 +1669,7 @@ function isModuleInstalled(name) {
1610
1669
 
1611
1670
  // src/core/utils/building/resolve-config.ts
1612
1671
  import fs10 from "fs-extra";
1672
+ import glob3 from "fast-glob";
1613
1673
  async function resolveConfig(inlineConfig, command) {
1614
1674
  let userConfig = {};
1615
1675
  let userConfigMetadata;
@@ -1645,6 +1705,7 @@ async function resolveConfig(inlineConfig, command) {
1645
1705
  srcDir,
1646
1706
  mergedConfig.entrypointsDir ?? "entrypoints"
1647
1707
  );
1708
+ const modulesDir = path5.resolve(srcDir, mergedConfig.modulesDir ?? "modules");
1648
1709
  if (await isDirMissing(entrypointsDir)) {
1649
1710
  logMissingDir(logger, "Entrypoints", entrypointsDir);
1650
1711
  }
@@ -1686,11 +1747,20 @@ async function resolveConfig(inlineConfig, command) {
1686
1747
  hostname: "localhost"
1687
1748
  };
1688
1749
  }
1750
+ const modules = await resolveWxtModules(modulesDir, mergedConfig.modules);
1751
+ const moduleOptions = modules.reduce((map, module) => {
1752
+ if (module.configKey) {
1753
+ map[module.configKey] = // @ts-expect-error
1754
+ mergedConfig[module.configKey];
1755
+ }
1756
+ return map;
1757
+ }, {});
1689
1758
  return {
1690
1759
  browser,
1691
1760
  command,
1692
1761
  debug,
1693
1762
  entrypointsDir,
1763
+ modulesDir,
1694
1764
  filterEntrypoints,
1695
1765
  env,
1696
1766
  fsCache: createFsCache(wxtDir),
@@ -1722,7 +1792,10 @@ async function resolveConfig(inlineConfig, command) {
1722
1792
  reloadCommand
1723
1793
  },
1724
1794
  hooks: mergedConfig.hooks ?? {},
1725
- vite: mergedConfig.vite ?? (() => ({}))
1795
+ vite: mergedConfig.vite ?? (() => ({})),
1796
+ modules,
1797
+ plugins: [],
1798
+ ...moduleOptions
1726
1799
  };
1727
1800
  }
1728
1801
  async function resolveManifestConfig(env, manifest) {
@@ -1861,6 +1934,43 @@ async function mergeBuilderConfig(inlineConfig, userConfig) {
1861
1934
  }
1862
1935
  throw Error("Builder not found. Make sure vite is installed.");
1863
1936
  }
1937
+ async function resolveWxtModules(modulesDir, modules = []) {
1938
+ const npmModules = await Promise.all(
1939
+ modules.map(async (moduleId) => {
1940
+ const mod = await import(
1941
+ /* @vite-ignore */
1942
+ moduleId
1943
+ );
1944
+ if (mod.default == null) {
1945
+ throw Error("Module missing default export: " + moduleId);
1946
+ }
1947
+ return mod.default;
1948
+ })
1949
+ );
1950
+ const localModulePaths = await glob3(["*.[tj]s", "*/index.[tj]s"], {
1951
+ cwd: modulesDir,
1952
+ onlyFiles: true
1953
+ }).catch(() => []);
1954
+ const localModules = await Promise.all(
1955
+ localModulePaths.map(async (file) => {
1956
+ const { config } = await loadConfig({
1957
+ configFile: path5.resolve(modulesDir, file),
1958
+ globalRc: false,
1959
+ rcFile: false,
1960
+ packageJson: false,
1961
+ envName: false,
1962
+ dotenv: false
1963
+ });
1964
+ if (config == null)
1965
+ throw Error(
1966
+ `No config found for ${file}. Did you forget to add a default export?`
1967
+ );
1968
+ config.name ??= file;
1969
+ return config;
1970
+ })
1971
+ );
1972
+ return [...npmModules, ...localModules];
1973
+ }
1864
1974
 
1865
1975
  // src/core/utils/building/group-entrypoints.ts
1866
1976
  function groupEntrypoints(entrypoints) {
@@ -2016,7 +2126,7 @@ function getChunkSortWeight(filename) {
2016
2126
  import pc4 from "picocolors";
2017
2127
 
2018
2128
  // src/core/utils/building/internal-build.ts
2019
- import glob3 from "fast-glob";
2129
+ import glob4 from "fast-glob";
2020
2130
 
2021
2131
  // src/core/utils/manifest.ts
2022
2132
  import fs12 from "fs-extra";
@@ -2808,7 +2918,7 @@ async function internalBuild() {
2808
2918
  return output;
2809
2919
  }
2810
2920
  async function combineAnalysisStats() {
2811
- const unixFiles = await glob3(`${wxt.config.analysis.outputName}-*.json`, {
2921
+ const unixFiles = await glob4(`${wxt.config.analysis.outputName}-*.json`, {
2812
2922
  cwd: wxt.config.analysis.outputDir,
2813
2923
  absolute: true
2814
2924
  });
@@ -2869,7 +2979,7 @@ var npm = {
2869
2979
  overridesKey: "overrides",
2870
2980
  async downloadDependency(id, downloadDir) {
2871
2981
  await ensureDir3(downloadDir);
2872
- const { execa } = await import("./execa-VDW6HLFV.js");
2982
+ const { execa } = await import("./execa-5TSWMF32.js");
2873
2983
  const res = await execa("npm", ["pack", id, "--json"], {
2874
2984
  cwd: downloadDir
2875
2985
  });
@@ -2881,7 +2991,7 @@ var npm = {
2881
2991
  if (options?.all) {
2882
2992
  args.push("--depth", "Infinity");
2883
2993
  }
2884
- const { execa } = await import("./execa-VDW6HLFV.js");
2994
+ const { execa } = await import("./execa-5TSWMF32.js");
2885
2995
  const res = await execa("npm", args, { cwd: options?.cwd });
2886
2996
  const project = JSON.parse(res.stdout);
2887
2997
  return flattenNpmListOutput([project]);
@@ -2938,7 +3048,7 @@ var bun = {
2938
3048
  if (options?.all) {
2939
3049
  args.push("--all");
2940
3050
  }
2941
- const { execa } = await import("./execa-VDW6HLFV.js");
3051
+ const { execa } = await import("./execa-5TSWMF32.js");
2942
3052
  const res = await execa("bun", args, { cwd: options?.cwd });
2943
3053
  return dedupeDependencies(
2944
3054
  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 }))
@@ -2957,7 +3067,7 @@ var yarn = {
2957
3067
  if (options?.all) {
2958
3068
  args.push("--depth", "Infinity");
2959
3069
  }
2960
- const { execa } = await import("./execa-VDW6HLFV.js");
3070
+ const { execa } = await import("./execa-5TSWMF32.js");
2961
3071
  const res = await execa("yarn", args, { cwd: options?.cwd });
2962
3072
  const tree = res.stdout.split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
2963
3073
  if (tree == null)
@@ -2994,7 +3104,7 @@ var pnpm = {
2994
3104
  if (typeof process !== "undefined" && process.env.WXT_PNPM_IGNORE_WORKSPACE === "true") {
2995
3105
  args.push("--ignore-workspace");
2996
3106
  }
2997
- const { execa } = await import("./execa-VDW6HLFV.js");
3107
+ const { execa } = await import("./execa-5TSWMF32.js");
2998
3108
  const res = await execa("pnpm", args, { cwd: options?.cwd });
2999
3109
  const projects = JSON.parse(res.stdout);
3000
3110
  return flattenNpmListOutput(projects);
@@ -3088,7 +3198,8 @@ async function createViteBuilder(wxtConfig, hooks, server) {
3088
3198
  noopBackground(),
3089
3199
  globals(wxtConfig),
3090
3200
  excludeBrowserPolyfill(wxtConfig),
3091
- defineImportMeta()
3201
+ defineImportMeta(),
3202
+ wxtPluginLoader(wxtConfig)
3092
3203
  );
3093
3204
  if (wxtConfig.analysis.enabled) {
3094
3205
  config.plugins.push(bundleAnalysis(wxtConfig));
@@ -3324,6 +3435,19 @@ async function registerWxt(command, inlineConfig = {}, getServer) {
3324
3435
  builder,
3325
3436
  server
3326
3437
  };
3438
+ for (const module of config.modules) {
3439
+ if (module.hooks)
3440
+ wxt.hooks.addHooks(module.hooks);
3441
+ if (wxt.config.imports !== false && module.imports) {
3442
+ wxt.config.imports.imports ??= [];
3443
+ wxt.config.imports.imports.push(...module.imports);
3444
+ }
3445
+ await module.setup?.(
3446
+ wxt,
3447
+ // @ts-expect-error: Untyped configKey field
3448
+ module.configKey ? config[module.configKey] : void 0
3449
+ );
3450
+ }
3327
3451
  wxt.hooks.addHooks(config.hooks);
3328
3452
  await wxt.hooks.callHook("ready", wxt);
3329
3453
  }
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]) => {
@@ -2109,6 +2182,7 @@ function isModuleInstalled(name) {
2109
2182
 
2110
2183
  // src/core/utils/building/resolve-config.ts
2111
2184
  import fs10 from "fs-extra";
2185
+ import glob3 from "fast-glob";
2112
2186
  async function resolveConfig(inlineConfig, command) {
2113
2187
  let userConfig = {};
2114
2188
  let userConfigMetadata;
@@ -2144,6 +2218,7 @@ async function resolveConfig(inlineConfig, command) {
2144
2218
  srcDir,
2145
2219
  mergedConfig.entrypointsDir ?? "entrypoints"
2146
2220
  );
2221
+ const modulesDir = path6.resolve(srcDir, mergedConfig.modulesDir ?? "modules");
2147
2222
  if (await isDirMissing(entrypointsDir)) {
2148
2223
  logMissingDir(logger, "Entrypoints", entrypointsDir);
2149
2224
  }
@@ -2185,11 +2260,20 @@ async function resolveConfig(inlineConfig, command) {
2185
2260
  hostname: "localhost"
2186
2261
  };
2187
2262
  }
2263
+ const modules = await resolveWxtModules(modulesDir, mergedConfig.modules);
2264
+ const moduleOptions = modules.reduce((map, module) => {
2265
+ if (module.configKey) {
2266
+ map[module.configKey] = // @ts-expect-error
2267
+ mergedConfig[module.configKey];
2268
+ }
2269
+ return map;
2270
+ }, {});
2188
2271
  return {
2189
2272
  browser,
2190
2273
  command,
2191
2274
  debug,
2192
2275
  entrypointsDir,
2276
+ modulesDir,
2193
2277
  filterEntrypoints,
2194
2278
  env,
2195
2279
  fsCache: createFsCache(wxtDir),
@@ -2221,7 +2305,10 @@ async function resolveConfig(inlineConfig, command) {
2221
2305
  reloadCommand
2222
2306
  },
2223
2307
  hooks: mergedConfig.hooks ?? {},
2224
- vite: mergedConfig.vite ?? (() => ({}))
2308
+ vite: mergedConfig.vite ?? (() => ({})),
2309
+ modules,
2310
+ plugins: [],
2311
+ ...moduleOptions
2225
2312
  };
2226
2313
  }
2227
2314
  async function resolveManifestConfig(env, manifest) {
@@ -2360,6 +2447,43 @@ async function mergeBuilderConfig(inlineConfig, userConfig) {
2360
2447
  }
2361
2448
  throw Error("Builder not found. Make sure vite is installed.");
2362
2449
  }
2450
+ async function resolveWxtModules(modulesDir, modules = []) {
2451
+ const npmModules = await Promise.all(
2452
+ modules.map(async (moduleId) => {
2453
+ const mod = await import(
2454
+ /* @vite-ignore */
2455
+ moduleId
2456
+ );
2457
+ if (mod.default == null) {
2458
+ throw Error("Module missing default export: " + moduleId);
2459
+ }
2460
+ return mod.default;
2461
+ })
2462
+ );
2463
+ const localModulePaths = await glob3(["*.[tj]s", "*/index.[tj]s"], {
2464
+ cwd: modulesDir,
2465
+ onlyFiles: true
2466
+ }).catch(() => []);
2467
+ const localModules = await Promise.all(
2468
+ localModulePaths.map(async (file) => {
2469
+ const { config } = await loadConfig({
2470
+ configFile: path6.resolve(modulesDir, file),
2471
+ globalRc: false,
2472
+ rcFile: false,
2473
+ packageJson: false,
2474
+ envName: false,
2475
+ dotenv: false
2476
+ });
2477
+ if (config == null)
2478
+ throw Error(
2479
+ `No config found for ${file}. Did you forget to add a default export?`
2480
+ );
2481
+ config.name ??= file;
2482
+ return config;
2483
+ })
2484
+ );
2485
+ return [...npmModules, ...localModules];
2486
+ }
2363
2487
 
2364
2488
  // src/core/utils/building/group-entrypoints.ts
2365
2489
  function groupEntrypoints(entrypoints) {
@@ -2515,7 +2639,7 @@ function getChunkSortWeight(filename) {
2515
2639
  import pc4 from "picocolors";
2516
2640
 
2517
2641
  // package.json
2518
- var version = "0.18.2";
2642
+ var version = "0.18.5";
2519
2643
 
2520
2644
  // src/core/utils/log/printHeader.ts
2521
2645
  function printHeader() {
@@ -2524,7 +2648,7 @@ function printHeader() {
2524
2648
  }
2525
2649
 
2526
2650
  // src/core/utils/building/internal-build.ts
2527
- import glob3 from "fast-glob";
2651
+ import glob4 from "fast-glob";
2528
2652
 
2529
2653
  // src/core/utils/manifest.ts
2530
2654
  import fs12 from "fs-extra";
@@ -3316,7 +3440,7 @@ async function internalBuild() {
3316
3440
  return output;
3317
3441
  }
3318
3442
  async function combineAnalysisStats() {
3319
- const unixFiles = await glob3(`${wxt.config.analysis.outputName}-*.json`, {
3443
+ const unixFiles = await glob4(`${wxt.config.analysis.outputName}-*.json`, {
3320
3444
  cwd: wxt.config.analysis.outputDir,
3321
3445
  absolute: true
3322
3446
  });
@@ -3365,7 +3489,7 @@ async function build(config) {
3365
3489
 
3366
3490
  // src/core/clean.ts
3367
3491
  import path8 from "node:path";
3368
- import glob4 from "fast-glob";
3492
+ import glob5 from "fast-glob";
3369
3493
  import fs14 from "fs-extra";
3370
3494
  import pc6 from "picocolors";
3371
3495
  async function clean(root = process.cwd()) {
@@ -3377,7 +3501,7 @@ async function clean(root = process.cwd()) {
3377
3501
  ".output/*"
3378
3502
  ];
3379
3503
  consola.debug("Looking for:", tempDirs.map(pc6.cyan).join(", "));
3380
- const directories = await glob4(tempDirs, {
3504
+ const directories = await glob5(tempDirs, {
3381
3505
  cwd: path8.resolve(root),
3382
3506
  absolute: true,
3383
3507
  onlyDirectories: true,
@@ -3883,7 +4007,7 @@ import path10 from "node:path";
3883
4007
  import fs16 from "fs-extra";
3884
4008
  import { minimatch as minimatch2 } from "minimatch";
3885
4009
  import JSZip from "jszip";
3886
- import glob5 from "fast-glob";
4010
+ import glob6 from "fast-glob";
3887
4011
  async function zip(config) {
3888
4012
  await registerWxt("build", config);
3889
4013
  const output = await internalBuild();
@@ -3931,17 +4055,14 @@ async function zip(config) {
3931
4055
  }
3932
4056
  async function zipDir(directory, outputPath, options) {
3933
4057
  const archive = new JSZip();
3934
- const files = (await glob5("**/*", {
4058
+ const files = (await glob6("**/*", {
3935
4059
  cwd: directory,
3936
4060
  // Ignore node_modules, otherwise this glob step takes forever
3937
4061
  ignore: ["**/node_modules"],
3938
- onlyFiles: true
4062
+ onlyFiles: true,
4063
+ dot: true
3939
4064
  })).filter((relativePath) => {
3940
- return wxt.config.zip.includeSources.some(
3941
- (pattern) => minimatch2(relativePath, pattern)
3942
- ) || !wxt.config.zip.excludeSources.some(
3943
- (pattern) => minimatch2(relativePath, pattern)
3944
- );
4065
+ return options?.include?.some((pattern) => minimatch2(relativePath, pattern)) || !options?.exclude?.some((pattern) => minimatch2(relativePath, pattern));
3945
4066
  });
3946
4067
  const filesToZip = [
3947
4068
  ...files,
@@ -4052,7 +4173,7 @@ function createAliasedCommand(base, name, alias, bin, docsUrl) {
4052
4173
  const args = process.argv.slice(
4053
4174
  process.argv.indexOf(aliasedCommand.name) + 1
4054
4175
  );
4055
- const { execa } = await import("./execa-6HO2IY2B.js");
4176
+ const { execa } = await import("./execa-QQUOQNS3.js");
4056
4177
  await execa(bin, args, {
4057
4178
  stdio: "inherit"
4058
4179
  });