wxt 0.21.2 → 0.21.4

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.
Files changed (43) hide show
  1. package/dist/builtin-modules/escape-unicode.mjs +34 -0
  2. package/dist/builtin-modules/index.mjs +6 -1
  3. package/dist/builtin-modules/unimport.mjs +3 -3
  4. package/dist/cli/cli-utils.mjs +5 -2
  5. package/dist/core/builders/vite/index.mjs +8 -1
  6. package/dist/core/builders/vite/plugins/devHtmlPrerender.mjs +2 -2
  7. package/dist/core/initialize.d.mts +3 -3
  8. package/dist/core/initialize.mjs +33 -47
  9. package/dist/core/keyboard-shortcuts.mjs +1 -0
  10. package/dist/core/package-managers/bun.mjs +5 -2
  11. package/dist/core/package-managers/npm.mjs +10 -4
  12. package/dist/core/package-managers/pnpm.mjs +5 -2
  13. package/dist/core/package-managers/yarn.mjs +5 -2
  14. package/dist/core/resolve-config.mjs +17 -20
  15. package/dist/core/utils/building/find-entrypoints.mjs +3 -3
  16. package/dist/core/utils/building/internal-build.mjs +3 -3
  17. package/dist/core/utils/building/rebuild.mjs +1 -1
  18. package/dist/core/utils/create-file-reloader.mjs +3 -3
  19. package/dist/core/utils/env.mjs +5 -1
  20. package/dist/core/utils/fs.mjs +6 -1
  21. package/dist/core/utils/log/index.mjs +1 -0
  22. package/dist/core/utils/log/printFileList.mjs +3 -3
  23. package/dist/core/utils/log/wxtLogger.mjs +32 -0
  24. package/dist/core/utils/manifest.mjs +6 -6
  25. package/dist/core/utils/paths.mjs +2 -2
  26. package/dist/core/utils/spinner.mjs +69 -0
  27. package/dist/core/utils/strings.mjs +2 -2
  28. package/dist/core/zip.mjs +6 -13
  29. package/dist/index.d.mts +2 -2
  30. package/dist/inline/get-port-please/index.mjs +196 -0
  31. package/dist/inline/is-wsl/index.mjs +44 -0
  32. package/dist/inline/normalize-path/index.mjs +23 -0
  33. package/dist/inline/ohash/index.mjs +113 -0
  34. package/dist/inline/scule/index.mjs +50 -0
  35. package/dist/types.d.mts +49 -34
  36. package/dist/utils/content-script-ui/iframe.d.mts +2 -0
  37. package/dist/utils/content-script-ui/iframe.mjs +2 -0
  38. package/dist/utils/content-script-ui/integrated.d.mts +2 -0
  39. package/dist/utils/content-script-ui/integrated.mjs +2 -0
  40. package/dist/utils/content-script-ui/shadow-root.d.mts +2 -0
  41. package/dist/utils/content-script-ui/shadow-root.mjs +2 -0
  42. package/dist/version.mjs +1 -1
  43. package/package.json +16 -19
@@ -0,0 +1,34 @@
1
+ import { addViteConfig, defineWxtModule } from "../modules.mjs";
2
+ //#region src/builtin-modules/escape-unicode.ts
3
+ var escape_unicode_default = defineWxtModule({
4
+ name: "wxt:built-in:escape-unicode",
5
+ setup(wxt) {
6
+ if (!wxt.config.experimental.escapeUnicode) return;
7
+ addViteConfig(wxt, () => ({ plugins: [escapeUnicodePlugin(wxt)] }));
8
+ }
9
+ });
10
+ function escapeUnicodePlugin(wxt) {
11
+ return {
12
+ name: "wxt:escape-unicode",
13
+ generateBundle: (_, bundle) => {
14
+ const start = Date.now();
15
+ for (const key of Object.keys(bundle)) {
16
+ const chunk = bundle[key];
17
+ if (chunk.type === "chunk") chunk.code = escapeNonCharacterUnicode(chunk.code);
18
+ }
19
+ const end = Date.now();
20
+ wxt.logger.info("Escaped UTF8 non-characters in " + (end - start) + "ms");
21
+ }
22
+ };
23
+ }
24
+ /**
25
+ * See:
26
+ *
27
+ * - https://github.com/rolldown/rolldown/issues/8805#issuecomment-4103480096
28
+ * - https://github.com/rolldown/rolldown/issues/8805#issuecomment-5134001768
29
+ */
30
+ function escapeNonCharacterUnicode(text) {
31
+ return text.replace(/[\uFDD0-\uFDEF\uFFFE\uFFFF]|[\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/gu, (m) => "\\u" + m.codePointAt(0).toString(16));
32
+ }
33
+ //#endregion
34
+ export { escape_unicode_default as default };
@@ -1,6 +1,11 @@
1
1
  import favicon_permission_default from "./favicon-permission.mjs";
2
2
  import unimport_default from "./unimport.mjs";
3
+ import escape_unicode_default from "./escape-unicode.mjs";
3
4
  //#region src/builtin-modules/index.ts
4
- const builtinModules = [unimport_default, favicon_permission_default];
5
+ const builtinModules = [
6
+ unimport_default,
7
+ favicon_permission_default,
8
+ escape_unicode_default
9
+ ];
5
10
  //#endregion
6
11
  export { builtinModules };
@@ -55,13 +55,13 @@ async function getImportsModuleEntry(wxt, unimport) {
55
55
  tsReference: true
56
56
  };
57
57
  }
