wxt 0.6.0 → 0.6.2

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.cts CHANGED
@@ -2,6 +2,7 @@ import * as vite from 'vite';
2
2
  import { Manifest, Scripting } from 'webextension-polyfill';
3
3
  import { UnimportOptions } from 'unimport';
4
4
  import { LogLevel } from 'consola';
5
+ import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
5
6
 
6
7
  /**
7
8
  * Extends [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
@@ -205,6 +206,36 @@ interface InlineConfig {
205
206
  */
206
207
  ignoredSources?: string[];
207
208
  };
209
+ /**
210
+ * Transform the final manifest before it's written to the file system. Edit the `manifest`
211
+ * parameter directly, do not return a new object. Return values are ignored.
212
+ *
213
+ * @example
214
+ * defineConfig({
215
+ * // Add a CSS-only content script.
216
+ * transformManifest(manifest) {
217
+ * manifest.content_scripts.push({
218
+ * matches: ["*://google.com/*"],
219
+ * css: ["content-scripts/some-example.css"],
220
+ * });
221
+ * }
222
+ * })
223
+ */
224
+ transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
225
+ analysis?: {
226
+ /**
227
+ * Explicitly include bundle analysis when running `wxt build`. This can be overridden by the
228
+ * command line `--analysis` option.
229
+ */
230
+ enabled?: boolean;
231
+ /**
232
+ * When running `wxt build --analyze` or setting `analysis.enabled` to true, customize how the
233
+ * bundle will be visualized. See
234
+ * [`rollup-plugin-visualizer`](https://github.com/btd/rollup-plugin-visualizer#how-to-use-generated-files)
235
+ * for more details.
236
+ */
237
+ template?: PluginVisualizerOptions['template'];
238
+ };
208
239
  }
209
240
  interface WxtInlineViteConfig extends Omit<vite.InlineConfig, 'root' | 'configFile' | 'mode' | 'build'> {
210
241
  build?: Omit<vite.BuildOptions, 'outDir'>;
@@ -483,7 +514,7 @@ type EntrypointGroup = Entrypoint | Entrypoint[];
483
514
  */
484
515
  declare function clean(root?: string): Promise<void>;
485
516
 
486
- var version = "0.6.0";
517
+ var version = "0.6.2";
487
518
 
488
519
  declare function defineConfig(config: UserConfig): UserConfig;
489
520
 
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as vite from 'vite';
2
2
  import { Manifest, Scripting } from 'webextension-polyfill';
3
3
  import { UnimportOptions } from 'unimport';
4
4
  import { LogLevel } from 'consola';
5
+ import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
5
6
 
6
7
  /**
7
8
  * Extends [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
@@ -205,6 +206,36 @@ interface InlineConfig {
205
206
  */
206
207
  ignoredSources?: string[];
207
208
  };
209
+ /**
210
+ * Transform the final manifest before it's written to the file system. Edit the `manifest`
211
+ * parameter directly, do not return a new object. Return values are ignored.
212
+ *
213
+ * @example
214
+ * defineConfig({
215
+ * // Add a CSS-only content script.
216
+ * transformManifest(manifest) {
217
+ * manifest.content_scripts.push({
218
+ * matches: ["*://google.com/*"],
219
+ * css: ["content-scripts/some-example.css"],
220
+ * });
221
+ * }
222
+ * })
223
+ */
224
+ transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
225
+ analysis?: {
226
+ /**
227
+ * Explicitly include bundle analysis when running `wxt build`. This can be overridden by the
228
+ * command line `--analysis` option.
229
+ */
230
+ enabled?: boolean;
231
+ /**
232
+ * When running `wxt build --analyze` or setting `analysis.enabled` to true, customize how the
233
+ * bundle will be visualized. See
234
+ * [`rollup-plugin-visualizer`](https://github.com/btd/rollup-plugin-visualizer#how-to-use-generated-files)
235
+ * for more details.
236
+ */
237
+ template?: PluginVisualizerOptions['template'];
238
+ };
208
239
  }
