wxt 0.14.5 → 0.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import "./chunk-73I7FAJU.js";
5
5
  import cac from "cac";
6
6
 
7
7
  // package.json
8
- var version = "0.14.5";
8
+ var version = "0.14.6";
9
9
 
10
10
  // src/core/utils/fs.ts
11
11
  import fs from "fs-extra";
@@ -77,11 +77,27 @@ function every(array, predicate) {
77
77
  return false;
78
78
  return true;
79
79
  }
80
+ function some(array, predicate) {
81
+ for (let i = 0; i < array.length; i++)
82
+ if (predicate(array[i], i))
83
+ return true;
84
+ return false;
85
+ }
80
86
 
81
87
  // src/core/utils/building/detect-dev-changes.ts
82
- function detectDevChanges(changedFiles, currentOutput) {
83
- if (currentOutput == null)
84
- return { type: "no-change" };
88
+ function detectDevChanges(config, changedFiles, currentOutput) {
89
+ const isConfigChange = some(
90
+ changedFiles,
91
+ (file) => file === config.userConfigMetadata.configFile
92
+ );
93
+ if (isConfigChange)
94
+ return { type: "full-restart" };
95
+ const isRunnerChange = some(
96
+ changedFiles,
97
+ (file) => file === config.runnerConfig.configFile
98
+ );
99
+ if (isRunnerChange)
100
+ return { type: "browser-restart" };
85
101
  const changedSteps = new Set(
86
102
  changedFiles.flatMap(
87
103
  (changedFile) => findEffectedSteps(changedFile, currentOutput)
@@ -113,7 +129,7 @@ function detectDevChanges(changedFiles, currentOutput) {
113
129
  unchangedOutput.publicAssets.push(asset);
114
130
  }
115
131
  }
116
- const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, ([_, file]) => file.endsWith(".html"));
132
+ const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
117
133
  if (isOnlyHtmlChanges) {
118
134
  return {
119
135
  type: "html-reload",
@@ -141,7 +157,7 @@ function detectDevChanges(changedFiles, currentOutput) {
141
157
  }
142
158
  function findEffectedSteps(changedFile, currentOutput) {
143
159
  const changes = [];
144
- const changedPath = normalizePath(changedFile[1]);
160
+ const changedPath = normalizePath(changedFile);
145
161
  const isChunkEffected = (chunk) => (
146
162
  // If it's an HTML file with the same path, is is effected because HTML files need to be pre-rendered
147
163
  // fileName is normalized, relative bundle path
@@ -1489,6 +1505,9 @@ async function createViteBuilder(inlineConfig, userConfig, wxtConfig) {
1489
1505
  async listen() {
1490
1506
  await viteServer.listen(info.port);
1491
1507
  },
1508
+ async close() {
1509
+ await viteServer.close();
1510
+ },
1492
1511
  transformHtml(...args) {
1493
1512
  return viteServer.transformIndexHtml(...args);
1494
1513
  },
@@ -2539,6 +2558,70 @@ async function rebuild(config, allEntrypoints, entrypointGroups, existingOutput
2539
2558
  }
2540
2559
 
2541
2560
  // src/core/utils/building/internal-build.ts
2561
+ import managePath from "manage-path";
2562
+ import { resolve as resolve13, relative as relative6 } from "node:path";
2563
+
2564
+ // src/core/utils/validation.ts
2565
+ function validateEntrypoints(entrypoints) {
2566
+ const errors = entrypoints.flatMap((entrypoint) => {
2567
+ switch (entrypoint.type) {
2568
+ case "content-script":
2569
+ return validateContentScriptEntrypoint(entrypoint);
2570
+ default:
2571
+ return validateBaseEntrypoint(entrypoint);
2572
+ }
2573
+ });
2574
+ let errorCount = 0;
2575
+ let warningCount = 0;
2576
+ for (const err of errors) {
2577
+ if (err.type === "warning")
2578
+ warningCount++;
2579
+ else
2580
+ errorCount++;
2581
+ }
2582
+ return {
2583
+ errors,
2584
+ errorCount,
2585
+ warningCount
2586
+ };
2587
+ }
2588
+ function validateContentScriptEntrypoint(definition) {
2589
+ const errors = validateBaseEntrypoint(definition);
2590
+ if (definition.options.matches == null) {
2591
+ errors.push({
2592
+ type: "error",
2593
+ message: "`matches` is required",
2594
+ value: definition.options.matches,
2595
+ entrypoint: definition
2596
+ });
2597
+ }
2598
+ return errors;
2599
+ }
2600
+ function validateBaseEntrypoint(definition) {
2601
+ const errors = [];
2602
+ if (definition.options.exclude != null && !Array.isArray(definition.options.exclude)) {
2603
+ errors.push({
2604
+ type: "error",
2605
+ message: "`exclude` must be an array of browser names",
2606
+ value: definition.options.exclude,
2607
+ entrypoint: definition
2608
+ });
2609
+ }
2610
+ if (definition.options.include != null && !Array.isArray(definition.options.include)) {
2611
+ errors.push({
2612
+ type: "error",
2613
+ message: "`include` must be an array of browser names",
2614
+ value: definition.options.include,
2615
+ entrypoint: definition
2616
+ });
2617
+ }
2618
+ return errors;
2619
+ }
2620
+ var ValidationError = class extends Error {
2621
+ };
2622
+
2623
+ // src/core/utils/building/internal-build.ts
2624
+ import consola3 from "consola";
2542
2625
  async function internalBuild(config) {
2543
2626
  const verb = config.command === "serve" ? "Pre-rendering" : "Building";
2544
2627
  const target = `${config.browser}-mv${config.manifestVersion}`;
@@ -2552,6 +2635,15 @@ async function internalBuild(config) {
2552
2635
  await fs12.ensureDir(config.outDir);
2553
2636
  const entrypoints = await findEntrypoints(config);
2554
2637
  config.logger.debug("Detected entrypoints:", entrypoints);
2638
+ const validationResults = validateEntrypoints(entrypoints);
2639
+ if (validationResults.errorCount + validationResults.warningCount > 0) {
2640
+ printValidationResults(config, validationResults);
2641
+ }
2642
+ if (validationResults.errorCount > 0) {
2643
+ throw new ValidationError(`Entrypoint validation failed`, {
2644
+ cause: validationResults
2645
+ });
2646
+ }
2555
2647
  const groups = groupEntrypoints(entrypoints);
2556
2648
  const { output, warnings } = await rebuild(
2557
2649
  config,
@@ -2584,11 +2676,35 @@ async function combineAnalysisStats(config) {
2584
2676
  absolute: true
2585
2677
  });
2586
2678
  const absolutePaths = unixFiles.map(unnormalizePath);
2679
+ const alterPath = managePath(process.env);
2680
+ alterPath.push(resolve13(config.root, "node_modules/wxt/node_modules/.bin"));
2587
2681
  await execaCommand(
2588
2682
  `rollup-plugin-visualizer ${absolutePaths.join(" ")} --template ${config.analysis.template}`,
2589
2683
  { cwd: config.root, stdio: "inherit" }
2590
2684
  );
2591
2685
  }
2686
+ function printValidationResults(config, { errorCount, errors, warningCount }) {
2687
+ (errorCount > 0 ? config.logger.error : config.logger.warn)(
2688
+ `Entrypoint validation failed: ${errorCount} error${errorCount === 1 ? "" : "s"}, ${warningCount} warning${warningCount === 1 ? "" : "s"}`
2689
+ );
2690
+ const cwd = process.cwd();
2691
+ const entrypointErrors = errors.reduce((map, error) => {
2692
+ const entryErrors = map.get(error.entrypoint) ?? [];
2693
+ entryErrors.push(error);
2694
+ map.set(error.entrypoint, entryErrors);
2695
+ return map;
2696
+ }, /* @__PURE__ */ new Map());
2697
+ Array.from(entrypointErrors.entries()).forEach(([entrypoint, errors2]) => {
2698
+ consola3.log(relative6(cwd, entrypoint.inputPath));
2699
+ console.log();
2700
+ errors2.forEach((err) => {
2701
+ const type = err.type === "error" ? pc5.red("ERROR") : pc5.yellow("WARN");
2702
+ const recieved = pc5.dim(`(recieved: ${JSON.stringify(err.value)})`);
2703
+ consola3.log(` - ${type} ${err.message} ${recieved}`);
2704
+ });
2705
+ console.log();
2706
+ });
2707
+ }
2592
2708
 
2593
2709
  // src/core/build.ts
2594
2710
  async function build(config) {
@@ -2600,17 +2716,17 @@ async function build(config) {
2600
2716
  import path5 from "node:path";
2601
2717
  import glob4 from "fast-glob";
2602
2718
  import fs13 from "fs-extra";
2603
- import { consola as consola3 } from "consola";
2719
+ import { consola as consola4 } from "consola";
2604
2720
  import pc6 from "picocolors";
2605
2721
  async function clean(root = process.cwd()) {
2606
- consola3.info("Cleaning Project");
2722
+ consola4.info("Cleaning Project");
2607
2723
  const tempDirs = [
2608
2724
  "node_modules/.vite",
2609
2725
  "node_modules/.cache",
2610
2726
  "**/.wxt",
2611
2727
  ".output/*"
2612
2728
  ];
2613
- consola3.debug("Looking for:", tempDirs.map(pc6.cyan).join(", "));
2729
+ consola4.debug("Looking for:", tempDirs.map(pc6.cyan).join(", "));
2614
2730
  const directories = await glob4(tempDirs, {
2615
2731
  cwd: path5.resolve(root),
2616
2732
  absolute: true,
@@ -2618,26 +2734,26 @@ async function clean(root = process.cwd()) {
2618
2734
  deep: 2
2619
2735
  });
2620
2736
  if (directories.length === 0) {
2621
- consola3.debug("No generated files found.");
2737
+ consola4.debug("No generated files found.");
2622
2738
  return;
2623
2739
  }
2624
- consola3.debug(
2740
+ consola4.debug(
2625
2741
  "Found:",
2626
2742
  directories.map((dir) => pc6.cyan(path5.relative(root, dir))).join(", ")
2627
2743
  );
2628
2744
  for (const directory of directories) {
2629
2745
  await fs13.rm(directory, { force: true, recursive: true });
2630
- consola3.debug("Deleted " + pc6.cyan(path5.relative(root, directory)));
2746
+ consola4.debug("Deleted " + pc6.cyan(path5.relative(root, directory)));
2631
2747
  }
2632
2748
  }
2633
2749
 
2634
2750
  // src/core/runners/wsl.ts
2635
- import { relative as relative6 } from "node:path";
2751
+ import { relative as relative7 } from "node:path";
2636
2752
  function createWslRunner() {
2637
2753
  return {
2638
2754
  async openBrowser(config) {
2639
2755
  config.logger.warn(
2640
- `Cannot open browser when using WSL. Load "${relative6(
2756
+ `Cannot open browser when using WSL. Load "${relative7(
2641
2757
  process.cwd(),
2642
2758
  config.outDir
2643
2759
  )}" as an unpacked extension manually`
@@ -2653,7 +2769,7 @@ function createWebExtRunner() {
2653
2769
  let runner;
2654
2770
  return {
2655
2771
  async openBrowser(config) {
2656
- config.logger.info("Opening browser...");
2772
+ const startTime = Date.now();
2657
2773
  if (config.browser === "firefox" && config.manifestVersion === 3) {
2658
2774
  throw Error(
2659
2775
  "Dev mode does not support Firefox MV3. For alternatives, see https://github.com/wxt-dev/wxt/issues/230#issuecomment-1806881653"
@@ -2698,7 +2814,8 @@ function createWebExtRunner() {
2698
2814
  config.logger.debug("web-ext options:", options);
2699
2815
  const webExt = await import("web-ext-run");
2700
2816
  runner = await webExt.default.cmd.run(finalConfig, options);
2701
- config.logger.success("Opened!");
2817
+ const duration = Date.now() - startTime;
2818
+ config.logger.success(`Opened browser in ${formatDuration(duration)}`);
2702
2819
  },
2703
2820
  async closeBrowser() {
2704
2821
  return await runner?.exit();
@@ -2709,12 +2826,12 @@ var WARN_LOG_LEVEL = 40;
2709
2826
  var ERROR_LOG_LEVEL = 50;
2710
2827
 
2711
2828
  // src/core/runners/safari.ts
2712
- import { relative as relative7 } from "node:path";
2829
+ import { relative as relative8 } from "node:path";
2713
2830
  function createSafariRunner() {
2714
2831
  return {
2715
2832
  async openBrowser(config) {
2716
2833
  config.logger.warn(
2717
- `Cannot Safari using web-ext. Load "${relative7(
2834
+ `Cannot Safari using web-ext. Load "${relative8(
2718
2835
  process.cwd(),
2719
2836
  config.outDir
2720
2837
  )}" as an unpacked extension manually`
@@ -2726,12 +2843,12 @@ function createSafariRunner() {
2726
2843
  }
2727
2844
 
2728
2845
  // src/core/runners/manual.ts
2729
- import { relative as relative8 } from "node:path";
2846
+ import { relative as relative9 } from "node:path";
2730
2847
  function createManualRunner() {
2731
2848
  return {
2732
2849
  async openBrowser(config) {
2733
2850
  config.logger.info(
2734
- `Load "${relative8(
2851
+ `Load "${relative9(
2735
2852
  process.cwd(),
2736
2853
  config.outDir
2737
2854
  )}" as an unpacked extension manually`
@@ -2760,10 +2877,10 @@ async function createExtensionRunner(config) {
2760
2877
  }
2761
2878
 
2762
2879
  // src/core/create-server.ts
2763
- import { consola as consola4 } from "consola";
2880
+ import { consola as consola5 } from "consola";
2764
2881
  import { Mutex } from "async-mutex";
2765
2882
  import pc7 from "picocolors";
2766
- import { relative as relative9 } from "node:path";
2883
+ import { relative as relative10 } from "node:path";
2767
2884
  async function createServer(inlineConfig) {
2768
2885
  const port = await getPort();
2769
2886
  const hostname = "localhost";
@@ -2773,19 +2890,36 @@ async function createServer(inlineConfig) {
2773
2890
  hostname,
2774
2891
  origin
2775
2892
  };
2893
+ const buildAndOpenBrowser = async () => {
2894
+ server.currentOutput = await internalBuild(config);
2895
+ await runner.openBrowser(config);
2896
+ };
2897
+ const closeAndRecreateRunner = async () => {
2898
+ await runner.closeBrowser();
2899
+ config = await getLatestConfig();
2900
+ runner = await createExtensionRunner(config);
2901
+ };
2776
2902
  const server = {
2777
2903
  ...serverInfo,
2778
- watcher: void 0,
2779
- // Filled out later down below
2780
- ws: void 0,
2781
- // Filled out later down below
2904
+ get watcher() {
2905
+ return builderServer.watcher;
2906
+ },
2907
+ get ws() {
2908
+ return builderServer.ws;
2909
+ },
2782
2910
  currentOutput: void 0,
2783
- // Filled out later down below
2784
2911
  async start() {
2785
2912
  await builderServer.listen();
2786
2913
  config.logger.success(`Started dev server @ ${serverInfo.origin}`);
2787
- server.currentOutput = await internalBuild(config);
2788
- await runner.openBrowser(config);
2914
+ await buildAndOpenBrowser();
2915
+ },
2916
+ async stop() {
2917
+ await runner.closeBrowser();
2918
+ await builderServer.close();
2919
+ },
2920
+ async restart() {
2921
+ await closeAndRecreateRunner();
2922
+ await buildAndOpenBrowser();
2789
2923
  },
2790
2924
  transformHtml(url, html, originalUrl) {
2791
2925
  return builderServer.transformHtml(url, html, originalUrl);
@@ -2798,17 +2932,21 @@ async function createServer(inlineConfig) {
2798
2932
  },
2799
2933
  reloadExtension() {
2800
2934
  server.ws.send("wxt:reload-extension");
2935
+ },
2936
+ async restartBrowser() {
2937
+ await closeAndRecreateRunner();
2938
+ await runner.openBrowser(config);
2801
2939
  }
2802
2940
  };
2803
2941
  const getLatestConfig = () => getInternalConfig(inlineConfig ?? {}, "serve", server);
2804
2942
  let config = await getLatestConfig();
2805
- const [runner, builderServer] = await Promise.all([
2943
+ let [runner, builderServer] = await Promise.all([
2806
2944
  createExtensionRunner(config),
2807
2945
  config.builder.createServer(server)
2808
2946
  ]);
2809
- server.watcher = builderServer.watcher;
2810
- server.ws = builderServer.ws;
2811
2947
  server.ws.on("wxt:background-initialized", () => {
2948
+ if (server.currentOutput == null)
2949
+ return;
2812
2950
  reloadContentScripts(server.currentOutput.steps, config, server);
2813
2951
  });
2814
2952
  const reloadOnChange = createFileReloader({
@@ -2836,18 +2974,34 @@ function createFileReloader(options) {
2836
2974
  return;
2837
2975
  changeQueue.push([event, path7]);
2838
2976
  await fileChangedMutex.runExclusive(async () => {
2839
- const fileChanges = changeQueue.splice(0, changeQueue.length);
2977
+ if (server.currentOutput == null)
2978
+ return;
2979
+ const fileChanges = changeQueue.splice(0, changeQueue.length).map(([_, file]) => file);
2840
2980
  if (fileChanges.length === 0)
2841
2981
  return;
2842
- const changes = detectDevChanges(fileChanges, server.currentOutput);
2982
+ const changes = detectDevChanges(
2983
+ config,
2984
+ fileChanges,
2985
+ server.currentOutput
2986
+ );
2843
2987
  if (changes.type === "no-change")
2844
2988
  return;
2989
+ if (changes.type === "full-restart") {
2990
+ config.logger.info("Config changed, restarting server...");
2991
+ server.restart();
2992
+ return;
2993
+ }
2994
+ if (changes.type === "browser-restart") {
2995
+ config.logger.info("Runner config changed, restarting browser...");
2996
+ server.restartBrowser();
2997
+ return;
2998
+ }
2845
2999
  config.logger.info(
2846
- `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => pc7.dim(relative9(config.root, file))).join(", ")}`
3000
+ `Changed: ${Array.from(new Set(fileChanges)).map((file) => pc7.dim(relative10(config.root, file))).join(", ")}`
2847
3001
  );
2848
3002
  const rebuiltNames = changes.rebuildGroups.flat().map((entry) => {
2849
3003
  return pc7.cyan(
2850
- relative9(config.outDir, getEntrypointOutputFile(entry, ""))
3004
+ relative10(config.outDir, getEntrypointOutputFile(entry, ""))
2851
3005
  );
2852
3006
  }).join(pc7.dim(", "));
2853
3007
  const allEntrypoints = await findEntrypoints(config);
@@ -2870,13 +3024,15 @@ function createFileReloader(options) {
2870
3024
  reloadContentScripts(changes.changedSteps, config, server);
2871
3025
  break;
2872
3026
  }
2873
- consola4.success(`Reloaded: ${rebuiltNames}`);
3027
+ consola5.success(`Reloaded: ${rebuiltNames}`);
2874
3028
  });
2875
3029
  };
2876
3030
  }
2877
3031
  function reloadContentScripts(steps, config, server) {
2878
3032
  if (config.manifestVersion === 3) {
2879
3033
  steps.forEach((step) => {
3034
+ if (server.currentOutput == null)
3035
+ return;
2880
3036
  const entry = step.entrypoints;
2881
3037
  if (Array.isArray(entry) || entry.type !== "content-script")
2882
3038
  return;
@@ -2913,13 +3069,13 @@ function reloadHtmlPages(groups, server, config) {
2913
3069
 
2914
3070
  // src/core/initialize.ts
2915
3071
  import prompts from "prompts";
2916
- import { consola as consola5 } from "consola";
3072
+ import { consola as consola6 } from "consola";
2917
3073
  import { downloadTemplate } from "giget";
2918
3074
  import fs14 from "fs-extra";
2919
3075
  import path6 from "node:path";
2920
3076
  import pc8 from "picocolors";
2921
3077
  async function initialize(options) {
2922
- consola5.info("Initalizing new project");
3078
+ consola6.info("Initalizing new project");
2923
3079
  const templates = await listTemplates();
2924
3080
  const defaultTemplate = templates.find(
2925
3081
  (template) => template.name === options.template?.toLowerCase().trim()
@@ -2966,15 +3122,15 @@ async function initialize(options) {
2966
3122
  await cloneProject(input);
2967
3123
  const cdPath = path6.relative(process.cwd(), path6.resolve(input.directory));
2968
3124
  console.log();
2969
- consola5.log(
3125
+ consola6.log(
2970
3126
  `\u2728 WXT project created with the ${TEMPLATE_COLORS[input.template.name]?.(input.template.name) ?? input.template.name} template.`
2971
3127
  );
2972
3128
  console.log();
2973
- consola5.log("Next steps:");
3129
+ consola6.log("Next steps:");
2974
3130
  let step = 0;
2975
3131
  if (cdPath !== "")
2976
- consola5.log(` ${++step}.`, pc8.cyan(`cd ${cdPath}`));
2977
- consola5.log(` ${++step}.`, pc8.cyan(`${input.packageManager} install`));
3132
+ consola6.log(` ${++step}.`, pc8.cyan(`cd ${cdPath}`));
3133
+ consola6.log(` ${++step}.`, pc8.cyan(`${input.packageManager} install`));
2978
3134
  console.log();
2979
3135
  }
2980
3136
  async function listTemplates() {
@@ -3019,7 +3175,7 @@ async function cloneProject({
3019
3175
  path6.join(directory, "_gitignore"),
3020
3176
  path6.join(directory, ".gitignore")
3021
3177
  ).catch(
3022
- (err) => consola5.warn("Failed to move _gitignore to .gitignore:", err)
3178
+ (err) => consola6.warn("Failed to move _gitignore to .gitignore:", err)
3023
3179
  );
3024
3180
  spinner.succeed();
3025
3181
  } catch (err) {
@@ -3050,7 +3206,7 @@ async function prepare(config) {
3050
3206
 
3051
3207
  // src/core/zip.ts
3052
3208
  import zipdir from "zip-dir";
3053
- import { dirname as dirname5, relative as relative10, resolve as resolve13 } from "node:path";
3209
+ import { dirname as dirname5, relative as relative11, resolve as resolve14 } from "node:path";
3054
3210
  import fs15 from "fs-extra";
3055
3211
  import { minimatch as minimatch2 } from "minimatch";
3056
3212
  async function zip(config) {
@@ -3068,7 +3224,7 @@ async function zip(config) {
3068
3224
  ).replaceAll("{{manifestVersion}}", `mv${internalConfig.manifestVersion}`);
3069
3225
  await fs15.ensureDir(internalConfig.outBaseDir);
3070
3226
  const outZipFilename = applyTemplate(internalConfig.zip.artifactTemplate);
3071
- const outZipPath = resolve13(internalConfig.outBaseDir, outZipFilename);
3227
+ const outZipPath = resolve14(internalConfig.outBaseDir, outZipFilename);
3072
3228
  await zipdir(internalConfig.outDir, {
3073
3229
  saveTo: outZipPath
3074
3230
  });
@@ -3077,14 +3233,14 @@ async function zip(config) {
3077
3233
  const sourcesZipFilename = applyTemplate(
3078
3234
  internalConfig.zip.sourcesTemplate
3079
3235
  );
3080
- const sourcesZipPath = resolve13(
3236
+ const sourcesZipPath = resolve14(
3081
3237
  internalConfig.outBaseDir,
3082
3238
  sourcesZipFilename
3083
3239
  );
3084
3240
  await zipdir(internalConfig.zip.sourcesRoot, {
3085
3241
  saveTo: sourcesZipPath,
3086
3242
  filter(path7) {
3087
- const relativePath = relative10(internalConfig.zip.sourcesRoot, path7);
3243
+ const relativePath = relative11(internalConfig.zip.sourcesRoot, path7);
3088
3244
  const matchedPattern = internalConfig.zip.ignoredSources.find(
3089
3245
  (pattern) => minimatch2(relativePath, pattern)
3090
3246
  );
@@ -3103,7 +3259,7 @@ async function zip(config) {
3103
3259
  }
3104
3260
 
3105
3261
  // src/cli.ts
3106
- import consola6, { LogLevels as LogLevels2 } from "consola";
3262
+ import consola7, { LogLevels as LogLevels2 } from "consola";
3107
3263
  process.env.VITE_CJS_IGNORE_WARNING = "true";
3108
3264
  var cli = cac("wxt");
3109
3265
  cli.help();
@@ -3193,21 +3349,24 @@ function wrapAction(cb, options) {
3193
3349
  return async (...args) => {
3194
3350
  const isDebug = !!args.find((arg) => arg?.debug);
3195
3351
  if (isDebug) {
3196
- consola6.level = LogLevels2.debug;
3352
+ consola7.level = LogLevels2.debug;
3197
3353
  }
3198
3354
  const startTime = Date.now();
3199
3355
  try {
3200
3356
  printHeader();
3201
3357
  const status = await cb(...args);
3202
3358
  if (!status?.isOngoing && !options?.disableFinishedLog)
3203
- consola6.success(
3359
+ consola7.success(
3204
3360
  `Finished in ${formatDuration(Date.now() - startTime)}`
3205
3361
  );
3206
3362
  } catch (err) {
3207
- consola6.fail(
3363
+ consola7.fail(
3208
3364
  `Command failed after ${formatDuration(Date.now() - startTime)}`
3209
3365
  );
3210
- consola6.error(err);
3366
+ if (err instanceof ValidationError) {
3367
+ } else {
3368
+ consola7.error(err);
3369
+ }
3211
3370
  process.exit(1);
3212
3371
  }
3213
3372
  };
@@ -388,15 +388,23 @@ interface BuildStepOutput {
388
388
  entrypoints: EntrypointGroup;
389
389
  chunks: OutputFile[];
390
390
  }
391
- interface WxtDevServer extends Omit<WxtBuilderServer, 'listen'>, ServerInfo {
391
+ interface WxtDevServer extends Omit<WxtBuilderServer, 'listen' | 'close'>, ServerInfo {
392
392
  /**
393
393
  * Stores the current build output of the server.
394
394
  */
395
- currentOutput: BuildOutput;
395
+ currentOutput: BuildOutput | undefined;
396
396
  /**
397
397
  * Start the server.
398
398
  */
399
399
  start(): Promise<void>;
400
+ /**
401
+ * Stop the server.
402
+ */
403
+ stop(): Promise<void>;
404
+ /**
405
+ * Close the browser, stop the server, rebuild the entire extension, and start the server again.
406
+ */
407
+ restart(): Promise<void>;
400
408
  /**
401
409
  * Transform the HTML for dev mode.
402
410
  */
@@ -423,6 +431,10 @@ interface WxtDevServer extends Omit<WxtBuilderServer, 'listen'>, ServerInfo {
423
431
  * @param contentScript The manifest definition for a content script
424
432
  */
425
433
  reloadContentScript: (contentScript: Omit<Scripting.RegisteredContentScript, 'id'>) => void;
434
+ /**
435
+ * Grab the latest runner config and restart the browser.
436
+ */
437
+ restartBrowser: () => void;
426
438
  }
427
439
  type TargetBrowser = string;
428
440
  type TargetManifestVersion = 2 | 3;
@@ -704,6 +716,10 @@ interface WxtBuilderServer {
704
716
  * Start the server.
705
717
  */
706
718
  listen(): Promise<void>;
719
+ /**
720
+ * Stop the server.
721
+ */
722
+ close(): Promise<void>;
707
723
  /**
708
724
  * Transform the HTML for dev mode.
709
725
  */
@@ -388,15 +388,23 @@ interface BuildStepOutput {
388
388
  entrypoints: EntrypointGroup;
389
389
  chunks: OutputFile[];
390
390
  }
391
- interface WxtDevServer extends Omit<WxtBuilderServer, 'listen'>, ServerInfo {
391
+ interface WxtDevServer extends Omit<WxtBuilderServer, 'listen' | 'close'>, ServerInfo {
392
392
  /**
393
393
  * Stores the current build output of the server.
394
394
  */
395
- currentOutput: BuildOutput;
395
+ currentOutput: BuildOutput | undefined;
396
396
  /**
397
397
  * Start the server.
398
398
  */
399
399
  start(): Promise<void>;
400
+ /**
401
+ * Stop the server.
402
+ */
403
+ stop(): Promise<void>;
404
+ /**
405
+ * Close the browser, stop the server, rebuild the entire extension, and start the server again.
406
+ */
407
+ restart(): Promise<void>;
400
408
  /**
401
409
  * Transform the HTML for dev mode.
402
410
  */
@@ -423,6 +431,10 @@ interface WxtDevServer extends Omit<WxtBuilderServer, 'listen'>, ServerInfo {
423
431
  * @param contentScript The manifest definition for a content script
424
432
  */
425
433
  reloadContentScript: (contentScript: Omit<Scripting.RegisteredContentScript, 'id'>) => void;
434
+ /**
435
+ * Grab the latest runner config and restart the browser.
436
+ */
437
+ restartBrowser: () => void;
426
438
  }
427
439
  type TargetBrowser = string;
428
440
  type TargetManifestVersion = 2 | 3;
@@ -704,6 +716,10 @@ interface WxtBuilderServer {
704
716
  * Start the server.
705
717
  */
706
718
  listen(): Promise<void>;
719
+ /**
720
+ * Stop the server.
721
+ */
722
+ close(): Promise<void>;
707
723
  /**
708
724
  * Transform the HTML for dev mode.
709
725
  */