wxt 0.2.3 → 0.2.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.
package/dist/index.d.ts CHANGED
@@ -91,6 +91,57 @@ interface InlineConfig {
91
91
  * Custom runner options. Options set here can be overridden in a `web-ext.config.ts` file.
92
92
  */
93
93
  runner?: ExtensionRunnerConfig;
94
+ zip?: {
95
+ /**
96
+ * Configure the filename output when zipping files.
97
+ *
98
+ * Available template variables:
99
+ *
100
+ * - `{{name}}` - The project's name converted to kebab-case
101
+ * - `{{version}} - The version_name or version from the manifest
102
+ * - `{{browser}} - The target browser from the `--browser` CLI flag
103
+ * - `{{manifestVersion}}` - Either "2" or "3"
104
+ *
105
+ * @default "{{name}}-{{version}}-{{browser}}.zip"
106
+ */
107
+ artifactTemplate?: string;
108
+ /**
109
+ * Configure the filename output when zipping files.
110
+ *
111
+ * Available template variables:
112
+ *
113
+ * - `{{name}}` - The project's name converted to kebab-case
114
+ * - `{{version}} - The version_name or version from the manifest
115
+ * - `{{browser}} - The target browser from the `--browser` CLI flag
116
+ * - `{{manifestVersion}}` - Either "2" or "3"
117
+ *
118
+ * @default "{{name}}-{{version}}-sources.zip"
119
+ */
120
+ sourcesTemplate?: string;
121
+ /**
122
+ * Override the artifactTemplate's `{{name}}` template variable. Defaults to the package.json's
123
+ * name, or if that doesn't exist, the current working directories name.
124
+ */
125
+ name?: string;
126
+ /**
127
+ * Root directory to ZIP. The ZIP can be uploaded to the Firefox Addon Store as your source
128
+ * code. Defaults to the `config.root` directory.
129
+ */
130
+ sourcesRoot?: string;
131
+ /**
132
+ * [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to exclude when
133
+ * creating a ZIP of all your source code for Firfox. Patterns are relative to your
134
+ * `config.zip.sourcesRoot`.
135
+ *
136
+ * Hidden files, node_modules, and tests are ignored by default.
137
+ *
138
+ * @example
139
+ * [
140
+ * "coverage", // Ignore the coverage directory in the `sourcesRoot`
141
+ * ]
142
+ */
143
+ ignoredSources?: string[];
144
+ };
94
145
  }
95
146
  interface WxtInlineViteConfig extends Omit<vite.InlineConfig, 'root' | 'configFile' | 'mode' | 'build'> {
96
147
  build?: Omit<vite.BuildOptions, 'outDir'>;
@@ -353,7 +404,7 @@ interface ExtensionRunnerConfig {
353
404
 
354
405
  type EntrypointGroup = Entrypoint | Entrypoint[];
355
406
 
356
- var version = "0.2.3";
407
+ var version = "0.2.5";
357
408
 
358
409
  declare function defineConfig(config: UserConfig): UserConfig;
359
410
 
package/dist/index.js CHANGED
@@ -223,7 +223,7 @@ function getUnimportOptions(config) {
223
223
  ],
224
224
  presets: [{ package: "wxt/client" }],
225
225
  warn: config.logger.warn,
226
- dirs: ["components", "composables", "hooks", "utils"]
226
+ dirs: ["./components/*", "./composables/*", "./hooks/*", "./utils/*"]
227
227
  };
228
228
  return mergeConfig(
229
229
  defaultOptions,
@@ -297,6 +297,26 @@ function tsconfigPaths(config) {
297
297
  });
298
298
  }
299
299
 
300
+ // src/core/vite-plugins/noopBackground.ts
301
+ function noopBackground() {
302
+ const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
303
+ const resolvedVirtualModuleId = "\0" + virtualModuleId;
304
+ return {
305
+ name: "wxt:noop-background",
306
+ resolveId(id) {
307
+ if (id === virtualModuleId)
308
+ return resolvedVirtualModuleId;
309
+ },
310
+ load(id) {
311
+ if (id === resolvedVirtualModuleId) {
312
+ return `import { defineBackground } from 'wxt/client';
313
+ export default defineBackground(() => void 0)`;
314
+ }
315
+ }
316
+ };
317
+ }
318
+ var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
319
+
300
320
  // src/core/utils/createFsCache.ts
