wxt 0.2.4 → 0.3.0

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/index.cjs CHANGED
@@ -39,22 +39,36 @@ __export(src_exports, {
39
39
  module.exports = __toCommonJS(src_exports);
40
40
 
41
41
  // src/core/utils/getInternalConfig.ts
42
- var import_node_path3 = __toESM(require("path"), 1);
43
- var vite = __toESM(require("vite"), 1);
42
+ var import_node_path4 = __toESM(require("path"), 1);
43
+ var vite2 = __toESM(require("vite"), 1);
44
44
  var import_consola = require("consola");
45
45
 
46
46
  // src/core/utils/entrypoints.ts
47
+ var import_node_path2 = __toESM(require("path"), 1);
48
+
49
+ // src/core/utils/paths.ts
47
50
  var import_node_path = __toESM(require("path"), 1);
51
+ var vite = __toESM(require("vite"), 1);
52
+ function normalizePath2(path5) {
53
+ return vite.normalizePath(path5);
54
+ }
55
+ function unnormalizePath(path5) {
56
+ return import_node_path.default.normalize(path5);
57
+ }
58
+
59
+ // src/core/utils/entrypoints.ts
48
60
  function getEntrypointName(entrypointsDir, inputPath) {
49
- const relativePath = import_node_path.default.relative(entrypointsDir, inputPath);
50
- const name = relativePath.split(/[\.\/]/, 2)[0];
61
+ const relativePath = import_node_path2.default.relative(entrypointsDir, inputPath);
62
+ const name = relativePath.split(/[\.\/\\]/, 2)[0];
51
63
  return name;
52
64
  }
53
65
  function getEntrypointOutputFile(entrypoint, ext) {
54
- return (0, import_node_path.resolve)(entrypoint.outputDir, `${entrypoint.name}${ext}`);
66
+ return (0, import_node_path2.resolve)(entrypoint.outputDir, `${entrypoint.name}${ext}`);
55
67
  }
56
68
  function getEntrypointBundlePath(entrypoint, outDir, ext) {
57
- return (0, import_node_path.relative)(outDir, getEntrypointOutputFile(entrypoint, ext));
69
+ return normalizePath2(
70
+ (0, import_node_path2.relative)(outDir, getEntrypointOutputFile(entrypoint, ext))
71
+ );
58
72
  }
59
73
 
60
74
  // src/core/vite-plugins/devHtmlPrerender.ts
@@ -208,7 +222,7 @@ function download(config) {
208
222
  }
209
223
 
210
224
  // src/core/vite-plugins/multipageMove.ts
211
- var import_node_path2 = require("path");
225
+ var import_node_path3 = require("path");
212
226
  var import_fs_extra = __toESM(require("fs-extra"), 1);
213
227
  function multipageMove(entrypoints, config) {
214
228
  return {
@@ -216,7 +230,7 @@ function multipageMove(entrypoints, config) {
216
230
  async writeBundle(_, bundle) {
217
231
  for (const oldBundlePath in bundle) {
218
232
  const entrypoint = entrypoints.find(
219
- (entry) => !!entry.inputPath.endsWith(oldBundlePath)
233
+ (entry) => !!normalizePath2(entry.inputPath).endsWith(oldBundlePath)
220
234
  );
221
235
  if (entrypoint == null) {
222
236
  config.logger.debug("No entrypoint found for", oldBundlePath);
@@ -225,7 +239,7 @@ function multipageMove(entrypoints, config) {
225
239
  const newBundlePath = getEntrypointBundlePath(
226
240
  entrypoint,
227
241
  config.outDir,
228
- (0, import_node_path2.extname)(oldBundlePath)
242
+ (0, import_node_path3.extname)(oldBundlePath)
229
243
  );
230
244
  if (newBundlePath === oldBundlePath) {
231
245
  config.logger.debug(
@@ -234,9 +248,9 @@ function multipageMove(entrypoints, config) {
234
248
  );
235
249
  continue;
236
250
  }
237
- const oldAbsPath = (0, import_node_path2.resolve)(config.outDir, oldBundlePath);
238
- const newAbsPath = (0, import_node_path2.resolve)(config.outDir, newBundlePath);
239
- await (0, import_fs_extra.ensureDir)((0, import_node_path2.dirname)(newAbsPath));
251
+ const oldAbsPath = (0, import_node_path3.resolve)(config.outDir, oldBundlePath);
252
+ const newAbsPath = (0, import_node_path3.resolve)(config.outDir, newBundlePath);
253
+ await (0, import_fs_extra.ensureDir)((0, import_node_path3.dirname)(newAbsPath));
240
254
  await import_fs_extra.default.move(oldAbsPath, newAbsPath, { overwrite: true });
241
255
  const renamedChunk = {
242
256
  ...bundle[oldBundlePath],
@@ -257,13 +271,10 @@ var import_vite = require("vite");
257
271
  function getUnimportOptions(config) {
258
272
  const defaultOptions = {
259
273
  debugLog: config.logger.debug,
260
- imports: [
261
- { name: "*", as: "browser", from: "webextension-polyfill" },
262
- { name: "defineConfig", from: "wxt" }
263
- ],
264
- presets: [{ package: "wxt/client" }],
274
+ imports: [{ name: "defineConfig", from: "wxt" }],
275
+ presets: [{ package: "wxt/client" }, { package: "wxt/browser" }],
265
276
  warn: config.logger.warn,
266
- dirs: ["components", "composables", "hooks", "utils"]
277
+ dirs: ["./components/*", "./composables/*", "./hooks/*", "./utils/*"]
267
278
  };
268
279
  return (0, import_vite.mergeConfig)(
269
280
  defaultOptions,
@@ -309,7 +320,7 @@ function virtualEntrypoin(type, config) {
309
320
  const index = id.indexOf(virtualId);
310
321
  if (index === -1)
311
322
  return;
312
- const inputPath = id.substring(index + virtualId.length);
323
+ const inputPath = normalizePath2(id.substring(index + virtualId.length));
313
324
  return resolvedVirtualId + inputPath;
314
325
  },
315
326
  async load(id) {
@@ -337,6 +348,26 @@ function tsconfigPaths(config) {
337
348
  });
338
349
  }
339
350
 
351
+ // src/core/vite-plugins/noopBackground.ts
352
+ function noopBackground() {
353
+ const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
354
+ const resolvedVirtualModuleId = "\0" + virtualModuleId;
355
+ return {
356
+ name: "wxt:noop-background",
357
+ resolveId(id) {
358
+ if (id === virtualModuleId)
359
+ return resolvedVirtualModuleId;
360
+ },
361
+ load(id) {
362
+ if (id === resolvedVirtualModuleId) {
363
+ return `import { defineBackground } from 'wxt/client';
364
+ export default defineBackground(() => void 0)`;
365
+ }
366
+ }
367
+ };
368
+ }
369
+ var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
370
+
340
371
  // src/core/utils/createFsCache.ts
341
372
  var import_fs_extra3 = __toESM(require("fs-extra"), 1);
342
373
  var import_path4 = require("path");
@@ -370,7 +401,7 @@ function getGlobals(config) {
370
401
  {
371
402
  name: "__BROWSER__",
372
403
  value: config.browser,
373
- type: `"chromium" | "firefox"`
404
+ type: `string`
374
405
  },
375
406
  {
376
407
  name: "__IS_CHROME__",
@@ -408,12 +439,12 @@ function getGlobals(config) {
408
439
  // src/core/utils/getInternalConfig.ts
409
440
  var import_c12 = require("c12");
410
441
  async function getInternalConfig(config, command) {
411
- const root = config.root ? import_node_path3.default.resolve(config.root) : process.cwd();
442
+ const root = config.root ? import_node_path4.default.resolve(config.root) : process.cwd();
412
443
  const mode = config.mode ?? (command === "build" ? "production" : "development");
413
444
  const browser = config.browser ?? "chrome";
414
445
  const manifestVersion = config.manifestVersion ?? (browser == "firefox" ? 2 : 3);
415
- const outBaseDir = import_node_path3.default.resolve(root, ".output");
416
- const outDir = import_node_path3.default.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
446
+ const outBaseDir = import_node_path4.default.resolve(root, ".output");
447
+ const outDir = import_node_path4.default.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
417
448
  const logger = config.logger ?? import_consola.consola;
418
449
  const baseConfig = {
419
450
  root,
@@ -446,22 +477,22 @@ async function getInternalConfig(config, command) {
446
477
  });
447
478
  userConfig = loaded.config ?? {};
448
479
  }
449
- const merged = vite.mergeConfig(
480
+ const merged = vite2.mergeConfig(
450
481
  baseConfig,
451
482
  userConfig
452
483
  );
453
- const srcDir = userConfig.srcDir ? (0, import_node_path3.resolve)(root, userConfig.srcDir) : root;
454
- const entrypointsDir = (0, import_node_path3.resolve)(
484
+ const srcDir = userConfig.srcDir ? (0, import_node_path4.resolve)(root, userConfig.srcDir) : root;
485
+ const entrypointsDir = (0, import_node_path4.resolve)(
455
486
  srcDir,
456
487
  userConfig.entrypointsDir ?? "entrypoints"
457
488
  );
458
- const publicDir = (0, import_node_path3.resolve)(srcDir, userConfig.publicDir ?? "public");
459
- const wxtDir = (0, import_node_path3.resolve)(srcDir, ".wxt");
460
- const typesDir = (0, import_node_path3.resolve)(wxtDir, "types");
489
+ const publicDir = (0, import_node_path4.resolve)(root, userConfig.publicDir ?? "public");
490
+ const wxtDir = (0, import_node_path4.resolve)(srcDir, ".wxt");
491
+ const typesDir = (0, import_node_path4.resolve)(wxtDir, "types");
461
492
  const env = { mode, browser, manifestVersion, command };
462
493
  const userManifest = await resolveManifestConfig(env, userConfig.manifest);
463
494
  const inlineManifest = await resolveManifestConfig(env, config.manifest);
464
- const manifest = vite.mergeConfig(userManifest, inlineManifest);
495
+ const manifest = vite2.mergeConfig(userManifest, inlineManifest);
465
496
  const finalConfig = {
466
497
  ...merged,
467
498
  srcDir,
@@ -510,6 +541,7 @@ async function getInternalConfig(config, command) {
510
541
  );
511
542
  finalConfig.vite.plugins.push(devServerGlobals(finalConfig));
512
543
  finalConfig.vite.plugins.push(tsconfigPaths(finalConfig));
544
+ finalConfig.vite.plugins.push(noopBackground());
513
545
  finalConfig.vite.define ??= {};
514
546
  getGlobals(finalConfig).forEach((global) => {
515
547
  finalConfig.vite.define[global.name] = JSON.stringify(global.value);
@@ -522,7 +554,7 @@ async function resolveManifestConfig(env, manifest) {
522
554
 
523
555
  // src/index.ts
524
556
  var import_picocolors3 = __toESM(require("picocolors"), 1);
525
- var vite5 = __toESM(require("vite"), 1);
557
+ var vite6 = __toESM(require("vite"), 1);
526
558
 
527
559
  // src/core/utils/arrays.ts
528
560
  function every(array, predicate) {
@@ -595,11 +627,12 @@ function detectDevChanges(changedFiles, currentOutput) {
595
627
  }
596
628
  function findEffectedSteps(changedFile, currentOutput) {
597
629
  const changes = [];
598
- const changedPath = changedFile[1];
630
+ const changedPath = normalizePath2(changedFile[1]);
599
631
  const isChunkEffected = (chunk) => (
600
632
  // If it's an HTML file with the same path, is is effected because HTML files need to be pre-rendered
601
- // TODO: use bundle path to support `<name>/index.html`?
633
+ // fileName is normalized, relative bundle path
602
634
  chunk.type === "asset" && changedPath.endsWith(chunk.fileName) || // If it's a chunk that depends on the changed file, it is effected
635
+ // moduleIds are absolute, normalized paths
603
636
  chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
604
637
  );
605
638
  for (const step of currentOutput.steps) {
@@ -618,10 +651,10 @@ function findEffectedSteps(changedFile, currentOutput) {
618
651
  // src/index.ts
619
652
  var import_async_mutex = require("async-mutex");
620
653
  var import_consola2 = require("consola");
621
- var import_node_path6 = require("path");
654
+ var import_node_path7 = require("path");
622
655
 
623
656
  // src/core/build/buildEntrypoints.ts
624
- var vite2 = __toESM(require("vite"), 1);
657
+ var vite3 = __toESM(require("vite"), 1);
625
658
 
626
659
  // src/core/utils/removeEmptyDirs.ts
627
660
  var import_fs_extra4 = __toESM(require("fs-extra"), 1);
@@ -642,9 +675,20 @@ async function removeEmptyDirs(dir) {
642
675
  }
643
676
 
644
677
  // src/core/build/buildEntrypoints.ts
645
- var import_fast_glob = __toESM(require("fast-glob"), 1);
646
- var import_fs_extra5 = __toESM(require("fs-extra"), 1);
678
+ var import_fs_extra6 = __toESM(require("fs-extra"), 1);
647
679
  var import_path6 = require("path");
680
+
681
+ // src/core/utils/public.ts
682
+ var import_fs_extra5 = __toESM(require("fs-extra"), 1);
683
+ var import_fast_glob = __toESM(require("fast-glob"), 1);
684
+ async function getPublicFiles(config) {
685
+ if (!await import_fs_extra5.default.exists(config.publicDir))
686
+ return [];
687
+ const files = await (0, import_fast_glob.default)("**/*", { cwd: config.publicDir });
688
+ return files.map(unnormalizePath);
689
+ }
690
+
691
+ // src/core/build/buildEntrypoints.ts
648
692
  async function buildEntrypoints(groups, config) {
649
693
  const steps = [];
650
694
  for (const group of groups) {
@@ -683,11 +727,11 @@ async function buildSingleEntrypoint(entrypoint, config) {
683
727
  }
684
728
  }
685
729
  };
686
- const entryConfig = vite2.mergeConfig(
730
+ const entryConfig = vite3.mergeConfig(
687
731
  libMode,
688
732
  config.vite
689
733
  );
690
- const result = await vite2.build(entryConfig);
734
+ const result = await vite3.build(entryConfig);
691
735
  return {
692
736
  entrypoints: entrypoint,
693
737
  chunks: getBuildOutputChunks(result)
@@ -713,11 +757,11 @@ async function buildMultipleEntrypoints(entrypoints, config) {
713
757
  }
714
758
  }
715
759
  };
716
- const entryConfig = vite2.mergeConfig(
760
+ const entryConfig = vite3.mergeConfig(
717
761
  multiPage,
718
762
  config.vite
719
763
  );
720
- const result = await vite2.build(entryConfig);
764
+ const result = await vite3.build(entryConfig);
721
765
  return {
722
766
  entrypoints,
723
767
  chunks: getBuildOutputChunks(result)
@@ -731,21 +775,21 @@ function getBuildOutputChunks(result) {
731
775
  return result.output;
732
776
  }
733
777
  async function copyPublicDirectory(config) {
778
+ const files = await getPublicFiles(config);
779
+ if (files.length === 0)
780
+ return [];
734
781
  const publicAssets = [];
735
- if (!await import_fs_extra5.default.exists(config.publicDir))
736
- return publicAssets;
737
- const files = await (0, import_fast_glob.default)("**/*", { cwd: config.publicDir });
738
782
  for (const file of files) {
739
783
  const srcPath = (0, import_path6.resolve)(config.publicDir, file);
740
784
  const outPath = (0, import_path6.resolve)(config.outDir, file);
741
- await import_fs_extra5.default.ensureDir((0, import_path6.dirname)(outPath));
742
- await import_fs_extra5.default.copyFile(srcPath, outPath);
785
+ await import_fs_extra6.default.ensureDir((0, import_path6.dirname)(outPath));
786
+ await import_fs_extra6.default.copyFile(srcPath, outPath);
743
787
  publicAssets.push({
744
788
  type: "asset",
745
789
  fileName: file,
746
790
  name: file,
747
791
  needsCodeReference: false,
748
- source: await import_fs_extra5.default.readFile(srcPath)
792
+ source: await import_fs_extra6.default.readFile(srcPath)
749
793
  });
750
794
  }
751
795
  return publicAssets;
@@ -753,7 +797,7 @@ async function copyPublicDirectory(config) {
753
797
 
754
798
  // src/core/build/findEntrypoints.ts
755
799
  var import_path8 = require("path");
756
- var import_fs_extra7 = __toESM(require("fs-extra"), 1);
800
+ var import_fs_extra8 = __toESM(require("fs-extra"), 1);
757
801
  var import_picomatch = __toESM(require("picomatch"), 1);
758
802
  var import_linkedom2 = require("linkedom");
759
803
  var import_json5 = __toESM(require("json5"), 1);
@@ -761,20 +805,30 @@ var import_json5 = __toESM(require("json5"), 1);
761
805
  // src/core/utils/importTsFile.ts
762
806
  var import_jiti = __toESM(require("jiti"), 1);
763
807
  var import_unimport2 = require("unimport");
764
- var import_fs_extra6 = __toESM(require("fs-extra"), 1);
808
+ var import_fs_extra7 = __toESM(require("fs-extra"), 1);
765
809
  var import_path7 = require("path");
766
810
  var import_babel = __toESM(require("jiti/dist/babel"), 1);
811
+
812
+ // src/core/utils/strings.ts
813
+ function removeImportStatements(text) {
814
+ return text.replace(
815
+ /(import\s?[{\w][\s\S]*?from\s?["'][\s\S]*?["'];?|import\s?["'][\s\S]*?["'];?)/gm,
816
+ ""
817
+ );
818
+ }
819
+
820
+ // src/core/utils/importTsFile.ts
767
821
  async function importTsFile(path5, config) {
768
822
  config.logger.debug("Loading file metadata:", path5);
823
+ const normalPath = normalizePath2(path5);
769
824
  const unimport2 = (0, import_unimport2.createUnimport)({
770
825
  ...getUnimportOptions(config),
771
826
  // Only allow specific imports, not all from the project
772
- imports: [{ name: "*", as: "browser", from: "webextension-polyfill" }],
773
827
  dirs: []
774
828
  });
775
829
  await unimport2.init();
776
- const text = await import_fs_extra6.default.readFile(path5, "utf-8");
777
- const textNoImports = text.replace(/import.*[\n;]/gm, "");
830
+ const text = await import_fs_extra7.default.readFile(path5, "utf-8");
831
+ const textNoImports = removeImportStatements(text);
778
832
  const { code } = await unimport2.injectImports(textNoImports);
779
833
  config.logger.debug(
780
834
  ["Text:", text, "No imports:", textNoImports, "Code:", code].join("\n")
@@ -790,7 +844,7 @@ async function importTsFile(path5, config) {
790
844
  )
791
845
  },
792
846
  transform(opts) {
793
- if (opts.filename === path5)
847
+ if (opts.filename === normalPath)
794
848
  return (0, import_babel.default)({ ...opts, source: code });
795
849
  else
796
850
  return (0, import_babel.default)(opts);
@@ -814,6 +868,7 @@ async function findEntrypoints(config) {
814
868
  const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
815
869
  const existingNames = {};
816
870
  const entrypoints = [];
871
+ let hasBackground = false;
817
872
  await Promise.all(
818
873
  relativePaths.map(async (relativePath) => {
819
874
  const path5 = (0, import_path8.resolve)(config.entrypointsDir, relativePath);
@@ -843,6 +898,7 @@ ${JSON.stringify(
843
898
  break;
844
899
  case "background":
845
900
  entrypoint = await getBackgroundEntrypoint(config, path5);
901
+ hasBackground = true;
846
902
  break;
847
903
  case "content-script":
848
904
  entrypoint = await getContentScriptEntrypoint(
@@ -872,11 +928,16 @@ ${JSON.stringify(
872
928
  existingNames[entrypoint.name] = entrypoint;
873
929
  })
874
930
  );
931
+ if (config.command === "serve" && !hasBackground) {
932
+ entrypoints.push(
933
+ await getBackgroundEntrypoint(config, VIRTUAL_NOOP_BACKGROUND_MODULE_ID)
934
+ );
935
+ }
875
936
  return entrypoints;
876
937
  }
877
938
  async function getPopupEntrypoint(config, path5) {
878
939
  const options = {};
879
- const content = await import_fs_extra7.default.readFile(path5, "utf-8");
940
+ const content = await import_fs_extra8.default.readFile(path5, "utf-8");
880
941
  const { document } = (0, import_linkedom2.parseHTML)(content);
881
942
  const title = document.querySelector("title");
882
943
  if (title != null)
@@ -906,7 +967,7 @@ async function getPopupEntrypoint(config, path5) {
906
967
  }
907
968
  async function getOptionsEntrypoint(config, path5) {
908
969
  const options = {};
909
- const content = await import_fs_extra7.default.readFile(path5, "utf-8");
970
+ const content = await import_fs_extra8.default.readFile(path5, "utf-8");
910
971
  const { document } = (0, import_linkedom2.parseHTML)(content);
911
972
  const openInTabContent = document.querySelector("meta[name='manifest.open_in_tab']")?.getAttribute("content");
912
973
  if (openInTabContent) {
@@ -929,9 +990,17 @@ async function getOptionsEntrypoint(config, path5) {
929
990
  };
930
991
  }
931
992
  async function getBackgroundEntrypoint(config, path5) {
932
- const { main: _, ...options } = await importTsFile(path5, config);
933
- if (options == null) {
934
- throw Error("Background script does not have a default export");
993
+ let options = {};
994
+ if (path5 !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
995
+ const defaultExport = await importTsFile(
996
+ path5,
997
+ config
998
+ );
999
+ if (defaultExport == null) {
1000
+ throw Error("Background script does not have a default export");
1001
+ }
1002
+ const { main: _, ...moduleOptions } = defaultExport;
1003
+ options = moduleOptions;
935
1004
  }
936
1005
  return {
937
1006
  type: "background",
@@ -975,6 +1044,7 @@ var PATH_GLOB_TO_TYPE_MAP = {
975
1044
  "devtools.html": "devtools",
976
1045
  "devtools/index.html": "devtools",
977
1046
  "background.ts": "background",
1047
+ [VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
978
1048
  "content.ts?(x)": "content-script",
979
1049
  "content/index.ts?(x)": "content-script",
980
1050
  "*.content.ts?(x)": "content-script",
@@ -992,10 +1062,10 @@ var PATH_GLOB_TO_TYPE_MAP = {
992
1062
 
993
1063
  // src/core/build/generateTypesDir.ts
994
1064
  var import_unimport3 = require("unimport");
995
- var import_fs_extra8 = __toESM(require("fs-extra"), 1);
1065
+ var import_fs_extra9 = __toESM(require("fs-extra"), 1);
996
1066
  var import_path9 = require("path");
997
1067
  async function generateTypesDir(entrypoints, config) {
998
- await import_fs_extra8.default.ensureDir(config.typesDir);
1068
+ await import_fs_extra9.default.ensureDir(config.typesDir);
999
1069
  const references = [];
1000
1070
  references.push(await writeImportsDeclarationFile(config));
1001
1071
  references.push(await writePathsDeclarationFile(entrypoints, config));
@@ -1007,7 +1077,7 @@ async function writeImportsDeclarationFile(config) {
1007
1077
  const filePath = (0, import_path9.resolve)(config.typesDir, "imports.d.ts");
1008
1078
  const unimport2 = (0, import_unimport3.createUnimport)(getUnimportOptions(config));
1009
1079
  await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
1010
- await import_fs_extra8.default.writeFile(
1080
+ await import_fs_extra9.default.writeFile(
1011
1081
  filePath,
1012
1082
  ["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
1013
1083
  "\n"
@@ -1017,28 +1087,34 @@ async function writeImportsDeclarationFile(config) {
1017
1087
  }
1018
1088
  async function writePathsDeclarationFile(entrypoints, config) {
1019
1089
  const filePath = (0, import_path9.resolve)(config.typesDir, "paths.d.ts");
1020
- const unions = entrypoints.map((entry) => {
1021
- const path5 = getEntrypointBundlePath(
1090
+ const unions = entrypoints.map(
1091
+ (entry) => getEntrypointBundlePath(
1022
1092
  entry,
1023
1093
  config.outDir,
1024
1094
  entry.inputPath.endsWith(".html") ? ".html" : ".js"
1025
- );
1026
- return ` | "/${path5}"`;
1027
- }).sort();
1028
- await import_fs_extra8.default.writeFile(
1095
+ )
1096
+ ).concat(await getPublicFiles(config)).map(normalizePath2).map((path5) => ` | "/${path5}"`).sort().join("\n");
1097
+ const template = `// Generated by wxt
1098
+ import "wxt/browser";
1099
+
1100
+ declare module "wxt/browser" {
1101
+ type PublicPath =
1102
+ {{ union }}
1103
+ export interface ProjectRuntime extends Runtime.Static {
1104
+ getURL(path: PublicPath): string;
1105
+ }
1106
+ }
1107
+ `;
1108
+ await import_fs_extra9.default.writeFile(
1029
1109
  filePath,
1030
- [
1031
- "// Generated by wxt",
1032
- "type EntrypointPath =",
1033
- ...unions.length === 0 ? [" never"] : unions
1034
- ].join("\n") + "\n"
1110
+ template.replace("{{ union }}", unions || " | never")
1035
1111
  );
1036
1112
  return filePath;
1037
1113
  }
1038
1114
  async function writeGlobalsDeclarationFile(config) {
1039
1115
  const filePath = (0, import_path9.resolve)(config.typesDir, "globals.d.ts");
1040
1116
  const globals = getGlobals(config);
1041
- await import_fs_extra8.default.writeFile(
1117
+ await import_fs_extra9.default.writeFile(
1042
1118
  filePath,
1043
1119
  [
1044
1120
  "// Generated by wxt",
@@ -1054,13 +1130,13 @@ async function writeGlobalsDeclarationFile(config) {
1054
1130
  async function writeMainDeclarationFile(references, config) {
1055
1131
  const dir = config.wxtDir;
1056
1132
  const filePath = (0, import_path9.resolve)(dir, "wxt.d.ts");
1057
- await import_fs_extra8.default.writeFile(
1133
+ await import_fs_extra9.default.writeFile(
1058
1134
  filePath,
1059
1135
  [
1060
1136
  "// Generated by wxt",
1061
1137
  `/// <reference types="vite/client" />`,
1062
1138
  ...references.map(
1063
- (ref) => `/// <reference types="./${(0, import_path9.relative)(dir, ref)}" />`
1139
+ (ref) => `/// <reference types="./${normalizePath2((0, import_path9.relative)(dir, ref))}" />`
1064
1140
  )
1065
1141
  ].join("\n") + "\n"
1066
1142
  );
@@ -1068,7 +1144,7 @@ async function writeMainDeclarationFile(references, config) {
1068
1144
  }
1069
1145
  async function writeTsConfigFile(mainReference, config) {
1070
1146
  const dir = config.wxtDir;
1071
- await import_fs_extra8.default.writeFile(
1147
+ await import_fs_extra9.default.writeFile(
1072
1148
  (0, import_path9.resolve)(dir, "tsconfig.json"),
1073
1149
  `{
1074
1150
  "compilerOptions": {
@@ -1079,37 +1155,32 @@ async function writeTsConfigFile(mainReference, config) {
1079
1155
  "esModuleInterop": true,
1080
1156
  "forceConsistentCasingInFileNames": true,
1081
1157
  "resolveJsonModule": true,
1082
-
1083
- /* Type Checking */
1084
1158
  "strict": true,
1085
-
1086
- /* Completeness */
1159
+ "lib": ["DOM", "WebWorker"],
1087
1160
  "skipLibCheck": true,
1088
-
1089
- /* Aliases */
1090
- "baseUrl": "${(0, import_path9.relative)(dir, config.root)}",
1161
+ "baseUrl": "${normalizePath2((0, import_path9.relative)(dir, config.root))}",
1091
1162
  "paths": {
1092
1163
  "@@": ["."],
1093
1164
  "@@/*": ["./*"],
1094
1165
  "~~": ["."],
1095
1166
  "~~/*": ["./*"],
1096
- "@": ["${(0, import_path9.relative)(config.root, config.srcDir)}"],
1097
- "@/*": ["${(0, import_path9.relative)(config.root, config.srcDir)}/*"],
1098
- "~": ["${(0, import_path9.relative)(config.root, config.srcDir)}"],
1099
- "~/*": ["${(0, import_path9.relative)(config.root, config.srcDir)}/*"]
1167
+ "@": ["${normalizePath2((0, import_path9.relative)(config.root, config.srcDir))}"],
1168
+ "@/*": ["${normalizePath2((0, import_path9.relative)(config.root, config.srcDir))}/*"],
1169
+ "~": ["${normalizePath2((0, import_path9.relative)(config.root, config.srcDir))}"],
1170
+ "~/*": ["${normalizePath2((0, import_path9.relative)(config.root, config.srcDir))}/*"]
1100
1171
  }
1101
1172
  },
1102
1173
  "include": [
1103
- "${(0, import_path9.relative)(dir, config.root)}/**/*",
1104
- "./${(0, import_path9.relative)(dir, mainReference)}"
1174
+ "${normalizePath2((0, import_path9.relative)(dir, config.root))}/**/*",
1175
+ "./${normalizePath2((0, import_path9.relative)(dir, mainReference))}"
1105
1176
  ],
1106
- "exclude": ["${(0, import_path9.relative)(dir, config.outBaseDir)}"]
1177
+ "exclude": ["${normalizePath2((0, import_path9.relative)(dir, config.outBaseDir))}"]
1107
1178
  }`
1108
1179
  );
1109
1180
  }
1110
1181
 
1111
1182
  // src/core/utils/manifest.ts
1112
- var import_fs_extra10 = __toESM(require("fs-extra"), 1);
1183
+ var import_fs_extra11 = __toESM(require("fs-extra"), 1);
1113
1184
  var import_path10 = require("path");
1114
1185
 
1115
1186
  // src/core/utils/ContentSecurityPolicy.ts
@@ -1194,12 +1265,12 @@ function mapWxtOptionsToContentScript(options) {
1194
1265
  }
1195
1266
 
1196
1267
  // src/core/utils/package.ts
1197
- var import_node_path4 = require("path");
1198
- var import_fs_extra9 = __toESM(require("fs-extra"), 1);
1268
+ var import_node_path5 = require("path");
1269
+ var import_fs_extra10 = __toESM(require("fs-extra"), 1);
1199
1270
  async function getPackageJson(config) {
1200
- const file = (0, import_node_path4.resolve)(config.root, "package.json");
1271
+ const file = (0, import_node_path5.resolve)(config.root, "package.json");
1201
1272
  try {
1202
- return await import_fs_extra9.default.readJson(file);
1273
+ return await import_fs_extra10.default.readJson(file);
1203
1274
  } catch (err) {
1204
1275
  config.logger.debug(
1205
1276
  `Failed to read package.json at: ${file}. Returning undefined.`
@@ -1211,8 +1282,8 @@ async function getPackageJson(config) {
1211
1282
  // src/core/utils/manifest.ts
1212
1283
  async function writeManifest(manifest, output, config) {
1213
1284
  const str = config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
1214
- await import_fs_extra10.default.ensureDir(config.outDir);
1215
- await import_fs_extra10.default.writeFile((0, import_path10.resolve)(config.outDir, "manifest.json"), str, "utf-8");
1285
+ await import_fs_extra11.default.ensureDir(config.outDir);
1286
+ await import_fs_extra11.default.writeFile((0, import_path10.resolve)(config.outDir, "manifest.json"), str, "utf-8");
1216
1287
  output.publicAssets.unshift({
1217
1288
  type: "asset",
1218
1289
  fileName: "manifest.json",
@@ -1493,8 +1564,8 @@ function addHostPermission(manifest, hostPermission) {
1493
1564
 
1494
1565
  // src/core/build.ts
1495
1566
  var import_picocolors2 = __toESM(require("picocolors"), 1);
1496
- var vite3 = __toESM(require("vite"), 1);
1497
- var import_fs_extra12 = __toESM(require("fs-extra"), 1);
1567
+ var vite4 = __toESM(require("vite"), 1);
1568
+ var import_fs_extra13 = __toESM(require("fs-extra"), 1);
1498
1569
 
1499
1570
  // src/core/utils/groupEntrypoints.ts
1500
1571
  function groupEntrypoints(entrypoints) {
@@ -1545,9 +1616,9 @@ function formatDuration(duration) {
1545
1616
  var import_path11 = require("path");
1546
1617
 
1547
1618
  // src/core/log/printFileList.ts
1548
- var import_node_path5 = __toESM(require("path"), 1);
1619
+ var import_node_path6 = __toESM(require("path"), 1);
1549
1620
  var import_picocolors = __toESM(require("picocolors"), 1);
1550
- var import_fs_extra11 = __toESM(require("fs-extra"), 1);
1621
+ var import_fs_extra12 = __toESM(require("fs-extra"), 1);
1551
1622
  var import_filesize = require("filesize");
1552
1623
 
1553
1624
  // src/core/log/printTable.ts
@@ -1582,12 +1653,12 @@ async function printFileList(log, baseDir, files) {
1582
1653
  const fileRows = await Promise.all(
1583
1654
  files.map(async (file, i) => {
1584
1655
  const parts = [
1585
- import_node_path5.default.relative(process.cwd(), baseDir) + import_node_path5.default.sep,
1586
- import_node_path5.default.relative(baseDir, file)
1656
+ import_node_path6.default.relative(process.cwd(), baseDir) + import_node_path6.default.sep,
1657
+ import_node_path6.default.relative(baseDir, file)
1587
1658
  ];
1588
1659
  const prefix = i === files.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
1589
1660
  const color = getChunkColor(file);
1590
- const stats = await import_fs_extra11.default.lstat(file);
1661
+ const stats = await import_fs_extra12.default.lstat(file);
1591
1662
  totalSize += stats.size;
1592
1663
  const size = String((0, import_filesize.filesize)(stats.size));
1593
1664
  return [
@@ -1647,15 +1718,15 @@ async function buildInternal(config) {
1647
1718
  const target = `${config.browser}-mv${config.manifestVersion}`;
1648
1719
  config.logger.info(
1649
1720
  `${verb} ${import_picocolors2.default.cyan(target)} for ${import_picocolors2.default.cyan(config.mode)} with ${import_picocolors2.default.green(
1650
- `Vite ${vite3.version}`
1721
+ `Vite ${vite4.version}`
1651
1722
  )}`
1652
1723
  );
1653
1724
  const startTime = Date.now();
1654
- await import_fs_extra12.default.rm(config.outDir, { recursive: true, force: true });
1655
- await import_fs_extra12.default.ensureDir(config.outDir);
1725
+ await import_fs_extra13.default.rm(config.outDir, { recursive: true, force: true });
1726
+ await import_fs_extra13.default.ensureDir(config.outDir);
1656
1727
  const entrypoints = await findEntrypoints(config);
1657
1728
  const groups = groupEntrypoints(entrypoints);
1658
- const { output } = await rebuild(config, groups);
1729
+ const { output } = await rebuild(config, groups, void 0);
1659
1730
  config.logger.success(
1660
1731
  `Built extension in ${formatDuration(Date.now() - startTime)}`
1661
1732
  );
@@ -1667,7 +1738,11 @@ async function rebuild(config, entrypointGroups, existingOutput = {
1667
1738
  publicAssets: []
1668
1739
  }) {
1669
1740
  const allEntrypoints = await findEntrypoints(config);
1670
- await generateTypesDir(allEntrypoints, config);
1741
+ await generateTypesDir(allEntrypoints, config).catch((err) => {
1742
+ config.logger.warn("Failed to update .wxt directory:", err);
1743
+ if (config.command === "build")
1744
+ throw err;
1745
+ });
1671
1746
  const newOutput = await buildEntrypoints(entrypointGroups, config);
1672
1747
  const mergedOutput = {
1673
1748
  steps: [...existingOutput.steps, ...newOutput.steps],
@@ -1697,7 +1772,7 @@ async function rebuild(config, entrypointGroups, existingOutput = {
1697
1772
  }
1698
1773
 
1699
1774
  // src/core/server.ts
1700
- var vite4 = __toESM(require("vite"), 1);
1775
+ var vite5 = __toESM(require("vite"), 1);
1701
1776
 
1702
1777
  // src/core/runners/createWebExtRunner.ts
1703
1778
  function createWebExtRunner() {
@@ -1776,8 +1851,8 @@ async function getServerInfo() {
1776
1851
  }
1777
1852
  async function setupServer(serverInfo, config) {
1778
1853
  const runner = createWebExtRunner();
1779
- const viteServer = await vite4.createServer(
1780
- vite4.mergeConfig(serverInfo, config.vite)
1854
+ const viteServer = await vite5.createServer(
1855
+ vite5.mergeConfig(serverInfo, config.vite)
1781
1856
  );
1782
1857
  const start = async () => {
1783
1858
  await viteServer.listen(server.port);
@@ -1843,7 +1918,7 @@ function reloadHtmlPages(groups, server, config) {
1843
1918
  }
1844
1919
 
1845
1920
  // package.json
1846
- var version2 = "0.2.4";
1921
+ var version2 = "0.3.0";
1847
1922
 
1848
1923
  // src/core/utils/defineConfig.ts
1849
1924
  function defineConfig(config) {
@@ -1863,7 +1938,7 @@ async function build2(config) {
1863
1938
  async function createServer2(config) {
1864
1939
  const serverInfo = await getServerInfo();
1865
1940
  const getLatestInternalConfig = () => {
1866
- const viteConfig = vite5.mergeConfig(
1941
+ const viteConfig = vite6.mergeConfig(
1867
1942
  serverInfo.viteServerConfig,
1868
1943
  config?.vite ?? {}
1869
1944
  );
@@ -1883,15 +1958,17 @@ async function createServer2(config) {
1883
1958
  changeQueue.push([event, path5]);
1884
1959
  await fileChangedMutex.runExclusive(async () => {
1885
1960
  const fileChanges = changeQueue.splice(0, changeQueue.length);
1961
+ if (fileChanges.length === 0)
1962
+ return;
1886
1963
  const changes = detectDevChanges(fileChanges, server.currentOutput);
1887
1964
  if (changes.type === "no-change")
1888
1965
  return;
1889
1966
  internalConfig.logger.info(
1890
- `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => import_picocolors3.default.dim((0, import_node_path6.relative)(internalConfig.root, file))).join(", ")}`
1967
+ `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => import_picocolors3.default.dim((0, import_node_path7.relative)(internalConfig.root, file))).join(", ")}`
1891
1968
  );
1892
1969
  const rebuiltNames = changes.rebuildGroups.flat().map((entry) => {
1893
1970
  return import_picocolors3.default.cyan(
1894
- (0, import_node_path6.relative)(internalConfig.outDir, getEntrypointOutputFile(entry, ""))
1971
+ (0, import_node_path7.relative)(internalConfig.outDir, getEntrypointOutputFile(entry, ""))
1895
1972
  );
1896
1973
  }).join(import_picocolors3.default.dim(", "));
1897
1974
  internalConfig = await getLatestInternalConfig();