209
240
  interface WxtInlineViteConfig extends Omit<vite.InlineConfig, 'root' | 'configFile' | 'mode' | 'build'> {
210
241
  build?: Omit<vite.BuildOptions, 'outDir'>;
@@ -483,7 +514,7 @@ type EntrypointGroup = Entrypoint | Entrypoint[];
483
514
  */
484
515
  declare function clean(root?: string): Promise<void>;
485
516
 
486
- var version = "0.6.0";
517
+ var version = "0.6.2";
487
518
 
488
519
  declare function defineConfig(config: UserConfig): UserConfig;
489
520
 
package/dist/index.js CHANGED
@@ -406,6 +406,17 @@ function cssEntrypoints(entrypoint, config) {
406
406
  };
407
407
  }
408
408
 
409
+ // src/core/vite-plugins/bundleAnalysis.ts
410
+ import { visualizer } from "rollup-plugin-visualizer";
411
+ var increment = 0;
412
+ function bundleAnalysis() {
413
+ return visualizer({
414
+ emitFile: true,
415
+ template: "raw-data",
416
+ filename: `stats-${increment++}.json`
417
+ });
418
+ }
419
+
409
420
  // src/core/utils/globals.ts
410
421
  function getGlobals(config) {
411
422
  return [
@@ -523,7 +534,15 @@ async function getInternalConfig(inlineConfig, command) {
523
534
  vite: () => ({}),
524
535
  // Real value added after this object is initialized.
525
536
  wxtDir,
526
- zip: resolveInternalZipConfig(root, mergedConfig)
537
+ zip: resolveInternalZipConfig(root, mergedConfig),
538
+ transformManifest(manifest) {
539
+ userConfig.transformManifest?.(manifest);
540
+ inlineConfig.transformManifest?.(manifest);
541
+ },
542
+ analysis: {
543
+ enabled: mergedConfig.analysis?.enabled ?? false,
544
+ template: mergedConfig.analysis?.template ?? "treemap"
545
+ }
527
546
  };
528
547
  finalConfig.vite = (env2) => resolveInternalViteConfig(env2, mergedConfig, finalConfig);
529
548
  return finalConfig;
@@ -576,7 +595,11 @@ function mergeInlineConfig(inlineConfig, userConfig) {
576
595
  runner,
577
596
  srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
578
597
  vite: viteConfig,
579
- zip
598
+ zip,
599
+ analysis: {
600
+ enabled: inlineConfig.analysis?.enabled ?? userConfig.analysis?.enabled,
601
+ template: inlineConfig.analysis?.template ?? userConfig.analysis?.template
602
+ }
580
603
  };
581
604
  }
582
605
  function resolveInternalZipConfig(root, mergedConfig) {
@@ -621,6 +644,9 @@ async function resolveInternalViteConfig(env, mergedConfig, finalConfig) {
621
644
  internalVite.plugins.push(devServerGlobals(finalConfig));
622
645
  internalVite.plugins.push(tsconfigPaths(finalConfig));
623
646
  internalVite.plugins.push(noopBackground());
647
+ if (finalConfig.analysis.enabled) {
648
+ internalVite.plugins.push(bundleAnalysis());
649
+ }
624
650
  internalVite.define ??= {};
625
651
  for (const global of getGlobals(finalConfig)) {
626
652
  internalVite.define[global.name] = JSON.stringify(global.value);
@@ -629,7 +655,7 @@ async function resolveInternalViteConfig(env, mergedConfig, finalConfig) {
629
655
  }
630
656
 
631
657
  // src/index.ts
632
- import pc4 from "picocolors";
658
+ import pc5 from "picocolors";
633
659
 
634
660
  // src/core/utils/arrays.ts
635
661
  function every(array, predicate) {
@@ -726,7 +752,7 @@ function findEffectedSteps(changedFile, currentOutput) {
726
752
  // src/index.ts
727
753
  import { Mutex } from "async-mutex";
728
754
  import { consola as consola3 } from "consola";
729
- import { relative as relative5 } from "node:path";
755
+ import { relative as relative7 } from "node:path";
730
756
 
731
757
  // src/core/build/buildEntrypoints.ts
732
758
  import * as vite3 from "vite";
@@ -764,9 +790,12 @@ async function getPublicFiles(config) {
764
790
  }
765
791
 
766
792
  // src/core/build/buildEntrypoints.ts
767
- async function buildEntrypoints(groups, config) {
793
+ import pc from "picocolors";
794
+ async function buildEntrypoints(groups, config, spinner) {
768
795
  const steps = [];
769
- for (const group of groups) {
796
+ for (let i = 0; i < groups.length; i++) {
797
+ const group = groups[i];
798
+ spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${[group].flat().map((e) => e.name).join(pc.dim(", "))}`;
770
799
  const step = Array.isArray(group) ? await buildMultipleEntrypoints(group, config) : await buildSingleEntrypoint(group, config);
771
800
  steps.push(step);
772
801
  }
@@ -970,7 +999,7 @@ async function findEntrypoints(config) {
970
999
  relativePaths.map(async (relativePath) => {
971
1000
  const path7 = resolve8(config.entrypointsDir, relativePath);
972
1001
  const matchingGlob = pathGlobs.find(
973
- (glob4) => minimatch(relativePath, glob4)
1002
+ (glob5) => minimatch(relativePath, glob5)
974
1003
  );
975
1004
  if (matchingGlob == null) {
976
1005
  return config.logger.warn(
@@ -1537,6 +1566,7 @@ async function getPackageJson(config) {
1537
1566
  }
1538
1567
 
1539
1568
  // src/core/utils/manifest.ts
1569
+ import { produce } from "immer";
1540
1570
  async function writeManifest(manifest, output, config) {
1541
1571
  const str = config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
1542
1572
  await fs12.ensureDir(config.outDir);
@@ -1578,7 +1608,7 @@ async function generateMainfest(entrypoints, buildOutput, config) {
1578
1608
  "Manifest 'version' is missing. Either:\n1. Add a version in your <rootDir>/package.json\n2. Pass the version via the manifest option in your wxt.config.ts"
1579
1609
  );
1580
1610
  }
1581
- return manifest;
1611
+ return produce(manifest, config.transformManifest);
1582
1612
  }
1583
1613
  function simplifyVersion(versionName) {
1584
1614
  const version3 = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(
@@ -1858,7 +1888,7 @@ function addHostPermission(manifest, hostPermission) {
1858
1888
  }
1859
1889
 
1860
1890
  // src/core/build.ts
1861
- import pc2 from "picocolors";
1891
+ import pc3 from "picocolors";
1862
1892
  import * as vite4 from "vite";
1863
1893
  import fs14 from "fs-extra";
1864
1894
 
@@ -1914,7 +1944,7 @@ import { resolve as resolve12 } from "path";
1914
1944
 
1915
1945
  // src/core/log/printFileList.ts
1916
1946
  import path5 from "node:path";
1917
- import pc from "picocolors";
1947
+ import pc2 from "picocolors";
1918
1948
  import fs13 from "fs-extra";
1919
1949
  import { filesize } from "filesize";
1920
1950
 
@@ -1960,21 +1990,21 @@ async function printFileList(log, header, baseDir, files) {
1960
1990
  totalSize += stats.size;
1961
1991
  const size = String(filesize(stats.size));
1962
1992
  return [
1963
- `${pc.gray(prefix)} ${pc.dim(parts[0])}${color(parts[1])}`,
1964
- pc.dim(size)
1993
+ `${pc2.gray(prefix)} ${pc2.dim(parts[0])}${color(parts[1])}`,
1994
+ pc2.dim(size)
1965
1995
  ];
1966
1996
  })
1967
1997
  );
1968
- fileRows.push([`${pc.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`]);
1998
+ fileRows.push([`${pc2.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`]);
1969
1999
  printTable(log, header, fileRows);
1970
2000
  }
1971
- var DEFAULT_COLOR = pc.blue;
2001
+ var DEFAULT_COLOR = pc2.blue;
1972
2002
  var CHUNK_COLORS = {
1973
- ".js.map": pc.gray,
1974
- ".html": pc.green,
1975
- ".css": pc.magenta,
1976
- ".js": pc.cyan,
1977
- ".zip": pc.yellow
2003
+ ".js.map": pc2.gray,
2004
+ ".html": pc2.green,
2005
+ ".css": pc2.magenta,
2006
+ ".js": pc2.cyan,
2007
+ ".zip": pc2.yellow
1978
2008
  };
1979
2009
  function getChunkColor(filename) {
1980
2010
  return Object.entries(CHUNK_COLORS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_COLOR;
@@ -2011,11 +2041,13 @@ function getChunkSortWeight(filename) {
2011
2041
  }
2012
2042
 
2013
2043
  // src/core/build.ts
2044
+ import { execSync } from "node:child_process";
2045
+ import glob3 from "fast-glob";
2014
2046
  async function buildInternal(config) {
2015
2047
  const verb = config.command === "serve" ? "Pre-rendering" : "Building";
2016
2048
  const target = `${config.browser}-mv${config.manifestVersion}`;
2017
2049
  config.logger.info(
2018
- `${verb} ${pc2.cyan(target)} for ${pc2.cyan(config.mode)} with ${pc2.green(
2050
+ `${verb} ${pc3.cyan(target)} for ${pc3.cyan(config.mode)} with ${pc3.green(
2019
2051
  `Vite ${vite4.version}`
2020
2052
  )}`
2021
2053
  );
@@ -2032,19 +2064,28 @@ async function buildInternal(config) {
2032
2064
  output,
2033
2065
  config
2034
2066
  );
2067
+ if (config.analysis.enabled) {
2068
+ await combineAnalysisStats(config);
2069
+ config.logger.info(
2070
+ `Analysis complete:
2071
+ ${pc3.gray("\u2514\u2500")} ${pc3.yellow("stats.html")}`
2072
+ );
2073
+ }
2035
2074
  return output;
2036
2075
  }
2037
2076
  async function rebuild(config, entrypointGroups, existingOutput = {
2038
2077
  steps: [],
2039
2078
  publicAssets: []
2040
2079
  }) {
2080
+ const { default: ora } = await import("ora");
2081
+ const spinner = ora(`Preparing...`).start();
2041
2082
  const allEntrypoints = await findEntrypoints(config);
2042
2083
  await generateTypesDir(allEntrypoints, config).catch((err) => {
2043
2084
  config.logger.warn("Failed to update .wxt directory:", err);
2044
2085
  if (config.command === "build")
2045
2086
  throw err;
2046
2087
  });
2047
- const newOutput = await buildEntrypoints(entrypointGroups, config);
2088
+ const newOutput = await buildEntrypoints(entrypointGroups, config, spinner);
2048
2089
  const mergedOutput = {
2049
2090
  steps: [...existingOutput.steps, ...newOutput.steps],
2050
2091
  publicAssets: [...existingOutput.publicAssets, ...newOutput.publicAssets]
@@ -2059,6 +2100,7 @@ async function rebuild(config, entrypointGroups, existingOutput = {
2059
2100
  ...newOutput
2060
2101
  };
2061
2102
  await writeManifest(newManifest, finalOutput, config);
2103
+ spinner.clear().stop();
2062
2104
  return {
2063
2105
  output: {
2064
2106
  manifest: newManifest,
@@ -2071,19 +2113,44 @@ async function rebuild(config, entrypointGroups, existingOutput = {
2071
2113
  manifest: newManifest
2072
2114
  };
2073
2115
  }
2116
+ async function combineAnalysisStats(config) {
2117
+ const unixFiles = await glob3(`stats-*.json`, {
2118
+ cwd: config.outDir,
2119
+ absolute: true
2120
+ });
2121
+ const absolutePaths = unixFiles.map(unnormalizePath);
2122
+ execSync(
2123
+ `rollup-plugin-visualizer ${absolutePaths.join(" ")} --template ${config.analysis.template}`,
2124
+ { cwd: config.root, stdio: "inherit" }
2125
+ );
2126
+ }
2074
2127
 
2075
2128
  // src/core/server.ts
2076
2129
  import * as vite5 from "vite";
2077
2130
 
2078
- // src/core/runners/createWebExtRunner.ts
2131
+ // src/core/runners/wsl.ts
2132
+ import { relative as relative5 } from "node:path";
2133
+ function createWslRunner() {
2134
+ return {
2135
+ async openBrowser(config) {
2136
+ config.logger.warn(
2137
+ `Cannot open browser when using WSL. Load "${relative5(
2138
+ process.cwd(),
2139
+ config.outDir
2140
+ )}" as an unpacked extension manually`
2141
+ );
2142
+ },
2143
+ async closeBrowser() {
2144
+ }
2145
+ };
2146
+ }
2147
+
2148
+ // src/core/runners/web-ext.ts
2079
2149
  function createWebExtRunner() {
2080
2150
  let runner;
2081
2151
  return {
2082
2152
  async openBrowser(config) {
2083
- if (config.browser === "safari") {
2084
- config.logger.warn("Cannot open safari automatically.");
2085
- return;
2086
- }
2153
+ config.logger.info("Opening browser...");
2087
2154
  const webExtLogger = await import("web-ext-run/util/logger");
2088
2155
  webExtLogger.consoleStream.write = ({ level, msg, name }) => {
2089
2156
  if (level >= ERROR_LOG_LEVEL)
@@ -2123,6 +2190,7 @@ function createWebExtRunner() {
2123
2190
  config.logger.debug("web-ext options:", options);
2124
2191
  const webExt = await import("web-ext-run");
2125
2192
  runner = await webExt.default.cmd.run(finalConfig, options);
2193
+ config.logger.success("Opened!");
2126
2194
  },
2127
2195
  async closeBrowser() {
2128
2196
  return await runner?.exit();
@@ -2132,6 +2200,33 @@ function createWebExtRunner() {
2132
2200
  var WARN_LOG_LEVEL = 40;
2133
2201
  var ERROR_LOG_LEVEL = 50;
2134
2202
 
2203
+ // src/core/runners/safari.ts
2204
+ import { relative as relative6 } from "node:path";
2205
+ function createSafariRunner() {
2206
+ return {
2207
+ async openBrowser(config) {
2208
+ config.logger.warn(
2209
+ `Cannot Safari using web-ext. Load "${relative6(
2210
+ process.cwd(),
2211
+ config.outDir
2212
+ )}" as an unpacked extension manually`
2213
+ );
2214
+ },
2215
+ async closeBrowser() {
2216
+ }
2217
+ };
2218
+ }
2219
+
2220
+ // src/core/runners/index.ts
2221
+ async function createExtensionRunner(config) {
2222
+ if (config.browser === "safari")
2223
+ return createSafariRunner();
2224
+ const { default: isWsl } = await import("is-wsl");
2225
+ if (isWsl)
2226
+ return createWslRunner();
2227
+ return createWebExtRunner();
2228
+ }
2229
+
2135
2230
  // src/core/server.ts
2136
2231
  async function getServerInfo() {
2137
2232
  const { default: getPort, portNumbers } = await import("get-port");
@@ -2151,7 +2246,7 @@ async function getServerInfo() {
2151
2246
  };
2152
2247
  }
2153
2248
  async function setupServer(serverInfo, config) {
2154
- const runner = createWebExtRunner();
2249
+ const runner = await createExtensionRunner(config);
2155
2250
  const viteServer = await vite5.createServer(
2156
2251
  vite5.mergeConfig(serverInfo, await config.vite(config.env))
2157
2252
  );
@@ -2159,9 +2254,7 @@ async function setupServer(serverInfo, config) {
2159
2254
  await viteServer.listen(server.port);
2160
2255
  config.logger.success(`Started dev server @ ${serverInfo.origin}`);
2161
2256
  server.currentOutput = await buildInternal(config);
2162
- config.logger.info("Opening browser...");
2163
2257
  await runner.openBrowser(config);
2164
- config.logger.success("Opened!");
2165
2258
  };
2166
2259
  const reloadExtension = () => {
2167
2260
  viteServer.ws.send("wxt:reload-extension");
@@ -2220,10 +2313,10 @@ function reloadHtmlPages(groups, server, config) {
2220
2313
 
2221
2314
  // src/core/clean.ts
2222
2315
  import path6 from "node:path";
2223
- import glob3 from "fast-glob";
2316
+ import glob4 from "fast-glob";
2224
2317
  import fs15 from "fs-extra";
2225
2318
  import { consola as consola2 } from "consola";
2226
- import pc3 from "picocolors";
2319
+ import pc4 from "picocolors";
2227
2320
  async function clean(root = process.cwd()) {
2228
2321
  consola2.info("Cleaning Project");
2229
2322
  const tempDirs = [
@@ -2232,8 +2325,8 @@ async function clean(root = process.cwd()) {
2232
2325
  "**/.wxt",
2233
2326
  ".output/*"
2234
2327
  ];
2235
- consola2.debug("Looking for:", tempDirs.map(pc3.cyan).join(", "));
2236
- const directories = await glob3(tempDirs, {
2328
+ consola2.debug("Looking for:", tempDirs.map(pc4.cyan).join(", "));
2329
+ const directories = await glob4(tempDirs, {
2237
2330
  cwd: path6.resolve(root),
2238
2331
  absolute: true,
2239
2332
  onlyDirectories: true,
@@ -2245,16 +2338,16 @@ async function clean(root = process.cwd()) {
2245
2338
  }
2246
2339
  consola2.debug(
2247
2340
  "Found:",
2248
- directories.map((dir) => pc3.cyan(path6.relative(root, dir))).join(", ")
2341
+ directories.map((dir) => pc4.cyan(path6.relative(root, dir))).join(", ")
2249
2342
  );
2250
2343
  for (const directory of directories) {
2251
2344
  await fs15.rm(directory, { force: true, recursive: true });
2252
- consola2.debug("Deleted " + pc3.cyan(path6.relative(root, directory)));
2345
+ consola2.debug("Deleted " + pc4.cyan(path6.relative(root, directory)));
2253
2346
  }
2254
2347
  }
2255
2348
 
2256
2349
  // package.json
2257
- var version2 = "0.6.0";
2350
+ var version2 = "0.6.2";
2258
2351
 
2259
2352
  // src/core/utils/defineConfig.ts
2260
2353
  function defineConfig(config) {
@@ -2302,13 +2395,13 @@ async function createServer2(config) {
2302
2395
  if (changes.type === "no-change")
2303
2396
  return;
2304
2397
  internalConfig.logger.info(
2305
- `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => pc4.dim(relative5(internalConfig.root, file))).join(", ")}`
2398
+ `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => pc5.dim(relative7(internalConfig.root, file))).join(", ")}`
2306
2399
  );
2307
2400
  const rebuiltNames = changes.rebuildGroups.flat().map((entry) => {
2308
- return pc4.cyan(
2309
- relative5(internalConfig.outDir, getEntrypointOutputFile(entry, ""))
2401
+ return pc5.cyan(
2402
+ relative7(internalConfig.outDir, getEntrypointOutputFile(entry, ""))
2310
2403
  );
2311
- }).join(pc4.dim(", "));
2404
+ }).join(pc5.dim(", "));
2312
2405
  internalConfig = await getLatestInternalConfig();
2313
2406
  internalConfig.server = server;
2314
2407
  const { output: newOutput } = await rebuild(