301
321
  import fs3, { ensureDir as ensureDir2 } from "fs-extra";
302
322
  import { dirname as dirname3, resolve as resolve5 } from "path";
@@ -430,7 +450,27 @@ async function getInternalConfig(config, command) {
430
450
  wxtDir,
431
451
  typesDir,
432
452
  fsCache: createFsCache(wxtDir),
433
- manifest
453
+ manifest,
454
+ zip: {
455
+ sourcesTemplate: "{{name}}-{{version}}-sources.zip",
456
+ artifactTemplate: "{{name}}-{{version}}-{{browser}}.zip",
457
+ sourcesRoot: root,
458
+ ...userConfig.zip,
459
+ ...config.zip,
460
+ ignoredSources: [
461
+ "**/node_modules",
462
+ // WXT files
463
+ "**/web-ext.config.ts",
464
+ // Hidden files
465
+ "**/.*",
466
+ // Tests
467
+ "**/__tests__/**",
468
+ "**/*.+(test|spec).?(c|m)+(j|t)s?(x)",
469
+ // User config
470
+ ...userConfig.zip?.ignoredSources ?? [],
471
+ ...config.zip?.ignoredSources ?? []
472
+ ]
473
+ }
434
474
  };
435
475
  finalConfig.vite.root = root;
436
476
  finalConfig.vite.configFile = false;
@@ -450,6 +490,7 @@ async function getInternalConfig(config, command) {
450
490
  );
451
491
  finalConfig.vite.plugins.push(devServerGlobals(finalConfig));
452
492
  finalConfig.vite.plugins.push(tsconfigPaths(finalConfig));
493
+ finalConfig.vite.plugins.push(noopBackground());
453
494
  finalConfig.vite.define ??= {};