58
- async function getEslintConfigEntry(unimport, version, options) {
58
+ async function getEslintConfigEntry(unimport, configVersion, options) {
59
59
  const globals = (await unimport.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().reduce((globals, name) => {
60
60
  globals[name] = options.eslintrc.globalsPropValue;
61
61
  return globals;
62
62
  }, {});
63
- if (version <= 8) return getEslint8ConfigEntry(options, globals);
64
- else return getEslint9ConfigEntry(options, globals);
63
+ if (configVersion === 8) return getEslint8ConfigEntry(options, globals);
64
+ return getEslint9ConfigEntry(options, globals);
65
65
  }
66
66
  function getEslint8ConfigEntry(options, globals) {
67
67
  return {
@@ -4,7 +4,7 @@ import { formatDuration } from "../core/utils/time.mjs";
4
4
  import { printHeader } from "../core/utils/log/printHeader.mjs";
5
5
  import "../core/utils/log/index.mjs";
6
6
  import { ValidationError } from "../core/utils/validation.mjs";
7
- import spawn from "nano-spawn";
7
+ import { x } from "tinyexec";
8
8
  import consola, { LogLevels } from "consola";
9
9
  //#region src/cli/cli-utils.ts
10
10
  /**
@@ -47,7 +47,10 @@ function createAliasedCommand(base, name, alias, bin, docsUrl) {
47
47
  const aliasedCommand = base.command(`${name} [...args]`, `Alias for ${alias} (${docsUrl})`).allowUnknownOptions().action(async () => {
48
48
  try {
49
49
  await registerWxt("build");
50
- await spawn(bin, process.argv.slice(process.argv.indexOf(aliasedCommand.name) + 1), { stdio: "inherit" });
50
+ await x(bin, process.argv.slice(process.argv.indexOf(aliasedCommand.name) + 1), {
51
+ throwOnError: true,
52
+ nodeOptions: { stdio: "inherit" }
53
+ });
51
54
  } catch {
52
55
  process.exit(1);
53
56
  }
@@ -347,7 +347,14 @@ async function removeEmptyDirs(dir) {
347
347
  const files = await readdir(dir);
348
348
  for (const file of files) {
349
349
  const filePath = join(dir, file);
350
- if ((await stat(filePath)).isDirectory()) await removeEmptyDirs(filePath);
350
+ let stats;
351
+ try {
352
+ stats = await stat(filePath);
353
+ } catch (err) {
354
+ if (err?.code === "ENOENT") continue;
355
+ throw err;
356
+ }
357
+ if (stats.isDirectory()) await removeEmptyDirs(filePath);
351
358
  }
352
359
  try {
353
360
  await rmdir(dir);
@@ -1,9 +1,9 @@
1
1
  import { normalizePath } from "../../../utils/paths.mjs";
2
2
  import { getEntrypointName } from "../../../utils/entrypoints.mjs";
3
3
  import "../../../utils/index.mjs";
4
+ import { c } from "../../../../inline/ohash/index.mjs";
4
5
  import { dirname, relative, resolve } from "node:path";
5
6
  import { parseHTML } from "linkedom";
6
- import { hash } from "ohash";
7
7
  //#region src/core/builders/vite/plugins/devHtmlPrerender.ts
8
8
  const inlineScriptContents = {};
9
9
  /**
@@ -48,7 +48,7 @@ function devHtmlPrerender(config, server) {
48
48
  const { document } = parseHTML(await server.transformHtml(url, html, originalUrl));
49
49
  document.querySelectorAll("script:not([src])").forEach((script) => {
50
50
  const textContent = script.textContent ?? "";
51
- const key = hash(textContent);
51
+ const key = c(textContent);
52
52
  inlineScriptContents[key] = textContent;
53
53
  const virtualScript = document.createElement("script");
54
54
  virtualScript.type = "module";
@@ -1,8 +1,8 @@
1
1
  //#region src/core/initialize.d.ts
2
2
  declare function initialize(options: {
3
- directory: string;
4
- template: string;
5
- packageManager: string;
3
+ directory?: string;
4
+ template?: string;
5
+ packageManager?: string;
6
6
  }): Promise<void>;
7
7
  //#endregion
8
8
  export { initialize };
@@ -1,73 +1,60 @@
1
1
  import { pathExists } from "./utils/fs.mjs";
2
+ import { createSpinner } from "./utils/spinner.mjs";
2
3
  import { readdir, rename } from "node:fs/promises";
3
4
  import path from "node:path";
4
5
  import { consola as consola$1 } from "consola";
5
6
  import { styleText } from "node:util";
6
- import prompts from "prompts";
7
+ import { question, select } from "@topcli/prompts";
7
8
  import { downloadTemplate } from "giget";
8
9
  //#region src/core/initialize.ts
9
10
  async function initialize(options) {
10
11
  consola$1.info("Initializing new project");
11
12
  const templates = await listTemplates();
12
- const defaultTemplate = templates.find((template) => template.name === options.template?.toLowerCase().trim());
13
- const input = await prompts([
13
+ const inputTemplateName = options.template ? templates.find((template) => template.name === options.template.toLowerCase().trim())?.name : void 0;
14
+ const directory = options.directory ?? await question("Project Directory", { defaultValue: "." });
15
+ if (!directory) throw Error("Directory is required");
16
+ const templateName = inputTemplateName ?? await select("Choose a template", { choices: templates.map((template) => ({
17
+ label: TEMPLATE_COLORS[template.name] ? styleText(TEMPLATE_COLORS[template.name], template.name) : template.name,
18
+ value: template.name
19
+ })) });
20
+ const template = templates.find((t) => t.name === templateName);
21
+ if (!template) throw Error("Unknown template: " + templateName);
22
+ const packageManager = options.packageManager ?? await select("Package Manager", { choices: [
14
23
  {
15
- name: "directory",
16
- type: () => options.directory == null ? "text" : void 0,
17
- message: "Project Directory",
18
- initial: options.directory
24
+ label: styleText("magenta", "bun"),
25
+ value: "bun"
19
26
  },
20
27
  {
21
- name: "template",
22
- type: () => defaultTemplate == null ? "select" : void 0,
23
- message: "Choose a template",
24
- choices: templates.map((template) => ({
25
- title: TEMPLATE_COLORS[template.name] ? styleText(TEMPLATE_COLORS[template.name], template.name) : template.name,
26
- value: template
27
- }))
28
+ label: styleText("red", "npm"),
29
+ value: "npm"
28
30
  },
29
31
  {
30
- name: "packageManager",
31
- type: () => options.packageManager == null ? "select" : void 0,
32
- message: "Package Manager",
33
- choices: [
34
- {
35
- title: styleText("magenta", "bun"),
36
- value: "bun"
37
- },
38
- {
39
- title: styleText("red", "npm"),
40
- value: "npm"
41
- },
42
- {
43
- title: styleText("yellow", "pnpm"),
44
- value: "pnpm"
45
- },
46
- {
47
- title: styleText("cyan", "yarn"),
48
- value: "yarn"
49
- }
50
- ]
32
+ label: styleText("yellow", "pnpm"),
33
+ value: "pnpm"
34
+ },
35
+ {
36
+ label: styleText("cyan", "yarn"),
37
+ value: "yarn"
51
38
  }
52
- ], { onCancel: () => process.exit(1) });
53
- input.directory ||= options.directory || ".";
54
- input.template ??= defaultTemplate;
55
- input.packageManager ??= options.packageManager;
56
- if (await pathExists(input.directory)) {
57
- if (!((await readdir(input.directory)).filter((dir) => dir !== ".git").length === 0)) {
58
- consola$1.error(`The directory ${path.resolve(input.directory)} is not empty. Aborted.`);
39
+ ] });
40
+ if (await pathExists(directory)) {
41
+ if (!((await readdir(directory)).filter((dir) => dir !== ".git").length === 0)) {
42
+ consola$1.error(`The directory ${path.resolve(directory)} is not empty. Aborted.`);
59
43
  process.exit(1);
60
44
  }
61
45
  }
62
- await cloneProject(input);
63
- const cdPath = path.relative(process.cwd(), path.resolve(input.directory));
46
+ await cloneProject({
47
+ directory,
48
+ template
49
+ });
50
+ const cdPath = path.relative(process.cwd(), path.resolve(directory));
64
51
  console.log();
65
- consola$1.log(`✨ WXT project created with the ${TEMPLATE_COLORS[input.template.name] ? styleText(TEMPLATE_COLORS[input.template.name], input.template.name) : input.template.name} template.`);
52
+ consola$1.log(`✨ WXT project created with the ${TEMPLATE_COLORS[template.name] ? styleText(TEMPLATE_COLORS[template.name], template.name) : template.name} template.`);
66
53
  console.log();
67
54
  consola$1.log("Next steps:");
68
55
  let step = 0;
69
56
  if (cdPath !== "") consola$1.log(` ${++step}.`, styleText("cyan", `cd ${cdPath}`));
70
- consola$1.log(` ${++step}.`, styleText("cyan", `${input.packageManager} install`));
57
+ consola$1.log(` ${++step}.`, styleText("cyan", `${packageManager} install`));
71
58
  console.log();
72
59
  }
73
60
  async function listTemplates() {
@@ -94,7 +81,6 @@ async function listTemplatesGithub() {
94
81
  return await res.json();
95
82
  }
96
83
  async function cloneProject({ directory, template }) {
97
- const { createSpinner } = await import("nanospinner");
98
84
  const spinner = createSpinner("Downloading template").start();
99
85
  try {
100
86
  await downloadTemplate(`gh:${REPO}/${template.path}`, {
@@ -11,6 +11,7 @@ function createKeyboardShortcuts(server) {
11
11
  return {
12
12
  start() {
13
13
  this.stop();
14
+ if (!process.stdin.isTTY) return;
14
15
  rl ??= readline.createInterface({
15
16
  input: process.stdin,
16
17
  terminal: false
@@ -1,5 +1,5 @@
1
1
  import { dedupeDependencies, npm } from "./npm.mjs";
2
- import spawn from "nano-spawn";
2
+ import { x } from "tinyexec";
3
3
  //#region src/core/package-managers/bun.ts
4
4
  const bun = {
5
5
  overridesKey: "overrides",
@@ -9,7 +9,10 @@ const bun = {
9
9
  async listDependencies(options) {
10
10
  const args = ["pm", "ls"];
11
11
  if (options?.all) args.push("--all");
12
- return dedupeDependencies((await spawn("bun", args, { cwd: options?.cwd })).stdout.split("\n").slice(1).map((line) => line.trim()).map((line) => /.* (@?\S+)@(\S+)$/.exec(line)).filter((match) => !!match).map(([_, name, version]) => ({
12
+ return dedupeDependencies((await x("bun", args, {
13
+ throwOnError: true,
14
+ nodeOptions: { cwd: options?.cwd }
15
+ })).stdout.split("\n").slice(1).map((line) => line.trim()).map((line) => /.* (@?\S+)@(\S+)$/.exec(line)).filter((match) => !!match).map(([_, name, version]) => ({
13
16
  name,
14
17
  version
15
18
  })));
@@ -1,23 +1,29 @@
1
1
  import { mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import spawn from "nano-spawn";
3
+ import { x } from "tinyexec";
4
4
  //#region src/core/package-managers/npm.ts
5
5
  const npm = {
6
6
  overridesKey: "overrides",
7
7
  async downloadDependency(id, downloadDir) {
8
8
  await mkdir(downloadDir, { recursive: true });
9
- const res = await spawn("npm", [
9
+ const res = await x("npm", [
10
10
  "pack",
11
11
  id,
12
12
  "--json"
13
- ], { cwd: downloadDir });
13
+ ], {
14
+ throwOnError: true,
15
+ nodeOptions: { cwd: downloadDir }
16
+ });
14
17
  const packed = JSON.parse(res.stdout);
15
18
  return path.resolve(downloadDir, packed[0].filename);
16
19
  },
17
20
  async listDependencies(options) {
18
21
  const args = ["ls", "--json"];
19
22
  if (options?.all) args.push("--depth", "Infinity");
20
- const res = await spawn("npm", args, { cwd: options?.cwd });
23
+ const res = await x("npm", args, {
24
+ throwOnError: true,
25
+ nodeOptions: { cwd: options?.cwd }
26
+ });
21
27
  return flattenNpmListOutput([JSON.parse(res.stdout)]);
22
28
  }
23
29
  };
@@ -1,5 +1,5 @@
1
1
  import { flattenNpmListOutput, npm } from "./npm.mjs";
2
- import spawn from "nano-spawn";
2
+ import { x } from "tinyexec";
3
3
  //#region src/core/package-managers/pnpm.ts
4
4
  const pnpm = {
5
5
  overridesKey: "resolutions",
@@ -14,7 +14,10 @@ const pnpm = {
14
14
  ];
15
15
  if (options?.all) args.push("--depth", "Infinity");
16
16
  if (typeof process !== "undefined" && process.env.WXT_PNPM_IGNORE_WORKSPACE === "true") args.push("--ignore-workspace");
17
- const res = await spawn("pnpm", args, { cwd: options?.cwd });
17
+ const res = await x("pnpm", args, {
18
+ throwOnError: true,
19
+ nodeOptions: { cwd: options?.cwd }
20
+ });
18
21
  return flattenNpmListOutput(JSON.parse(res.stdout));
19
22
  }
20
23
  };
@@ -1,5 +1,5 @@
1
1
  import { dedupeDependencies, npm } from "./npm.mjs";
2
- import spawn from "nano-spawn";
2
+ import { x } from "tinyexec";
3
3
  //#region src/core/package-managers/yarn.ts
4
4
  const yarn = {
5
5
  overridesKey: "resolutions",
@@ -9,7 +9,10 @@ const yarn = {
9
9
  async listDependencies(options) {
10
10
  const args = ["list", "--json"];
11
11
  if (options?.all) args.push("--depth", "Infinity");
12
- const tree = (await spawn("yarn", args, { cwd: options?.cwd })).stdout.split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
12
+ const tree = (await x("yarn", args, {
13
+ throwOnError: true,
14
+ nodeOptions: { cwd: options?.cwd }
15
+ })).stdout.trimEnd().split("\n").map((line) => JSON.parse(line)).find((line) => line.type === "tree")?.data;
13
16
  if (tree == null) throw Error("'yarn list --json' did not output a tree");
14
17
  const queue = [...tree.trees];
15
18
  const dependencies = [];
@@ -5,19 +5,19 @@ import { createFsCache } from "./utils/cache.mjs";
5
5
  import { getEslintVersion } from "./utils/eslint.mjs";
6
6
  import { safeStringToNumber } from "./utils/number.mjs";
7
7
  import { loadEnv } from "./utils/env.mjs";
8
+ import { v } from "../inline/get-port-please/index.mjs";
8
9
  import { createSafariRunner } from "./runners/safari.mjs";
10
+ import { d } from "../inline/is-wsl/index.mjs";
9
11
  import { createWslRunner } from "./runners/wsl.mjs";
10
12
  import { createManualRunner } from "./runners/manual.mjs";
13
+ import { createWxtLogger } from "./utils/log/wxtLogger.mjs";
11
14
  import { pathExists } from "./utils/fs.mjs";
12
15
  import { glob } from "tinyglobby";
13
16
  import path from "node:path";
14
17
  import { loadConfig } from "c12";
15
- import { resolve as resolve$1 } from "import-meta-resolve";
16
18
  import consola, { LogLevels } from "consola";
17
19
  import defu from "defu";
18
- import { getPort } from "get-port-please";
19
20
  import { fileURLToPath, pathToFileURL } from "node:url";
20
- import isWsl from "is-wsl";
21
21
  //#region src/core/resolve-config.ts
22
22
  /**
23
23
  * Given an inline config, discover the config file if necessary, merge the
@@ -41,7 +41,7 @@ async function resolveConfig(inlineConfig, command) {
41
41
  }
42
42
  const mergedConfig = await mergeInlineConfig(inlineConfig, userConfig);
43
43
  const debug = mergedConfig.debug ?? false;
44
- const logger = mergedConfig.logger ?? consola;
44
+ const logger = createWxtLogger(mergedConfig.logger ?? consola);
45
45
  if (debug) logger.level = LogLevels.debug;
46
46
  const browser = mergedConfig.browser ?? "chrome";
47
47
  const targetBrowsers = mergedConfig.targetBrowsers ?? [];
@@ -94,12 +94,12 @@ async function resolveConfig(inlineConfig, command) {
94
94
  let port = mergedConfig.dev?.server?.port;
95
95
  const origin = mergedConfig.dev?.server?.origin ?? "localhost";
96
96
  const strictPort = mergedConfig.dev?.server?.strictPort ?? false;
97
- if (port == null || !isFinite(port)) port = await getPort({
97
+ if (port == null || !isFinite(port)) port = await v({
98
98
  host,
99
99
  port: 3e3,
100
100
  portRange: [3001, 3010]
101
101
  });
102
- else if (!strictPort) port = await getPort({
102
+ else if (!strictPort) port = await v({
103
103
  host,
104
104
  port
105
105
  });
@@ -142,7 +142,7 @@ async function resolveConfig(inlineConfig, command) {
142
142
  wxtModuleDir,
143
143
  root,
144
144
  webExt,
145
- runner: command === "serve" ? await resolveRunner(browser, logger, mergedConfig) : createManualRunner(),
145
+ runner: command === "serve" ? await resolveRunner(browser, logger, webExt.config) : createManualRunner(),
146
146
  srcDir,
147
147
  typesDir,
148
148
  wxtDir,
@@ -150,7 +150,7 @@ async function resolveConfig(inlineConfig, command) {
150
150
  analysis: resolveAnalysisConfig(root, mergedConfig),
151
151
  userConfigMetadata: userConfigMetadata ?? {},
152
152
  alias,
153
- experimental: defu(mergedConfig.experimental, {}),
153
+ experimental: defu(mergedConfig.experimental, { escapeUnicode: false }),
154
154
  suppressWarnings: mergedConfig.suppressWarnings ?? {},
155
155
  watchOptions: mergedConfig.watchOptions ?? {},
156
156
  dev: {
@@ -342,17 +342,14 @@ async function getUnimportOptions(wxtDir, srcDir, logger, config) {
342
342
  return defu(config.imports ?? {}, defaultOptions);
343
343
  }
344
344
  async function getUnimportEslintOptions(logger, wxtDir, options) {
345
- const inlineEnabled = options === false ? false : options?.eslintrc?.enabled ?? "auto";
345
+ const inlineEnabled = options === false ? false : options?.eslintrc?.enabled ?? true;
346
346
  const version = await getEslintVersion();
347
347
  const major = parseInt(version[0]);
348
348
  let enabled;
349
349
  switch (inlineEnabled) {
350
- case "auto":
350
+ case "auto": logger.warn(`\`imports.eslintrc.enabled: "auto"\` is deprecated. Use \`true\` instead.`);
351
351
  case true:
352
- if (isNaN(major)) {
353
- if (inlineEnabled === true) logger.warn("Could not determine installed ESLint version, `eslint-auto-imports.mjs` not generated");
354
- enabled = false;
355
- } else if (major <= 8) enabled = 8;
352
+ if (major <= 8) enabled = 8;
356
353
  else if (major >= 9) enabled = 9;
357
354
  else enabled = false;
358
355
  break;
@@ -366,14 +363,14 @@ async function getUnimportEslintOptions(logger, wxtDir, options) {
366
363
  }
367
364
  /** Returns the path to `node_modules/wxt`. */
368
365
  function resolveWxtModuleDir() {
369
- const url = resolve$1("wxt", import.meta.url);
366
+ const url = import.meta.resolve("wxt", import.meta.url);
370
367
  return path.resolve(fileURLToPath(url), "../..");
371
368
  }
372
369
  async function isDirMissing(dir) {
373
370
  return !await pathExists(dir);
374
371
  }
375
372
  function logMissingDir(logger, name, expected) {
376
- logger.warn(`${name} directory not found: ./${normalizePath(path.relative(process.cwd(), expected))}`);
373
+ logger.warnOnce(`${name} directory not found: ./${normalizePath(path.relative(process.cwd(), expected))}`);
377
374
  }
378
375
  /** Map of `ConfigEnv` commands to their default modes. */
379
376
  const COMMAND_MODES = {
@@ -393,7 +390,7 @@ async function mergeBuilderConfig(logger, inlineConfig, userConfig) {
393
390
  async function resolveWxtUserModules(root, modulesDir, modules = []) {
394
391
  const importer = pathToFileURL(path.join(root, "index.js")).href;
395
392
  const npmModules = await Promise.all(modules.map(async (moduleId) => {
396
- const mod = await import(resolve$1(moduleId, importer));
393
+ const mod = await import(import.meta.resolve(moduleId, importer));
397
394
  if (mod.default == null) throw Error("Module missing default export: " + moduleId);
398
395
  return {
399
396
  ...mod.default,
@@ -427,12 +424,12 @@ async function resolveWxtUserModules(root, modulesDir, modules = []) {
427
424
  }));
428
425
  return [...npmModules, ...localModules];
429
426
  }
430
- async function resolveRunner(browser, logger, mergedConfig) {
427
+ async function resolveRunner(browser, logger, webExt) {
431
428
  if (browser === "safari") return createSafariRunner();
432
- if (isWsl) return createWslRunner();
429
+ if (d) return createWslRunner();
433
430
  try {
434
431
  const { createWebExtRunner } = await import("./runners/web-ext.mjs");
435
- return mergedConfig.webExt?.disabled ? createManualRunner() : createWebExtRunner();
432
+ return webExt.disabled ? createManualRunner() : createWebExtRunner();
436
433
  } catch (err) {
437
434
  if (err?.code !== "ERR_MODULE_NOT_FOUND") throw err;
438
435
  logger.debug("Error loading the web-ext runner", err);
@@ -1,12 +1,12 @@
1
1
  import { CSS_EXTENSIONS_PATTERN } from "../paths.mjs";
2
2
  import { getEntrypointName, isHtmlEntrypoint, isJsEntrypoint, resolvePerBrowserOptions } from "../entrypoints.mjs";
3
+ import { s } from "../../../inline/scule/index.mjs";
3
4
  import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from "../constants.mjs";
4
5
  import { wxt } from "../../wxt.mjs";
5
6
  import { mkdir, readFile, writeFile } from "node:fs/promises";
6
7
  import { glob } from "tinyglobby";
7
8
  import { relative, resolve } from "path";
8
9
  import { parseHTML } from "linkedom";
9
- import { camelCase } from "scule";
10
10
  import { styleText } from "node:util";
11
11
  import picomatch from "picomatch";
12
12
  import JSON5 from "json5";
@@ -118,8 +118,8 @@ async function importHtmlEntrypoint(info) {
118
118
  metaTags.forEach((tag) => {
119
119
  const name = tag.name;
120
120
  let key;
121
- if (name.startsWith("manifest.")) key = camelCase(name.slice(9));
122
- else if (name.startsWith("wxt.")) key = camelCase(name.slice(4));
121
+ if (name.startsWith("manifest.")) key = s(name.slice(9));
122
+ else if (name.startsWith("wxt.")) key = s(name.slice(4));
123
123
  else return;
124
124
  try {
125
125
  res[key] = JSON5.parse(tag.content);
@@ -1,4 +1,5 @@
1
1
  import { unnormalizePath } from "../paths.mjs";
2
+ import { isCI } from "../env.mjs";
2
3
  import { wxt } from "../../wxt.mjs";
3
4
  import { findEntrypoints } from "./find-entrypoints.mjs";
4
5
  import { groupEntrypoints } from "./group-entrypoints.mjs";
@@ -12,7 +13,7 @@ import { glob } from "tinyglobby";
12
13
  import { relative } from "node:path";
13
14
  import { mergeJsonOutputs } from "@aklinker1/rollup-plugin-visualizer";
14
15
  import { styleText } from "node:util";
15
- import { isCI } from "ci-info";
16
+ import open from "tiny-open";
16
17
  //#region src/core/utils/building/internal-build.ts
17
18
  /**
18
19
  * Builds the extension based on an internal config. No more config discovery is
@@ -51,10 +52,9 @@ async function internalBuild() {
51
52
  await combineAnalysisStats();
52
53
  const statsPath = relative(wxt.config.root, wxt.config.analysis.outputFile);
53
54
  wxt.logger.info(`Analysis complete:\n ${styleText("gray", "└─")} ${styleText("yellow", statsPath)}`);
54
- if (wxt.config.analysis.open) if (isCI) wxt.logger.debug(`Skipped opening ${styleText("yellow", statsPath)} in CI`);
55
+ if (wxt.config.analysis.open) if (isCI()) wxt.logger.debug(`Skipped opening ${styleText("yellow", statsPath)} in CI`);
55
56
  else {
56
57
  wxt.logger.info(`Opening ${styleText("yellow", statsPath)} in browser...`);
57
- const { default: open } = await import("open");
58
58
  await open(wxt.config.analysis.outputFile);
59
59
  }
60
60
  }
@@ -1,8 +1,8 @@
1
1
  import { wxt } from "../../wxt.mjs";
2
2
  import { buildEntrypoints } from "./build-entrypoints.mjs";
3
+ import { createSpinner } from "../spinner.mjs";
3
4
  import { generateWxtDir } from "../../generate-wxt-dir.mjs";
4
5
  import { generateManifest, writeManifest } from "../manifest.mjs";
5
- import { createSpinner } from "nanospinner";
6
6
  //#region src/core/utils/building/rebuild.ts
7
7
  /**
8
8
  * Given a configuration, list of entrypoints, and an existing, partial output,
@@ -12,18 +12,18 @@ import "./building/index.mjs";
12
12
  import { isBabelSyntaxError, logBabelSyntaxError } from "./syntax-errors.mjs";
13
13
  import { relative } from "node:path";
14
14
  import { styleText } from "node:util";
15
- import { Mutex } from "async-mutex";
15
+ import { withLock } from "superlock";
16
16
  //#region src/core/utils/create-file-reloader.ts
17
17
  /**
18
18
  * Returns a function responsible for reloading different parts of the extension
19
19
  * when a file changes.
20
20
  */
21
21
  function createFileReloader(server) {
22
- const fileChangedMutex = new Mutex();
22
+ const fileChangedLock = withLock();
23
23
  const changeQueue = [];
24
24
  let processLoop;
25
25
  const processQueue = async () => {
26
- await fileChangedMutex.runExclusive(async () => {
26
+ await fileChangedLock(async () => {
27
27
  const fileChanges = changeQueue.splice(0, changeQueue.length).map(([_, file]) => file);
28
28
  if (fileChanges.length === 0) return;
29
29
  if (server.currentOutput == null) return;
@@ -2,6 +2,10 @@ import { expand } from "dotenv-expand";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { parseEnv } from "node:util";
4
4
  //#region src/core/utils/env.ts
5
+ /** Returns true when running in a CI environment. */
6
+ function isCI() {
7
+ return !!process.env.CI && process.env.CI !== "false";
8
+ }
5
9
  /** Load environment files based on the current mode and browser. */
6
10
  function loadEnv(mode, browser) {
7
11
  const envFiles = [
@@ -27,4 +31,4 @@ function loadEnv(mode, browser) {
27
31
  return parsed;
28
32
  }
29
33
  //#endregion
30
- export { loadEnv };
34
+ export { isCI, loadEnv };
@@ -32,5 +32,10 @@ async function getPublicFiles() {
32
32
  expandDirectories: false
33
33
  })).map(unnormalizePath);
34
34
  }
35
+ function getBytesDisplay(bytes) {
36
+ if (bytes < 1e3) return `${bytes} B`;
37
+ if (bytes < 999995) return `${(bytes / 1e3).toFixed(2)} kB`;
38
+ return `${(bytes / 1e6).toFixed(2)} MB`;
39
+ }
35
40
  //#endregion
36
- export { getPublicFiles, pathExists, readJson, writeFileIfDifferent };
41
+ export { getBytesDisplay, getPublicFiles, pathExists, readJson, writeFileIfDifferent };
@@ -1,3 +1,4 @@
1
+ import "./wxtLogger.mjs";
1
2
  import "./printTable.mjs";
2
3
  import "./printFileList.mjs";
3
4
  import "./printBuildSummary.mjs";
@@ -1,9 +1,9 @@
1
1
  import { wxt } from "../../wxt.mjs";
2
+ import { getBytesDisplay } from "../fs.mjs";
2
3
  import { printTable } from "./printTable.mjs";
3
4
  import { lstat } from "node:fs/promises";
4
5
  import path from "node:path";
5
6
  import { styleText } from "node:util";
6
- import { filesize } from "filesize";
7
7
  //#region src/core/utils/log/printFileList.ts
8
8
  async function printFileList(log, header, baseDir, files) {
9
9
  let totalSize = 0;
@@ -15,13 +15,13 @@ async function printFileList(log, header, baseDir, files) {
15
15
  try {
16
16
  const stats = await lstat(file);
17
17
  totalSize += stats.size;
18
- size = String(filesize(stats.size));
18
+ size = getBytesDisplay(stats.size);
19
19
  } catch (ex) {
20
20
  wxt.logger.warn(`Could not get stats of '${file}' error: ${ex}`);
21
21
  }
22
22
  return [`${styleText("gray", prefix)} ${styleText("dim", parts[0])}${styleText(chunkColor, parts[1])}`, styleText("dim", size)];
23
23
  }));
24
- fileRows.push([`${styleText("cyan", "Σ Total size:")} ${String(filesize(totalSize))}`]);
24
+ fileRows.push([`${styleText("cyan", "Σ Total size:")} ${getBytesDisplay(totalSize)}`]);
25
25
  printTable(log, header, fileRows);
26
26
  }
27
27
  const DEFAULT_COLOR = "blue";