wxt 0.14.4 → 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/index.cjs CHANGED
@@ -130,12 +130,12 @@ var require_isexe = __commonJS({
130
130
  if (typeof Promise !== "function") {
131
131
  throw new TypeError("callback not provided");
132
132
  }
133
- return new Promise(function(resolve14, reject) {
133
+ return new Promise(function(resolve15, reject) {
134
134
  isexe(path10, options || {}, function(er, is) {
135
135
  if (er) {
136
136
  reject(er);
137
137
  } else {
138
- resolve14(is);
138
+ resolve15(is);
139
139
  }
140
140
  });
141
141
  });
@@ -202,27 +202,27 @@ var require_which = __commonJS({
202
202
  opt = {};
203
203
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
204
204
  const found = [];
205
- const step = (i) => new Promise((resolve14, reject) => {
205
+ const step = (i) => new Promise((resolve15, reject) => {
206
206
  if (i === pathEnv.length)
207
- return opt.all && found.length ? resolve14(found) : reject(getNotFoundError(cmd));
207
+ return opt.all && found.length ? resolve15(found) : reject(getNotFoundError(cmd));
208
208
  const ppRaw = pathEnv[i];
209
209
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
210
210
  const pCmd = path10.join(pathPart, cmd);
211
211
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
212
- resolve14(subStep(p, i, 0));
212
+ resolve15(subStep(p, i, 0));
213
213
  });
214
- const subStep = (p, i, ii) => new Promise((resolve14, reject) => {
214
+ const subStep = (p, i, ii) => new Promise((resolve15, reject) => {
215
215
  if (ii === pathExt.length)
216
- return resolve14(step(i + 1));
216
+ return resolve15(step(i + 1));
217
217
  const ext = pathExt[ii];
218
218
  isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
219
219
  if (!er && is) {
220
220
  if (opt.all)
221
221
  found.push(p + ext);
222
222
  else
223
- return resolve14(p + ext);
223
+ return resolve15(p + ext);
224
224
  }
225
- return resolve14(subStep(p, i, ii + 1));
225
+ return resolve15(subStep(p, i, ii + 1));
226
226
  });
227
227
  });
228
228
  return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
@@ -1529,7 +1529,7 @@ var init_kill = __esm({
1529
1529
  return spawnedPromise;
1530
1530
  }
1531
1531
  let timeoutId;
1532
- const timeoutPromise = new Promise((resolve14, reject) => {
1532
+ const timeoutPromise = new Promise((resolve15, reject) => {
1533
1533
  timeoutId = setTimeout(() => {
1534
1534
  timeoutKill(spawned, killSignal, reject);
1535
1535
  }, timeout);
@@ -2013,9 +2013,9 @@ var init_promise = __esm({
2013
2013
  Reflect.defineProperty(spawned, property, { ...descriptor, value });
2014
2014
  }
2015
2015
  };
2016
- getSpawnedPromise = (spawned) => new Promise((resolve14, reject) => {
2016
+ getSpawnedPromise = (spawned) => new Promise((resolve15, reject) => {
2017
2017
  spawned.on("exit", (exitCode, signal) => {
2018
- resolve14({ exitCode, signal });
2018
+ resolve15({ exitCode, signal });
2019
2019
  });
2020
2020
  spawned.on("error", (error) => {
2021
2021
  reject(error);
@@ -2497,11 +2497,27 @@ function every(array, predicate) {
2497
2497
  return false;
2498
2498
  return true;
2499
2499
  }
2500
+ function some(array, predicate) {
2501
+ for (let i = 0; i < array.length; i++)
2502
+ if (predicate(array[i], i))
2503
+ return true;
2504
+ return false;
2505
+ }
2500
2506
 
2501
2507
  // src/core/utils/building/detect-dev-changes.ts
2502
- function detectDevChanges(changedFiles, currentOutput) {
2503
- if (currentOutput == null)
2504
- return { type: "no-change" };
2508
+ function detectDevChanges(config, changedFiles, currentOutput) {
2509
+ const isConfigChange = some(
2510
+ changedFiles,
2511
+ (file) => file === config.userConfigMetadata.configFile
2512
+ );
2513
+ if (isConfigChange)
2514
+ return { type: "full-restart" };
2515
+ const isRunnerChange = some(
2516
+ changedFiles,
2517
+ (file) => file === config.runnerConfig.configFile
2518
+ );
2519
+ if (isRunnerChange)
2520
+ return { type: "browser-restart" };
2505
2521
  const changedSteps = new Set(
2506
2522
  changedFiles.flatMap(
2507
2523
  (changedFile) => findEffectedSteps(changedFile, currentOutput)
@@ -2533,7 +2549,7 @@ function detectDevChanges(changedFiles, currentOutput) {
2533
2549
  unchangedOutput.publicAssets.push(asset);
2534
2550
  }
2535
2551
  }
2536
- const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, ([_, file]) => file.endsWith(".html"));
2552
+ const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
2537
2553
  if (isOnlyHtmlChanges) {
2538
2554
  return {
2539
2555
  type: "html-reload",
@@ -2561,7 +2577,7 @@ function detectDevChanges(changedFiles, currentOutput) {
2561
2577
  }
2562
2578
  function findEffectedSteps(changedFile, currentOutput) {
2563
2579
  const changes = [];
2564
- const changedPath = normalizePath(changedFile[1]);
2580
+ const changedPath = normalizePath(changedFile);
2565
2581
  const isChunkEffected = (chunk) => (
2566
2582
  // If it's an HTML file with the same path, is is effected because HTML files need to be pre-rendered
2567
2583
  // fileName is normalized, relative bundle path
@@ -3912,6 +3928,9 @@ async function createViteBuilder(inlineConfig, userConfig, wxtConfig) {
3912
3928
  async listen() {
3913
3929
  await viteServer.listen(info.port);
3914
3930
  },
3931
+ async close() {
3932
+ await viteServer.close();
3933
+ },
3915
3934
  transformHtml(...args) {
3916
3935
  return viteServer.transformIndexHtml(...args);
3917
3936
  },
@@ -3977,6 +3996,7 @@ async function getInternalConfig(inlineConfig, command, server) {
3977
3996
  const typesDir = import_node_path7.default.resolve(wxtDir, "types");
3978
3997
  const outBaseDir = import_node_path7.default.resolve(root, mergedConfig.outDir ?? ".output");
3979
3998
  const outDir = import_node_path7.default.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
3999
+ const reloadCommand = mergedConfig.dev?.reloadCommand ?? "Alt+R";
3980
4000
  const runnerConfig = await (0, import_c12.loadConfig)({
3981
4001
  name: "web-ext",
3982
4002
  cwd: root,
@@ -4029,7 +4049,10 @@ async function getInternalConfig(inlineConfig, command, server) {
4029
4049
  experimental: {
4030
4050
  includeBrowserPolyfill: mergedConfig.experimental?.includeBrowserPolyfill ?? true
4031
4051
  },
4032
- server
4052
+ server,
4053
+ dev: {
4054
+ reloadCommand
4055
+ }
4033
4056
  };
4034
4057
  const builder = await createViteBuilder(
4035
4058
  inlineConfig,
@@ -4096,7 +4119,11 @@ function mergeInlineConfig(inlineConfig, userConfig) {
4096
4119
  ...inlineConfig.experimental
4097
4120
  },
4098
4121
  vite: void 0,
4099
- transformManifest: void 0
4122
+ transformManifest: void 0,
4123
+ dev: {
4124
+ ...userConfig.dev,
4125
+ ...inlineConfig.dev
4126
+ }
4100
4127
  };
4101
4128
  }
4102
4129
  function resolveInternalZipConfig(root, mergedConfig) {
@@ -4373,7 +4400,7 @@ function getChunkSortWeight(filename) {
4373
4400
  var import_picocolors4 = __toESM(require("picocolors"), 1);
4374
4401
 
4375
4402
  // package.json
4376
- var version = "0.14.4";
4403
+ var version = "0.14.6";
4377
4404
 
4378
4405
  // src/core/utils/log/printHeader.ts
4379
4406
  var import_consola2 = require("consola");
@@ -4514,6 +4541,7 @@ async function writeManifest(manifest, output, config) {
4514
4541
  });
4515
4542
  }
4516
4543
  async function generateManifest(entrypoints, buildOutput, config) {
4544
+ const warnings = [];
4517
4545
  const pkg = await getPackageJson(config);
4518
4546
  let versionName = config.manifest.version_name ?? config.manifest.version ?? pkg?.version;
4519
4547
  if (versionName == null) {
@@ -4531,21 +4559,26 @@ async function generateManifest(entrypoints, buildOutput, config) {
4531
4559
  short_name: pkg?.shortName,
4532
4560
  icons: discoverIcons(buildOutput)
4533
4561
  };
4534
- if (config.command === "serve") {
4535
- baseManifest.commands = {
4536
- "wxt:reload-extension": {
4537
- description: "Reload the extension during development",
4538
- suggested_key: {
4539
- default: "Alt+R"
4540
- }
4541
- }
4542
- };
4543
- }
4544
4562
  const userManifest = config.manifest;
4545
4563
  const manifest = (0, import_defu3.default)(
4546
4564
  userManifest,
4547
4565
  baseManifest
4548
4566
  );
4567
+ if (config.command === "serve" && config.dev.reloadCommand) {
4568
+ if (manifest.commands && Object.keys(manifest.commands).length >= 4) {
4569
+ warnings.push([
4570
+ "Extension already has 4 registered commands, WXT's reload command is disabled"
4571
+ ]);
4572
+ } else {
4573
+ manifest.commands ??= {};
4574
+ manifest.commands["wxt:reload-extension"] = {
4575
+ description: "Reload the extension during development",
4576
+ suggested_key: {
4577
+ default: config.dev.reloadCommand
4578
+ }
4579
+ };
4580
+ }
4581
+ }
4549
4582
  manifest.version = version2;
4550
4583
  manifest.version_name = // Firefox doesn't support version_name
4551
4584
  config.browser === "firefox" || versionName === version2 ? void 0 : versionName;
@@ -4564,7 +4597,10 @@ async function generateManifest(entrypoints, buildOutput, config) {
4564
4597
  "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"
4565
4598
  );
4566
4599
  }
4567
- return finalManifest;
4600
+ return {
4601
+ manifest: finalManifest,
4602
+ warnings
4603
+ };
4568
4604
  }
4569
4605
  function simplifyVersion(versionName) {
4570
4606
  const version2 = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(
@@ -4925,11 +4961,7 @@ async function rebuild(config, allEntrypoints, entrypointGroups, existingOutput
4925
4961
  steps: [...existingOutput.steps, ...newOutput.steps],
4926
4962
  publicAssets: [...existingOutput.publicAssets, ...newOutput.publicAssets]
4927
4963
  };
4928
- const newManifest = await generateManifest(
4929
- allEntrypoints,
4930
- mergedOutput,
4931
- config
4932
- );
4964
+ const { manifest: newManifest, warnings: manifestWarnings } = await generateManifest(allEntrypoints, mergedOutput, config);
4933
4965
  const finalOutput = {
4934
4966
  manifest: newManifest,
4935
4967
  ...newOutput
@@ -4945,11 +4977,76 @@ async function rebuild(config, allEntrypoints, entrypointGroups, existingOutput
4945
4977
  ...finalOutput.publicAssets
4946
4978
  ]
4947
4979
  },
4948
- manifest: newManifest
4980
+ manifest: newManifest,
4981
+ warnings: manifestWarnings
4949
4982
  };
4950
4983
  }
4951
4984
 
4952
4985
  // src/core/utils/building/internal-build.ts
4986
+ var import_manage_path = __toESM(require("manage-path"), 1);
4987
+ var import_node_path13 = require("path");
4988
+
4989
+ // src/core/utils/validation.ts
4990
+ function validateEntrypoints(entrypoints) {
4991
+ const errors = entrypoints.flatMap((entrypoint) => {
4992
+ switch (entrypoint.type) {
4993
+ case "content-script":
4994
+ return validateContentScriptEntrypoint(entrypoint);
4995
+ default:
4996
+ return validateBaseEntrypoint(entrypoint);
4997
+ }
4998
+ });
4999
+ let errorCount = 0;
5000
+ let warningCount = 0;
5001
+ for (const err of errors) {
5002
+ if (err.type === "warning")
5003
+ warningCount++;
5004
+ else
5005
+ errorCount++;
5006
+ }
5007
+ return {
5008
+ errors,
5009
+ errorCount,
5010
+ warningCount
5011
+ };
5012
+ }
5013
+ function validateContentScriptEntrypoint(definition) {
5014
+ const errors = validateBaseEntrypoint(definition);
5015
+ if (definition.options.matches == null) {
5016
+ errors.push({
5017
+ type: "error",
5018
+ message: "`matches` is required",
5019
+ value: definition.options.matches,
5020
+ entrypoint: definition
5021
+ });
5022
+ }
5023
+ return errors;
5024
+ }
5025
+ function validateBaseEntrypoint(definition) {
5026
+ const errors = [];
5027
+ if (definition.options.exclude != null && !Array.isArray(definition.options.exclude)) {
5028
+ errors.push({
5029
+ type: "error",
5030
+ message: "`exclude` must be an array of browser names",
5031
+ value: definition.options.exclude,
5032
+ entrypoint: definition
5033
+ });
5034
+ }
5035
+ if (definition.options.include != null && !Array.isArray(definition.options.include)) {
5036
+ errors.push({
5037
+ type: "error",
5038
+ message: "`include` must be an array of browser names",
5039
+ value: definition.options.include,
5040
+ entrypoint: definition
5041
+ });
5042
+ }
5043
+ return errors;
5044
+ }
5045
+ var ValidationError = class extends Error {
5046
+ };
5047
+
5048
+ // src/core/utils/building/internal-build.ts
5049
+ var import_consola3 = __toESM(require("consola"), 1);
4953
5050
  async function internalBuild(config) {
4954
5051
  const verb = config.command === "serve" ? "Pre-rendering" : "Building";
4955
5052
  const target = `${config.browser}-mv${config.manifestVersion}`;
@@ -4963,14 +5060,31 @@ async function internalBuild(config) {
4963
5060
  await import_fs_extra12.default.ensureDir(config.outDir);
4964
5061
  const entrypoints = await findEntrypoints(config);
4965
5062
  config.logger.debug("Detected entrypoints:", entrypoints);
5063
+ const validationResults = validateEntrypoints(entrypoints);
5064
+ if (validationResults.errorCount + validationResults.warningCount > 0) {
5065
+ printValidationResults(config, validationResults);
5066
+ }
5067
+ if (validationResults.errorCount > 0) {
5068
+ throw new ValidationError(`Entrypoint validation failed`, {
5069
+ cause: validationResults
5070
+ });
5071
+ }
4966
5072
  const groups = groupEntrypoints(entrypoints);
4967
- const { output } = await rebuild(config, entrypoints, groups, void 0);
5073
+ const { output, warnings } = await rebuild(
5074
+ config,
5075
+ entrypoints,
5076
+ groups,
5077
+ void 0
5078
+ );
4968
5079
  await printBuildSummary(
4969
5080
  config.logger.success,
4970
5081
  `Built extension in ${formatDuration(Date.now() - startTime)}`,
4971
5082
  output,
4972
5083
  config
4973
5084
  );
5085
+ for (const warning of warnings) {
5086
+ config.logger.warn(...warning);
5087
+ }
4974
5088
  if (config.analysis.enabled) {
4975
5089
  await combineAnalysisStats(config);
4976
5090
  config.logger.info(
@@ -4987,11 +5101,35 @@ async function combineAnalysisStats(config) {
4987
5101
  absolute: true
4988
5102
  });
4989
5103
  const absolutePaths = unixFiles.map(unnormalizePath);
5104
+ const alterPath = (0, import_manage_path.default)(process.env);
5105
+ alterPath.push((0, import_node_path13.resolve)(config.root, "node_modules/wxt/node_modules/.bin"));
4990
5106
  await execaCommand2(
4991
5107
  `rollup-plugin-visualizer ${absolutePaths.join(" ")} --template ${config.analysis.template}`,
4992
5108
  { cwd: config.root, stdio: "inherit" }
4993
5109
  );
4994
5110
  }
5111
+ function printValidationResults(config, { errorCount, errors, warningCount }) {
5112
+ (errorCount > 0 ? config.logger.error : config.logger.warn)(
5113
+ `Entrypoint validation failed: ${errorCount} error${errorCount === 1 ? "" : "s"}, ${warningCount} warning${warningCount === 1 ? "" : "s"}`
5114
+ );
5115
+ const cwd = process.cwd();
5116
+ const entrypointErrors = errors.reduce((map, error) => {
5117
+ const entryErrors = map.get(error.entrypoint) ?? [];
5118
+ entryErrors.push(error);
5119
+ map.set(error.entrypoint, entryErrors);
5120
+ return map;
5121
+ }, /* @__PURE__ */ new Map());
5122
+ Array.from(entrypointErrors.entries()).forEach(([entrypoint, errors2]) => {
5123
+ import_consola3.default.log((0, import_node_path13.relative)(cwd, entrypoint.inputPath));
5124
+ console.log();
5125
+ errors2.forEach((err) => {
5126
+ const type = err.type === "error" ? import_picocolors5.default.red("ERROR") : import_picocolors5.default.yellow("WARN");
5127
+ const recieved = import_picocolors5.default.dim(`(recieved: ${JSON.stringify(err.value)})`);
5128
+ import_consola3.default.log(` - ${type} ${err.message} ${recieved}`);
5129
+ });
5130
+ console.log();
5131
+ });
5132
+ }
4995
5133
 
4996
5134
  // src/core/build.ts
4997
5135
  async function build(config) {
@@ -5000,37 +5138,37 @@ async function build(config) {
5000
5138
  }
5001
5139
 
5002
5140
  // src/core/clean.ts
5003
- var import_node_path13 = __toESM(require("path"), 1);
5141
+ var import_node_path14 = __toESM(require("path"), 1);
5004
5142
  var import_fast_glob4 = __toESM(require("fast-glob"), 1);
5005
5143
  var import_fs_extra13 = __toESM(require("fs-extra"), 1);
5006
- var import_consola3 = require("consola");
5144
+ var import_consola4 = require("consola");
5007
5145
  var import_picocolors6 = __toESM(require("picocolors"), 1);
5008
5146
  async function clean(root = process.cwd()) {
5009
- import_consola3.consola.info("Cleaning Project");
5147
+ import_consola4.consola.info("Cleaning Project");
5010
5148
  const tempDirs = [
5011
5149
  "node_modules/.vite",
5012
5150
  "node_modules/.cache",
5013
5151
  "**/.wxt",
5014
5152
  ".output/*"
5015
5153
  ];
5016
- import_consola3.consola.debug("Looking for:", tempDirs.map(import_picocolors6.default.cyan).join(", "));
5154
+ import_consola4.consola.debug("Looking for:", tempDirs.map(import_picocolors6.default.cyan).join(", "));
5017
5155
  const directories = await (0, import_fast_glob4.default)(tempDirs, {
5018
- cwd: import_node_path13.default.resolve(root),
5156
+ cwd: import_node_path14.default.resolve(root),
5019
5157
  absolute: true,
5020
5158
  onlyDirectories: true,
5021
5159
  deep: 2
5022
5160
  });
5023
5161
  if (directories.length === 0) {
5024
- import_consola3.consola.debug("No generated files found.");
5162
+ import_consola4.consola.debug("No generated files found.");
5025
5163
  return;
5026
5164
  }
5027
- import_consola3.consola.debug(
5165
+ import_consola4.consola.debug(
5028
5166
  "Found:",
5029
- directories.map((dir) => import_picocolors6.default.cyan(import_node_path13.default.relative(root, dir))).join(", ")
5167
+ directories.map((dir) => import_picocolors6.default.cyan(import_node_path14.default.relative(root, dir))).join(", ")
5030
5168
  );
5031
5169
  for (const directory of directories) {
5032
5170
  await import_fs_extra13.default.rm(directory, { force: true, recursive: true });
5033
- import_consola3.consola.debug("Deleted " + import_picocolors6.default.cyan(import_node_path13.default.relative(root, directory)));
5171
+ import_consola4.consola.debug("Deleted " + import_picocolors6.default.cyan(import_node_path14.default.relative(root, directory)));
5034
5172
  }
5035
5173
  }
5036
5174
 
@@ -5045,12 +5183,12 @@ function defineRunnerConfig(config) {
5045
5183
  }
5046
5184
 
5047
5185
  // src/core/runners/wsl.ts
5048
- var import_node_path14 = require("path");
5186
+ var import_node_path15 = require("path");
5049
5187
  function createWslRunner() {
5050
5188
  return {
5051
5189
  async openBrowser(config) {
5052
5190
  config.logger.warn(
5053
- `Cannot open browser when using WSL. Load "${(0, import_node_path14.relative)(
5191
+ `Cannot open browser when using WSL. Load "${(0, import_node_path15.relative)(
5054
5192
  process.cwd(),
5055
5193
  config.outDir
5056
5194
  )}" as an unpacked extension manually`
@@ -5066,7 +5204,7 @@ function createWebExtRunner() {
5066
5204
  let runner;
5067
5205
  return {
5068
5206
  async openBrowser(config) {
5069
- config.logger.info("Opening browser...");
5207
+ const startTime = Date.now();
5070
5208
  if (config.browser === "firefox" && config.manifestVersion === 3) {
5071
5209
  throw Error(
5072
5210
  "Dev mode does not support Firefox MV3. For alternatives, see https://github.com/wxt-dev/wxt/issues/230#issuecomment-1806881653"
@@ -5111,7 +5249,8 @@ function createWebExtRunner() {
5111
5249
  config.logger.debug("web-ext options:", options);
5112
5250
  const webExt = await import("web-ext-run");
5113
5251
  runner = await webExt.default.cmd.run(finalConfig, options);
5114
- config.logger.success("Opened!");
5252
+ const duration = Date.now() - startTime;
5253
+ config.logger.success(`Opened browser in ${formatDuration(duration)}`);
5115
5254
  },
5116
5255
  async closeBrowser() {
5117
5256
  return await runner?.exit();
@@ -5122,12 +5261,12 @@ var WARN_LOG_LEVEL = 40;
5122
5261
  var ERROR_LOG_LEVEL = 50;
5123
5262
 
5124
5263
  // src/core/runners/safari.ts
5125
- var import_node_path15 = require("path");
5264
+ var import_node_path16 = require("path");
5126
5265
  function createSafariRunner() {
5127
5266
  return {
5128
5267
  async openBrowser(config) {
5129
5268
  config.logger.warn(
5130
- `Cannot Safari using web-ext. Load "${(0, import_node_path15.relative)(
5269
+ `Cannot Safari using web-ext. Load "${(0, import_node_path16.relative)(
5131
5270
  process.cwd(),
5132
5271
  config.outDir
5133
5272
  )}" as an unpacked extension manually`
@@ -5139,12 +5278,12 @@ function createSafariRunner() {
5139
5278
  }
5140
5279
 
5141
5280
  // src/core/runners/manual.ts
5142
- var import_node_path16 = require("path");
5281
+ var import_node_path17 = require("path");
5143
5282
  function createManualRunner() {
5144
5283
  return {
5145
5284
  async openBrowser(config) {
5146
5285
  config.logger.info(
5147
- `Load "${(0, import_node_path16.relative)(
5286
+ `Load "${(0, import_node_path17.relative)(
5148
5287
  process.cwd(),
5149
5288
  config.outDir
5150
5289
  )}" as an unpacked extension manually`
@@ -5173,10 +5312,10 @@ async function createExtensionRunner(config) {
5173
5312
  }
5174
5313
 
5175
5314
  // src/core/create-server.ts
5176
- var import_consola4 = require("consola");
5315
+ var import_consola5 = require("consola");
5177
5316
  var import_async_mutex = require("async-mutex");
5178
5317
  var import_picocolors7 = __toESM(require("picocolors"), 1);
5179
- var import_node_path17 = require("path");
5318
+ var import_node_path18 = require("path");
5180
5319
  async function createServer(inlineConfig) {
5181
5320
  const port = await getPort();
5182
5321
  const hostname = "localhost";
@@ -5186,19 +5325,36 @@ async function createServer(inlineConfig) {
5186
5325
  hostname,
5187
5326
  origin
5188
5327
  };
5328
+ const buildAndOpenBrowser = async () => {
5329
+ server.currentOutput = await internalBuild(config);
5330
+ await runner.openBrowser(config);
5331
+ };
5332
+ const closeAndRecreateRunner = async () => {
5333
+ await runner.closeBrowser();
5334
+ config = await getLatestConfig();
5335
+ runner = await createExtensionRunner(config);
5336
+ };
5189
5337
  const server = {
5190
5338
  ...serverInfo,
5191
- watcher: void 0,
5192
- // Filled out later down below
5193
- ws: void 0,
5194
- // Filled out later down below
5339
+ get watcher() {
5340
+ return builderServer.watcher;
5341
+ },
5342
+ get ws() {
5343
+ return builderServer.ws;
5344
+ },
5195
5345
  currentOutput: void 0,
5196
- // Filled out later down below
5197
5346
  async start() {
5198
5347
  await builderServer.listen();
5199
5348
  config.logger.success(`Started dev server @ ${serverInfo.origin}`);
5200
- server.currentOutput = await internalBuild(config);
5201
- await runner.openBrowser(config);
5349
+ await buildAndOpenBrowser();
5350
+ },
5351
+ async stop() {
5352
+ await runner.closeBrowser();
5353
+ await builderServer.close();
5354
+ },
5355
+ async restart() {
5356
+ await closeAndRecreateRunner();
5357
+ await buildAndOpenBrowser();
5202
5358
  },
5203
5359
  transformHtml(url2, html, originalUrl) {
5204
5360
  return builderServer.transformHtml(url2, html, originalUrl);
@@ -5211,17 +5367,21 @@ async function createServer(inlineConfig) {
5211
5367
  },
5212
5368
  reloadExtension() {
5213
5369
  server.ws.send("wxt:reload-extension");
5370
+ },
5371
+ async restartBrowser() {
5372
+ await closeAndRecreateRunner();
5373
+ await runner.openBrowser(config);
5214
5374
  }
5215
5375
  };
5216
5376
  const getLatestConfig = () => getInternalConfig(inlineConfig ?? {}, "serve", server);
5217
5377
  let config = await getLatestConfig();
5218
- const [runner, builderServer] = await Promise.all([
5378
+ let [runner, builderServer] = await Promise.all([
5219
5379
  createExtensionRunner(config),
5220
5380
  config.builder.createServer(server)
5221
5381
  ]);
5222
- server.watcher = builderServer.watcher;
5223
- server.ws = builderServer.ws;
5224
5382
  server.ws.on("wxt:background-initialized", () => {
5383
+ if (server.currentOutput == null)
5384
+ return;
5225
5385
  reloadContentScripts(server.currentOutput.steps, config, server);
5226
5386
  });
5227
5387
  const reloadOnChange = createFileReloader({
@@ -5249,18 +5409,34 @@ function createFileReloader(options) {
5249
5409
  return;
5250
5410
  changeQueue.push([event, path10]);
5251
5411
  await fileChangedMutex.runExclusive(async () => {
5252
- const fileChanges = changeQueue.splice(0, changeQueue.length);
5412
+ if (server.currentOutput == null)
5413
+ return;
5414
+ const fileChanges = changeQueue.splice(0, changeQueue.length).map(([_, file]) => file);
5253
5415
  if (fileChanges.length === 0)
5254
5416
  return;
5255
- const changes = detectDevChanges(fileChanges, server.currentOutput);
5417
+ const changes = detectDevChanges(
5418
+ config,
5419
+ fileChanges,
5420
+ server.currentOutput
5421
+ );
5256
5422
  if (changes.type === "no-change")
5257
5423
  return;
5424
+ if (changes.type === "full-restart") {
5425
+ config.logger.info("Config changed, restarting server...");
5426
+ server.restart();
5427
+ return;
5428
+ }
5429
+ if (changes.type === "browser-restart") {
5430
+ config.logger.info("Runner config changed, restarting browser...");
5431
+ server.restartBrowser();
5432
+ return;
5433
+ }
5258
5434
  config.logger.info(
5259
- `Changed: ${Array.from(new Set(fileChanges.map((change) => change[1]))).map((file) => import_picocolors7.default.dim((0, import_node_path17.relative)(config.root, file))).join(", ")}`
5435
+ `Changed: ${Array.from(new Set(fileChanges)).map((file) => import_picocolors7.default.dim((0, import_node_path18.relative)(config.root, file))).join(", ")}`
5260
5436
  );
5261
5437
  const rebuiltNames = changes.rebuildGroups.flat().map((entry) => {
5262
5438
  return import_picocolors7.default.cyan(
5263
- (0, import_node_path17.relative)(config.outDir, getEntrypointOutputFile(entry, ""))
5439
+ (0, import_node_path18.relative)(config.outDir, getEntrypointOutputFile(entry, ""))
5264
5440
  );
5265
5441
  }).join(import_picocolors7.default.dim(", "));
5266
5442
  const allEntrypoints = await findEntrypoints(config);
@@ -5283,13 +5459,15 @@ function createFileReloader(options) {
5283
5459
  reloadContentScripts(changes.changedSteps, config, server);
5284
5460
  break;
5285
5461
  }
5286
- import_consola4.consola.success(`Reloaded: ${rebuiltNames}`);
5462
+ import_consola5.consola.success(`Reloaded: ${rebuiltNames}`);
5287
5463
  });
5288
5464
  };
5289
5465
  }
5290
5466
  function reloadContentScripts(steps, config, server) {
5291
5467
  if (config.manifestVersion === 3) {
5292
5468
  steps.forEach((step) => {
5469
+ if (server.currentOutput == null)
5470
+ return;
5293
5471
  const entry = step.entrypoints;
5294
5472
  if (Array.isArray(entry) || entry.type !== "content-script")
5295
5473
  return;
@@ -5326,13 +5504,13 @@ function reloadHtmlPages(groups, server, config) {
5326
5504
 
5327
5505
  // src/core/initialize.ts
5328
5506
  var import_prompts = __toESM(require("prompts"), 1);
5329
- var import_consola5 = require("consola");
5507
+ var import_consola6 = require("consola");
5330
5508
  var import_giget = require("giget");
5331
5509
  var import_fs_extra14 = __toESM(require("fs-extra"), 1);
5332
- var import_node_path18 = __toESM(require("path"), 1);
5510
+ var import_node_path19 = __toESM(require("path"), 1);
5333
5511
  var import_picocolors8 = __toESM(require("picocolors"), 1);
5334
5512
  async function initialize(options) {
5335
- import_consola5.consola.info("Initalizing new project");
5513
+ import_consola6.consola.info("Initalizing new project");
5336
5514
  const templates = await listTemplates();
5337
5515
  const defaultTemplate = templates.find(
5338
5516
  (template) => template.name === options.template?.toLowerCase().trim()
@@ -5377,17 +5555,17 @@ async function initialize(options) {
5377
5555
  input.template ??= defaultTemplate;
5378
5556
  input.packageManager ??= options.packageManager;
5379
5557
  await cloneProject(input);
5380
- const cdPath = import_node_path18.default.relative(process.cwd(), import_node_path18.default.resolve(input.directory));
5558
+ const cdPath = import_node_path19.default.relative(process.cwd(), import_node_path19.default.resolve(input.directory));
5381
5559
  console.log();
5382
- import_consola5.consola.log(
5560
+ import_consola6.consola.log(
5383
5561
  `\u2728 WXT project created with the ${TEMPLATE_COLORS[input.template.name]?.(input.template.name) ?? input.template.name} template.`
5384
5562
  );
5385
5563
  console.log();
5386
- import_consola5.consola.log("Next steps:");
5564
+ import_consola6.consola.log("Next steps:");
5387
5565
  let step = 0;
5388
5566
  if (cdPath !== "")
5389
- import_consola5.consola.log(` ${++step}.`, import_picocolors8.default.cyan(`cd ${cdPath}`));
5390
- import_consola5.consola.log(` ${++step}.`, import_picocolors8.default.cyan(`${input.packageManager} install`));
5567
+ import_consola6.consola.log(` ${++step}.`, import_picocolors8.default.cyan(`cd ${cdPath}`));
5568
+ import_consola6.consola.log(` ${++step}.`, import_picocolors8.default.cyan(`${input.packageManager} install`));
5391
5569
  console.log();
5392
5570
  }
5393
5571
  async function listTemplates() {
@@ -5429,10 +5607,10 @@ async function cloneProject({
5429
5607
  force: true
5430
5608
  });
5431
5609
  await import_fs_extra14.default.move(
5432
- import_node_path18.default.join(directory, "_gitignore"),
5433
- import_node_path18.default.join(directory, ".gitignore")
5610
+ import_node_path19.default.join(directory, "_gitignore"),
5611
+ import_node_path19.default.join(directory, ".gitignore")
5434
5612
  ).catch(
5435
- (err) => import_consola5.consola.warn("Failed to move _gitignore to .gitignore:", err)
5613
+ (err) => import_consola6.consola.warn("Failed to move _gitignore to .gitignore:", err)
5436
5614
  );
5437
5615
  spinner.succeed();
5438
5616
  } catch (err) {
@@ -5463,7 +5641,7 @@ async function prepare(config) {
5463
5641
 
5464
5642
  // src/core/zip.ts
5465
5643
  var import_zip_dir = __toESM(require("zip-dir"), 1);
5466
- var import_node_path19 = require("path");
5644
+ var import_node_path20 = require("path");
5467
5645
  var import_fs_extra15 = __toESM(require("fs-extra"), 1);
5468
5646
  var import_minimatch2 = require("minimatch");
5469
5647
  async function zip(config) {
@@ -5473,7 +5651,7 @@ async function zip(config) {
5473
5651
  internalConfig.logger.info("Zipping extension...");
5474
5652
  const zipFiles = [];
5475
5653
  const projectName = internalConfig.zip.name ?? kebabCaseAlphanumeric(
5476
- (await getPackageJson(internalConfig))?.name || (0, import_node_path19.dirname)(process.cwd())
5654
+ (await getPackageJson(internalConfig))?.name || (0, import_node_path20.dirname)(process.cwd())
5477
5655
  );
5478
5656
  const applyTemplate = (template) => template.replaceAll("{{name}}", projectName).replaceAll("{{browser}}", internalConfig.browser).replaceAll(
5479
5657
  "{{version}}",
@@ -5481,7 +5659,7 @@ async function zip(config) {
5481
5659
  ).replaceAll("{{manifestVersion}}", `mv${internalConfig.manifestVersion}`);
5482
5660
  await import_fs_extra15.default.ensureDir(internalConfig.outBaseDir);
5483
5661
  const outZipFilename = applyTemplate(internalConfig.zip.artifactTemplate);
5484
- const outZipPath = (0, import_node_path19.resolve)(internalConfig.outBaseDir, outZipFilename);
5662
+ const outZipPath = (0, import_node_path20.resolve)(internalConfig.outBaseDir, outZipFilename);
5485
5663
  await (0, import_zip_dir.default)(internalConfig.outDir, {
5486
5664
  saveTo: outZipPath
5487
5665
  });
@@ -5490,14 +5668,14 @@ async function zip(config) {
5490
5668
  const sourcesZipFilename = applyTemplate(
5491
5669
  internalConfig.zip.sourcesTemplate
5492
5670
  );
5493
- const sourcesZipPath = (0, import_node_path19.resolve)(
5671
+ const sourcesZipPath = (0, import_node_path20.resolve)(
5494
5672
  internalConfig.outBaseDir,
5495
5673
  sourcesZipFilename
5496
5674
  );
5497
5675
  await (0, import_zip_dir.default)(internalConfig.zip.sourcesRoot, {
5498
5676
  saveTo: sourcesZipPath,
5499
5677
  filter(path10) {
5500
- const relativePath = (0, import_node_path19.relative)(internalConfig.zip.sourcesRoot, path10);
5678
+ const relativePath = (0, import_node_path20.relative)(internalConfig.zip.sourcesRoot, path10);
5501
5679
  const matchedPattern = internalConfig.zip.ignoredSources.find(
5502
5680
  (pattern) => (0, import_minimatch2.minimatch)(relativePath, pattern)
5503
5681
  );