454
495
  getGlobals(finalConfig).forEach((global) => {
455
496
  finalConfig.vite.define[global.name] = JSON.stringify(global.value);
@@ -558,7 +599,7 @@ function findEffectedSteps(changedFile, currentOutput) {
558
599
  // src/index.ts
559
600
  import { Mutex } from "async-mutex";
560
601
  import { consola as consola2 } from "consola";
561
- import { relative as relative6 } from "node:path";
602
+ import { relative as relative5 } from "node:path";
562
603
 
563
604
  // src/core/build/buildEntrypoints.ts
564
605
  import * as vite2 from "vite";
@@ -704,6 +745,16 @@ import { createUnimport as createUnimport2 } from "unimport";
704
745
  import fs6 from "fs-extra";
705
746
  import { resolve as resolve8 } from "path";
706
747
  import transform from "jiti/dist/babel";
748
+
749
+ // src/core/utils/strings.ts
750
+ function removeImportStatements(text) {
751
+ return text.replace(
752
+ /(import\s?[{\w][\s\S]*?from\s?["'][\s\S]*?["'];?|import\s?["'][\s\S]*?["'];?)/gm,
753
+ ""
754
+ );
755
+ }
756
+
757
+ // src/core/utils/importTsFile.ts
707
758
  async function importTsFile(path5, config) {
708
759
  config.logger.debug("Loading file metadata:", path5);
709
760
  const unimport2 = createUnimport2({
@@ -714,7 +765,7 @@ async function importTsFile(path5, config) {
714
765
  });
715
766
  await unimport2.init();
716
767
  const text = await fs6.readFile(path5, "utf-8");
717
- const textNoImports = text.replace(/import.*[\n;]/gm, "");
768
+ const textNoImports = removeImportStatements(text);
718
769
  const { code } = await unimport2.injectImports(textNoImports);
719
770
  config.logger.debug(
720
771
  ["Text:", text, "No imports:", textNoImports, "Code:", code].join("\n")
@@ -754,6 +805,7 @@ async function findEntrypoints(config) {
754
805
  const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
755
806
  const existingNames = {};
756
807
  const entrypoints = [];
808
+ let hasBackground = false;
757
809
  await Promise.all(
758
810
  relativePaths.map(async (relativePath) => {
759
811
  const path5 = resolve9(config.entrypointsDir, relativePath);
@@ -783,6 +835,7 @@ ${JSON.stringify(
783
835
  break;
784
836
  case "background":
785
837
  entrypoint = await getBackgroundEntrypoint(config, path5);
838
+ hasBackground = true;
786
839
  break;
787
840
  case "content-script":
788
841
  entrypoint = await getContentScriptEntrypoint(
@@ -812,6 +865,11 @@ ${JSON.stringify(
812
865
  existingNames[entrypoint.name] = entrypoint;
813
866
  })
814
867
  );
868
+ if (config.command === "serve" && !hasBackground) {
869
+ entrypoints.push(
870
+ await getBackgroundEntrypoint(config, VIRTUAL_NOOP_BACKGROUND_MODULE_ID)
871
+ );
872
+ }
815
873
  return entrypoints;
816
874
  }
817
875
  async function getPopupEntrypoint(config, path5) {
@@ -869,9 +927,17 @@ async function getOptionsEntrypoint(config, path5) {
869
927
  };
870
928
  }
871
929
  async function getBackgroundEntrypoint(config, path5) {
872
- const { main: _, ...options } = await importTsFile(path5, config);
873
- if (options == null) {
874
- throw Error("Background script does not have a default export");
930
+ let options = {};
931
+ if (path5 !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
932
+ const defaultExport = await importTsFile(
933
+ path5,
934
+ config
935
+ );
936
+ if (defaultExport == null) {
937
+ throw Error("Background script does not have a default export");
938
+ }
939
+ const { main: _, ...moduleOptions } = defaultExport;
940
+ options = moduleOptions;
875
941
  }
876
942
  return {
877
943
  type: "background",
@@ -915,6 +981,7 @@ var PATH_GLOB_TO_TYPE_MAP = {
915
981
  "devtools.html": "devtools",
916
982
  "devtools/index.html": "devtools",
917
983
  "background.ts": "background",
984
+ [VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
918
985
  "content.ts?(x)": "content-script",
919
986
  "content/index.ts?(x)": "content-script",
920
987
  "*.content.ts?(x)": "content-script",
@@ -1049,8 +1116,8 @@ async function writeTsConfigFile(mainReference, config) {
1049
1116
  }
1050
1117
 
1051
1118
  // src/core/utils/manifest.ts
1052
- import fs9 from "fs-extra";
1053
- import { resolve as resolve11 } from "path";
1119
+ import fs10 from "fs-extra";
1120
+ import { resolve as resolve12 } from "path";
1054
1121
 
1055
1122
  // src/core/utils/ContentSecurityPolicy.ts
1056
1123
  var ContentSecurityPolicy = class _ContentSecurityPolicy {
@@ -1133,11 +1200,26 @@ function mapWxtOptionsToContentScript(options) {
1133
1200
  };
1134
1201
  }
1135
1202
 
1203
+ // src/core/utils/package.ts
1204
+ import { resolve as resolve11 } from "node:path";
1205
+ import fs9 from "fs-extra";
1206
+ async function getPackageJson(config) {
1207
+ const file = resolve11(config.root, "package.json");
1208
+ try {
1209
+ return await fs9.readJson(file);
1210
+ } catch (err) {
1211
+ config.logger.debug(
1212
+ `Failed to read package.json at: ${file}. Returning undefined.`
1213
+ );
1214
+ return {};
1215
+ }
1216
+ }
1217
+
1136
1218
  // src/core/utils/manifest.ts
1137
1219
  async function writeManifest(manifest, output, config) {
1138
1220
  const str = config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
1139
- await fs9.ensureDir(config.outDir);
1140
- await fs9.writeFile(resolve11(config.outDir, "manifest.json"), str, "utf-8");
1221
+ await fs10.ensureDir(config.outDir);
1222
+ await fs10.writeFile(resolve12(config.outDir, "manifest.json"), str, "utf-8");
1141
1223
  output.publicAssets.unshift({
1142
1224
  type: "asset",
1143
1225
  fileName: "manifest.json",
@@ -1176,17 +1258,6 @@ async function generateMainfest(entrypoints, buildOutput, config) {
1176
1258
  }
1177
1259
  return manifest;
1178
1260
  }
1179
- async function getPackageJson(config) {
1180
- const file = resolve11(config.root, "package.json");
1181
- try {
1182
- return await fs9.readJson(file);
1183
- } catch (err) {
1184
- config.logger.debug(
1185
- `Failed to read package.json at: ${file}. Returning undefined.`
1186
- );
1187
- return {};
1188
- }
1189
- }
1190
1261
  function simplifyVersion(versionName) {
1191
1262
  const version3 = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(
1192
1263
  versionName
@@ -1430,7 +1501,7 @@ function addHostPermission(manifest, hostPermission) {
1430
1501
  // src/core/build.ts
1431
1502
  import pc2 from "picocolors";
1432
1503
  import * as vite3 from "vite";
1433
- import fs11 from "fs-extra";
1504
+ import fs12 from "fs-extra";
1434
1505
 
1435
1506
  // src/core/utils/groupEntrypoints.ts
1436
1507
  function groupEntrypoints(entrypoints) {
@@ -1478,7 +1549,13 @@ function formatDuration(duration) {
1478
1549
  }
1479
1550
 
1480
1551
  // src/core/log/printBuildSummary.ts
1481
- import path4, { relative as relative5, resolve as resolve12 } from "path";
1552
+ import { resolve as resolve13 } from "path";
1553
+
1554
+ // src/core/log/printFileList.ts
1555
+ import path4 from "node:path";
1556
+ import pc from "picocolors";
1557
+ import fs11 from "fs-extra";
1558
+ import { filesize } from "filesize";
1482
1559
 
1483
1560
  // src/core/log/printTable.ts
1484
1561
  function printTable(log, rows, gap = 2) {
@@ -1506,10 +1583,42 @@ function printTable(log, rows, gap = 2) {
1506
1583
  log(str);
1507
1584
  }
1508
1585
 
1586
+ // src/core/log/printFileList.ts
1587
+ async function printFileList(log, baseDir, files) {
1588
+ let totalSize = 0;
1589
+ const fileRows = await Promise.all(
1590
+ files.map(async (file, i) => {
1591
+ const parts = [
1592
+ path4.relative(process.cwd(), baseDir) + path4.sep,
1593
+ path4.relative(baseDir, file)
1594
+ ];
1595
+ const prefix = i === files.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
1596
+ const color = getChunkColor(file);
1597
+ const stats = await fs11.lstat(file);
1598
+ totalSize += stats.size;
1599
+ const size = String(filesize(stats.size));
1600
+ return [
1601
+ `${pc.gray(prefix)} ${pc.dim(parts[0])}${color(parts[1])}`,
1602
+ pc.dim(size)
1603
+ ];
1604
+ })
1605
+ );
1606
+ printTable(log, fileRows);
1607
+ log(`${pc.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`);
1608
+ }
1609
+ var DEFAULT_COLOR = pc.blue;
1610
+ var CHUNK_COLORS = {
1611
+ ".js.map": pc.gray,
1612
+ ".html": pc.green,
1613
+ ".css": pc.magenta,
1614
+ ".js": pc.cyan,
1615
+ ".zip": pc.yellow
1616
+ };
1617
+ function getChunkColor(filename) {
1618
+ return Object.entries(CHUNK_COLORS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_COLOR;
1619
+ }
1620
+
1509
1621
  // src/core/log/printBuildSummary.ts
1510
- import pc from "picocolors";
1511
- import fs10 from "fs-extra";
1512
- import { filesize } from "filesize";
1513
1622
  async function printBuildSummary(output, config) {
1514
1623
  const chunks = [
1515
1624
  ...output.steps.flatMap((step) => step.chunks),
@@ -1522,28 +1631,8 @@ async function printBuildSummary(output, config) {
1522
1631
  return diff;
1523
1632
  return l.fileName.localeCompare(r.fileName);
1524
1633
  });
1525
- let totalSize = 0;
1526
- const chunkRows = await Promise.all(
1527
- chunks.map(async (chunk, i) => {
1528
- const file = [
1529
- relative5(process.cwd(), config.outDir) + path4.sep,
1530
- chunk.fileName
1531
- ];
1532
- const prefix = i === chunks.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
1533
- const color = getChunkColor(chunk.fileName);
1534
- const stats = await fs10.lstat(resolve12(config.outDir, chunk.fileName));
1535
- totalSize += stats.size;
1536
- const size = String(filesize(stats.size));
1537
- return [
1538
- `${pc.gray(prefix)} ${pc.dim(file[0])}${color(file[1])}`,
1539
- pc.dim(size)
1540
- ];
1541
- })
1542
- );
1543
- printTable(config.logger.log, chunkRows);
1544
- config.logger.log(
1545
- `${pc.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`
1546
- );
1634
+ const files = chunks.map((chunk) => resolve13(config.outDir, chunk.fileName));
1635
+ await printFileList(config.logger.log, config.outDir, files);
1547
1636
  }
1548
1637
  var DEFAULT_SORT_WEIGHT = 100;
1549
1638
  var CHUNK_SORT_WEIGHTS = {
@@ -1558,16 +1647,6 @@ function getChunkSortWeight(filename) {
1558
1647
  ([key]) => filename.endsWith(key)
1559
1648
  )?.[1] ?? DEFAULT_SORT_WEIGHT;
1560
1649
  }
1561
- var DEFAULT_COLOR = pc.blue;
1562
- var CHUNK_COLORS = {
1563
- ".js.map": pc.gray,
1564
- ".html": pc.green,
1565
- ".css": pc.magenta,
1566
- ".js": pc.cyan
1567
- };
1568
- function getChunkColor(filename) {
1569
- return Object.entries(CHUNK_COLORS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_COLOR;
1570
- }
1571
1650
 
1572
1651
  // src/core/build.ts
1573
1652
  async function buildInternal(config) {
@@ -1579,11 +1658,11 @@ async function buildInternal(config) {
1579
1658
  )}`
1580
1659
  );
1581
1660
  const startTime = Date.now();
1582
- await fs11.rm(config.outDir, { recursive: true, force: true });
1583
- await fs11.ensureDir(config.outDir);
1661
+ await fs12.rm(config.outDir, { recursive: true, force: true });
1662
+ await fs12.ensureDir(config.outDir);
1584
1663
  const entrypoints = await findEntrypoints(config);
1585
1664
  const groups = groupEntrypoints(entrypoints);
1586
- const { output } = await rebuild(config, groups);
1665
+ const { output } = await rebuild(config, groups, void 0);
1587
1666
  config.logger.success(
1588
1667
  `Built extension in ${formatDuration(Date.now() - startTime)}`
1589
1668
  );
@@ -1595,7 +1674,11 @@ async function rebuild(config, entrypointGroups, existingOutput = {
1595
1674
  publicAssets: []
1596
1675
  }) {
1597
1676
  const allEntrypoints = await findEntrypoints(config);
1598
- await generateTypesDir(allEntrypoints, config);
1677
+ await generateTypesDir(allEntrypoints, config).catch((err) => {
1678
+ config.logger.warn("Failed to update .wxt directory:", err);
1679
+ if (config.command === "build")
1680
+ throw err;
1681
+ });
1599
1682
  const newOutput = await buildEntrypoints(entrypointGroups, config);
1600
1683
  const mergedOutput = {
1601
1684
  steps: [...existingOutput.steps, ...newOutput.steps],
@@ -1771,7 +1854,7 @@ function reloadHtmlPages(groups, server, config) {
1771
1854
  }
1772
1855
 
1773
1856
  // package.json
1774
- var version2 = "0.2.3";
1857
+ var version2 = "0.2.5";
1775
1858
 
1776
1859
  // src/core/utils/defineConfig.ts
1777
1860
  function defineConfig(config) {
@@ -1811,15 +1894,17 @@ async function createServer2(config) {
1811
1894
  changeQueue.push([event, path5]);
1812
1895
  await fileChangedMutex.runExclusive(async () => {
1813
1896
  const fileChanges = changeQueue.splice(0, changeQueue.length);
1897
+ if (fileChanges.length === 0)
1898
+ return;
1814
1899
  const changes = detectDevChanges(fileChanges, server.currentOutput);
1815
1900
  if (changes.type === "no-change")
1816
1901
  return;
1817
1902
  internalConfig.logger.info(
1818
- `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => pc3.dim(relative6(internalConfig.root, file))).join(", ")}`
1903
+ `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => pc3.dim(relative5(internalConfig.root, file))).join(", ")}`
1819
1904
  );
1820
1905
  const rebuiltNames = changes.rebuildGroups.flat().map((entry) => {
1821
1906
  return pc3.cyan(
1822
- relative6(internalConfig.outDir, getEntrypointOutputFile(entry, ""))
1907
+ relative5(internalConfig.outDir, getEntrypointOutputFile(entry, ""))
1823
1908
  );
1824
1909
  }).join(pc3.dim(", "));
1825
1910
  internalConfig = await getLatestInternalConfig();