wxt 0.16.1 → 0.16.3

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.
@@ -1,5 +1,73 @@
1
1
  // package.json
2
- var version = "0.16.1";
2
+ var version = "0.16.3";
3
+
4
+ // src/core/utils/fs.ts
5
+ import fs from "fs-extra";
6
+ import glob from "fast-glob";
7
+
8
+ // src/core/utils/paths.ts
9
+ import systemPath from "node:path";
10
+ import normalize from "normalize-path";
11
+ function normalizePath(path6) {
12
+ return normalize(path6);
13
+ }
14
+ function unnormalizePath(path6) {
15
+ return systemPath.normalize(path6);
16
+ }
17
+ var CSS_EXTENSIONS = ["css", "scss", "sass", "less", "styl", "stylus"];
18
+ var CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
19
+
20
+ // src/core/utils/fs.ts
21
+ async function writeFileIfDifferent(file, newContents) {
22
+ const existingContents = await fs.readFile(file, "utf-8").catch(() => void 0);
23
+ if (existingContents !== newContents) {
24
+ await fs.writeFile(file, newContents);
25
+ }
26
+ }
27
+ async function getPublicFiles() {
28
+ if (!await fs.exists(wxt.config.publicDir))
29
+ return [];
30
+ const files = await glob("**/*", { cwd: wxt.config.publicDir });
31
+ return files.map(unnormalizePath);
32
+ }
33
+
34
+ // src/core/utils/building/build-entrypoints.ts
35
+ import fs2 from "fs-extra";
36
+ import { dirname, resolve } from "path";
37
+ import pc from "picocolors";
38
+ async function buildEntrypoints(groups, spinner) {
39
+ const steps = [];
40
+ for (let i = 0; i < groups.length; i++) {
41
+ const group = groups[i];
42
+ const groupNames = [group].flat().map((e) => e.name);
43
+ const groupNameColored = groupNames.join(pc.dim(", "));
44
+ spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
45
+ try {
46
+ steps.push(await wxt.config.builder.build(group));
47
+ } catch (err) {
48
+ throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
49
+ }
50
+ }
51
+ const publicAssets = await copyPublicDirectory();
52
+ return { publicAssets, steps };
53
+ }
54
+ async function copyPublicDirectory() {
55
+ const files = await getPublicFiles();
56
+ if (files.length === 0)
57
+ return [];
58
+ const publicAssets = [];
59
+ for (const file of files) {
60
+ const srcPath = resolve(wxt.config.publicDir, file);
61
+ const outPath = resolve(wxt.config.outDir, file);
62
+ await fs2.ensureDir(dirname(outPath));
63
+ await fs2.copyFile(srcPath, outPath);
64
+ publicAssets.push({
65
+ type: "asset",
66
+ fileName: file
67
+ });
68
+ }
69
+ return publicAssets;
70
+ }
3
71
 
4
72
  // src/core/utils/arrays.ts
5
73
  function every(array, predicate) {
@@ -15,29 +83,17 @@ function some(array, predicate) {
15
83
  return false;
16
84
  }
17
85
 
18
- // src/core/utils/paths.ts
19
- import systemPath from "node:path";
20
- import normalize from "normalize-path";
21
- function normalizePath(path6) {
22
- return normalize(path6);
23
- }
24
- function unnormalizePath(path6) {
25
- return systemPath.normalize(path6);
26
- }
27
- var CSS_EXTENSIONS = ["css", "scss", "sass", "less", "styl", "stylus"];
28
- var CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
29
-
30
86
  // src/core/utils/building/detect-dev-changes.ts
31
- function detectDevChanges(config, changedFiles, currentOutput) {
87
+ function detectDevChanges(changedFiles, currentOutput) {
32
88
  const isConfigChange = some(
33
89
  changedFiles,
34
- (file) => file === config.userConfigMetadata.configFile
90
+ (file) => file === wxt.config.userConfigMetadata.configFile
35
91
  );
36
92
  if (isConfigChange)
37
93
  return { type: "full-restart" };
38
94
  const isRunnerChange = some(
39
95
  changedFiles,
40
- (file) => file === config.runnerConfig.configFile
96
+ (file) => file === wxt.config.runnerConfig.configFile
41
97
  );
42
98
  if (isRunnerChange)
43
99
  return { type: "browser-restart" };
@@ -121,15 +177,23 @@ function findEffectedSteps(changedFile, currentOutput) {
121
177
  return changes;
122
178
  }
123
179
 
180
+ // src/core/utils/building/find-entrypoints.ts
181
+ import { relative as relative2, resolve as resolve3 } from "path";
182
+ import fs3 from "fs-extra";
183
+ import { minimatch } from "minimatch";
184
+ import { parseHTML } from "linkedom";
185
+ import JSON5 from "json5";
186
+ import glob2 from "fast-glob";
187
+
124
188
  // src/core/utils/entrypoints.ts
125
- import path, { relative, resolve } from "node:path";
189
+ import path, { relative, resolve as resolve2 } from "node:path";
126
190
  function getEntrypointName(entrypointsDir, inputPath) {
127
191
  const relativePath = path.relative(entrypointsDir, inputPath);
128
192
  const name = relativePath.split(/[\.\/\\]/, 2)[0];
129
193
  return name;
130
194
  }
131
195
  function getEntrypointOutputFile(entrypoint, ext) {
132
- return resolve(entrypoint.outputDir, `${entrypoint.name}${ext}`);
196
+ return resolve2(entrypoint.outputDir, `${entrypoint.name}${ext}`);
133
197
  }
134
198
  function getEntrypointBundlePath(entrypoint, outDir, ext) {
135
199
  return normalizePath(
@@ -142,71 +206,371 @@ function resolvePerBrowserOption(option, browser) {
142
206
  return option;
143
207
  }
144
208
 
209
+ // src/core/utils/constants.ts
210
+ var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
211
+
145
212
  // src/core/utils/building/find-entrypoints.ts
146
- import { relative as relative6, resolve as resolve13 } from "path";
147
- import fs12 from "fs-extra";
148
- import { minimatch } from "minimatch";
149
- import { parseHTML as parseHTML2 } from "linkedom";
150
- import JSON5 from "json5";
213
+ import pc2 from "picocolors";
214
+ async function findEntrypoints() {
215
+ const relativePaths = await glob2(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
216
+ cwd: wxt.config.entrypointsDir
217
+ });
218
+ relativePaths.sort();
219
+ const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
220
+ const entrypointInfos = relativePaths.reduce((results, relativePath) => {
221
+ const inputPath = resolve3(wxt.config.entrypointsDir, relativePath);
222
+ const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
223
+ const matchingGlob = pathGlobs.find(
224
+ (glob4) => minimatch(relativePath, glob4)
225
+ );
226
+ if (matchingGlob) {
227
+ const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
228
+ results.push({
229
+ name,
230
+ inputPath,
231
+ type,
232
+ skipped: wxt.config.filterEntrypoints != null && !wxt.config.filterEntrypoints.has(name)
233
+ });
234
+ }
235
+ return results;
236
+ }, []);
237
+ preventNoEntrypoints(entrypointInfos);
238
+ preventDuplicateEntrypointNames(entrypointInfos);
239
+ let hasBackground = false;
240
+ const entrypoints = await Promise.all(
241
+ entrypointInfos.map(async (info) => {
242
+ const { type } = info;
243
+ switch (type) {
244
+ case "popup":
245
+ return await getPopupEntrypoint(info);
246
+ case "options":
247
+ return await getOptionsEntrypoint(info);
248
+ case "background":
249
+ hasBackground = true;
250
+ return await getBackgroundEntrypoint(info);
251
+ case "content-script":
252
+ return await getContentScriptEntrypoint(info);
253
+ case "unlisted-page":
254
+ return await getUnlistedPageEntrypoint(info);
255
+ case "unlisted-script":
256
+ return await getUnlistedScriptEntrypoint(info);
257
+ case "content-script-style":
258
+ return {
259
+ ...info,
260
+ type,
261
+ outputDir: resolve3(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
262
+ options: {
263
+ include: void 0,
264
+ exclude: void 0
265
+ }
266
+ };
267
+ default:
268
+ return {
269
+ ...info,
270
+ type,
271
+ outputDir: wxt.config.outDir,
272
+ options: {
273
+ include: void 0,
274
+ exclude: void 0
275
+ }
276
+ };
277
+ }
278
+ })
279
+ );
280
+ if (wxt.config.command === "serve" && !hasBackground) {
281
+ entrypoints.push(
282
+ await getBackgroundEntrypoint({
283
+ inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
284
+ name: "background",
285
+ type: "background",
286
+ skipped: false
287
+ })
288
+ );
289
+ }
290
+ wxt.logger.debug("All entrypoints:", entrypoints);
291
+ const skippedEntrypointNames = entrypointInfos.filter((item) => item.skipped).map((item) => item.name);
292
+ if (skippedEntrypointNames.length) {
293
+ wxt.logger.warn(
294
+ `Filter excluded the following entrypoints:
295
+ ${skippedEntrypointNames.map((item) => `${pc2.dim("-")} ${pc2.cyan(item)}`).join("\n")}`
296
+ );
297
+ }
298
+ const targetEntrypoints = entrypoints.filter((entry) => {
299
+ const { include, exclude } = entry.options;
300
+ if (include?.length && exclude?.length) {
301
+ wxt.logger.warn(
302
+ `The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
303
+ );
304
+ return false;
305
+ }
306
+ if (exclude?.length && !include?.length) {
307
+ return !exclude.includes(wxt.config.browser);
308
+ }
309
+ if (include?.length && !exclude?.length) {
310
+ return include.includes(wxt.config.browser);
311
+ }
312
+ if (skippedEntrypointNames.includes(entry.name)) {
313
+ return false;
314
+ }
315
+ return true;
316
+ });
317
+ wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
318
+ await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
319
+ return targetEntrypoints;
320
+ }
321
+ function preventDuplicateEntrypointNames(files) {
322
+ const namesToPaths = files.reduce(
323
+ (map, { name, inputPath }) => {
324
+ map[name] ??= [];
325
+ map[name].push(inputPath);
326
+ return map;
327
+ },
328
+ {}
329
+ );
330
+ const errorLines = Object.entries(namesToPaths).reduce(
331
+ (lines, [name, absolutePaths]) => {
332
+ if (absolutePaths.length > 1) {
333
+ lines.push(`- ${name}`);
334
+ absolutePaths.forEach((absolutePath) => {
335
+ lines.push(` - ${relative2(wxt.config.root, absolutePath)}`);
336
+ });
337
+ }
338
+ return lines;
339
+ },
340
+ []
341
+ );
342
+ if (errorLines.length > 0) {
343
+ const errorContent = errorLines.join("\n");
344
+ throw Error(
345
+ `Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
151
346
 
152
- // src/core/utils/fs.ts
153
- import fs from "fs-extra";
154
- import glob from "fast-glob";
155
- async function writeFileIfDifferent(file, newContents) {
156
- const existingContents = await fs.readFile(file, "utf-8").catch(() => void 0);
157
- if (existingContents !== newContents) {
158
- await fs.writeFile(file, newContents);
347
+ ${errorContent}`
348
+ );
159
349
  }
160
350
  }
161
- async function getPublicFiles(config) {
162
- if (!await fs.exists(config.publicDir))
163
- return [];
164
- const files = await glob("**/*", { cwd: config.publicDir });
165
- return files.map(unnormalizePath);
351
+ function preventNoEntrypoints(files) {
352
+ if (files.length === 0) {
353
+ throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
354
+ }
166
355
  }
167
-
168
- // src/core/utils/building/build-entrypoints.ts
169
- import fs2 from "fs-extra";
170
- import { dirname, resolve as resolve2 } from "path";
171
- import pc from "picocolors";
172
- async function buildEntrypoints(groups, config, spinner) {
173
- const steps = [];
174
- for (let i = 0; i < groups.length; i++) {
175
- const group = groups[i];
176
- const groupNames = [group].flat().map((e) => e.name);
177
- const groupNameColored = groupNames.join(pc.dim(", "));
178
- spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
356
+ function getHtmlBaseOptions(document) {
357
+ const options = {};
358
+ const includeContent = document.querySelector("meta[name='manifest.include']")?.getAttribute("content");
359
+ if (includeContent) {
360
+ options.include = JSON5.parse(includeContent);
361
+ }
362
+ const excludeContent = document.querySelector("meta[name='manifest.exclude']")?.getAttribute("content");
363
+ if (excludeContent) {
364
+ options.exclude = JSON5.parse(excludeContent);
365
+ }
366
+ return options;
367
+ }
368
+ async function getPopupEntrypoint({
369
+ inputPath,
370
+ name,
371
+ skipped
372
+ }) {
373
+ const content = await fs3.readFile(inputPath, "utf-8");
374
+ const { document } = parseHTML(content);
375
+ const options = getHtmlBaseOptions(document);
376
+ const title = document.querySelector("title");
377
+ if (title != null)
378
+ options.defaultTitle = title.textContent ?? void 0;
379
+ const defaultIconContent = document.querySelector("meta[name='manifest.default_icon']")?.getAttribute("content");
380
+ if (defaultIconContent) {
179
381
  try {
180
- steps.push(await config.builder.build(group));
382
+ options.defaultIcon = JSON5.parse(defaultIconContent);
181
383
  } catch (err) {
182
- throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
384
+ wxt.logger.fatal(
385
+ `Failed to parse default_icon meta tag content as JSON5. content=${defaultIconContent}`,
386
+ err
387
+ );
183
388
  }
184
389
  }
185
- const publicAssets = await copyPublicDirectory(config);
186
- return { publicAssets, steps };
187
- }
188
- async function copyPublicDirectory(config) {
189
- const files = await getPublicFiles(config);
190
- if (files.length === 0)
191
- return [];
192
- const publicAssets = [];
193
- for (const file of files) {
194
- const srcPath = resolve2(config.publicDir, file);
195
- const outPath = resolve2(config.outDir, file);
196
- await fs2.ensureDir(dirname(outPath));
197
- await fs2.copyFile(srcPath, outPath);
198
- publicAssets.push({
199
- type: "asset",
200
- fileName: file
201
- });
390
+ const mv2TypeContent = document.querySelector("meta[name='manifest.type']")?.getAttribute("content");
391
+ if (mv2TypeContent) {
392
+ options.mv2Key = mv2TypeContent === "page_action" ? "page_action" : "browser_action";
202
393
  }
203
- return publicAssets;
204
- }
205
-
206
- // src/core/utils/building/generate-wxt-dir.ts
207
- import { createUnimport } from "unimport";
208
- import fs3 from "fs-extra";
209
- import { relative as relative2, resolve as resolve3 } from "path";
394
+ const browserStyleContent = document.querySelector("meta[name='manifest.browser_style']")?.getAttribute("content");
395
+ if (browserStyleContent) {
396
+ options.browserStyle = browserStyleContent === "true";
397
+ }
398
+ return {
399
+ type: "popup",
400
+ name: "popup",
401
+ options,
402
+ inputPath,
403
+ outputDir: wxt.config.outDir,
404
+ skipped
405
+ };
406
+ }
407
+ async function getOptionsEntrypoint({
408
+ inputPath,
409
+ name,
410
+ skipped
411
+ }) {
412
+ const content = await fs3.readFile(inputPath, "utf-8");
413
+ const { document } = parseHTML(content);
414
+ const options = getHtmlBaseOptions(document);
415
+ const openInTabContent = document.querySelector("meta[name='manifest.open_in_tab']")?.getAttribute("content");
416
+ if (openInTabContent) {
417
+ options.openInTab = openInTabContent === "true";
418
+ }
419
+ const chromeStyleContent = document.querySelector("meta[name='manifest.chrome_style']")?.getAttribute("content");
420
+ if (chromeStyleContent) {
421
+ options.chromeStyle = chromeStyleContent === "true";
422
+ }
423
+ const browserStyleContent = document.querySelector("meta[name='manifest.browser_style']")?.getAttribute("content");
424
+ if (browserStyleContent) {
425
+ options.browserStyle = browserStyleContent === "true";
426
+ }
427
+ return {
428
+ type: "options",
429
+ name: "options",
430
+ options,
431
+ inputPath,
432
+ outputDir: wxt.config.outDir,
433
+ skipped
434
+ };
435
+ }
436
+ async function getUnlistedPageEntrypoint({
437
+ inputPath,
438
+ name,
439
+ skipped
440
+ }) {
441
+ const content = await fs3.readFile(inputPath, "utf-8");
442
+ const { document } = parseHTML(content);
443
+ return {
444
+ type: "unlisted-page",
445
+ name: getEntrypointName(wxt.config.entrypointsDir, inputPath),
446
+ inputPath,
447
+ outputDir: wxt.config.outDir,
448
+ options: getHtmlBaseOptions(document),
449
+ skipped
450
+ };
451
+ }
452
+ async function getUnlistedScriptEntrypoint({
453
+ inputPath,
454
+ name,
455
+ skipped
456
+ }) {
457
+ const defaultExport = await importEntrypointFile(inputPath);
458
+ if (defaultExport == null) {
459
+ throw Error(
460
+ `${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
461
+ );
462
+ }
463
+ const { main: _, ...moduleOptions } = defaultExport;
464
+ const options = moduleOptions;
465
+ return {
466
+ type: "unlisted-script",
467
+ name,
468
+ inputPath,
469
+ outputDir: wxt.config.outDir,
470
+ options,
471
+ skipped
472
+ };
473
+ }
474
+ async function getBackgroundEntrypoint({
475
+ inputPath,
476
+ name,
477
+ skipped
478
+ }) {
479
+ let options = {};
480
+ if (inputPath !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
481
+ const defaultExport = await importEntrypointFile(inputPath);
482
+ if (defaultExport == null) {
483
+ throw Error(
484
+ `${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
485
+ );
486
+ }
487
+ const { main: _, ...moduleOptions } = defaultExport;
488
+ options = moduleOptions;
489
+ }
490
+ if (wxt.config.manifestVersion !== 3) {
491
+ delete options.type;
492
+ }
493
+ return {
494
+ type: "background",
495
+ name,
496
+ inputPath,
497
+ outputDir: wxt.config.outDir,
498
+ options: {
499
+ ...options,
500
+ type: resolvePerBrowserOption(options.type, wxt.config.browser),
501
+ persistent: resolvePerBrowserOption(
502
+ options.persistent,
503
+ wxt.config.browser
504
+ )
505
+ },
506
+ skipped
507
+ };
508
+ }
509
+ async function getContentScriptEntrypoint({
510
+ inputPath,
511
+ name,
512
+ skipped
513
+ }) {
514
+ const { main: _, ...options } = await importEntrypointFile(inputPath);
515
+ if (options == null) {
516
+ throw Error(
517
+ `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
518
+ );
519
+ }
520
+ return {
521
+ type: "content-script",
522
+ name,
523
+ inputPath,
524
+ outputDir: resolve3(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
525
+ options,
526
+ skipped
527
+ };
528
+ }
529
+ var PATH_GLOB_TO_TYPE_MAP = {
530
+ "sandbox.html": "sandbox",
531
+ "sandbox/index.html": "sandbox",
532
+ "*.sandbox.html": "sandbox",
533
+ "*.sandbox/index.html": "sandbox",
534
+ "bookmarks.html": "bookmarks",
535
+ "bookmarks/index.html": "bookmarks",
536
+ "history.html": "history",
537
+ "history/index.html": "history",
538
+ "newtab.html": "newtab",
539
+ "newtab/index.html": "newtab",
540
+ "sidepanel.html": "sidepanel",
541
+ "sidepanel/index.html": "sidepanel",
542
+ "*.sidepanel.html": "sidepanel",
543
+ "*.sidepanel/index.html": "sidepanel",
544
+ "devtools.html": "devtools",
545
+ "devtools/index.html": "devtools",
546
+ "background.[jt]s": "background",
547
+ "background/index.[jt]s": "background",
548
+ [VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
549
+ "content.[jt]s?(x)": "content-script",
550
+ "content/index.[jt]s?(x)": "content-script",
551
+ "*.content.[jt]s?(x)": "content-script",
552
+ "*.content/index.[jt]s?(x)": "content-script",
553
+ [`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
554
+ [`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
555
+ [`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
556
+ [`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
557
+ "popup.html": "popup",
558
+ "popup/index.html": "popup",
559
+ "options.html": "options",
560
+ "options/index.html": "options",
561
+ "*.html": "unlisted-page",
562
+ "*/index.html": "unlisted-page",
563
+ "*.[jt]s?(x)": "unlisted-script",
564
+ "*/index.[jt]s?(x)": "unlisted-script",
565
+ [`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
566
+ [`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
567
+ };
568
+ var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
569
+
570
+ // src/core/utils/building/generate-wxt-dir.ts
571
+ import { createUnimport } from "unimport";
572
+ import fs4 from "fs-extra";
573
+ import { relative as relative3, resolve as resolve4 } from "path";
210
574
 
211
575
  // src/core/utils/unimport.ts
212
576
  import { defu } from "defu";
@@ -327,23 +691,23 @@ function parseI18nMessages(messagesJson) {
327
691
  }
328
692
 
329
693
  // src/core/utils/building/generate-wxt-dir.ts
330
- async function generateTypesDir(entrypoints, config) {
331
- await fs3.ensureDir(config.typesDir);
694
+ async function generateTypesDir(entrypoints) {
695
+ await fs4.ensureDir(wxt.config.typesDir);
332
696
  const references = [];
333
- const imports = getUnimportOptions(config);
697
+ const imports = getUnimportOptions(wxt.config);
334
698
  if (imports !== false) {
335
- references.push(await writeImportsDeclarationFile(config, imports));
699
+ references.push(await writeImportsDeclarationFile(imports));
336
700
  }
337
- references.push(await writePathsDeclarationFile(entrypoints, config));
338
- references.push(await writeI18nDeclarationFile(config));
339
- references.push(await writeGlobalsDeclarationFile(config));
340
- const mainReference = await writeMainDeclarationFile(references, config);
341
- await writeTsConfigFile(mainReference, config);
701
+ references.push(await writePathsDeclarationFile(entrypoints));
702
+ references.push(await writeI18nDeclarationFile());
703
+ references.push(await writeGlobalsDeclarationFile());
704
+ const mainReference = await writeMainDeclarationFile(references);
705
+ await writeTsConfigFile(mainReference);
342
706
  }
343
- async function writeImportsDeclarationFile(config, unimportOptions) {
344
- const filePath = resolve3(config.typesDir, "imports.d.ts");
707
+ async function writeImportsDeclarationFile(unimportOptions) {
708
+ const filePath = resolve4(wxt.config.typesDir, "imports.d.ts");
345
709
  const unimport2 = createUnimport(unimportOptions);
346
- await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
710
+ await unimport2.scanImportsFromDir(void 0, { cwd: wxt.config.srcDir });
347
711
  await writeFileIfDifferent(
348
712
  filePath,
349
713
  ["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
@@ -352,15 +716,15 @@ async function writeImportsDeclarationFile(config, unimportOptions) {
352
716
  );
353
717
  return filePath;
354
718
  }
355
- async function writePathsDeclarationFile(entrypoints, config) {
356
- const filePath = resolve3(config.typesDir, "paths.d.ts");
719
+ async function writePathsDeclarationFile(entrypoints) {
720
+ const filePath = resolve4(wxt.config.typesDir, "paths.d.ts");
357
721
  const unions = entrypoints.map(
358
722
  (entry) => getEntrypointBundlePath(
359
723
  entry,
360
- config.outDir,
724
+ wxt.config.outDir,
361
725
  entry.inputPath.endsWith(".html") ? ".html" : ".js"
362
726
  )
363
- ).concat(await getPublicFiles(config)).map(normalizePath).map((path6) => ` | "/${path6}"`).sort().join("\n");
727
+ ).concat(await getPublicFiles()).map(normalizePath).map((path6) => ` | "/${path6}"`).sort().join("\n");
364
728
  const template = `// Generated by wxt
365
729
  import "wxt/browser";
366
730
 
@@ -380,9 +744,9 @@ declare module "wxt/browser" {
380
744
  );
381
745
  return filePath;
382
746
  }
383
- async function writeI18nDeclarationFile(config) {
384
- const filePath = resolve3(config.typesDir, "i18n.d.ts");
385
- const defaultLocale = config.manifest.default_locale;
747
+ async function writeI18nDeclarationFile() {
748
+ const filePath = resolve4(wxt.config.typesDir, "i18n.d.ts");
749
+ const defaultLocale = wxt.config.manifest.default_locale;
386
750
  const template = `// Generated by wxt
387
751
  import "wxt/browser";
388
752
 
@@ -405,12 +769,12 @@ declare module "wxt/browser" {
405
769
  let messages;
406
770
  if (defaultLocale) {
407
771
  const defaultLocalePath = path2.resolve(
408
- config.publicDir,
772
+ wxt.config.publicDir,
409
773
  "_locales",
410
774
  defaultLocale,
411
775
  "messages.json"
412
776
  );
413
- const content = JSON.parse(await fs3.readFile(defaultLocalePath, "utf-8"));
777
+ const content = JSON.parse(await fs4.readFile(defaultLocalePath, "utf-8"));
414
778
  messages = parseI18nMessages(content);
415
779
  } else {
416
780
  messages = parseI18nMessages({});
@@ -433,9 +797,9 @@ declare module "wxt/browser" {
433
797
  );
434
798
  return filePath;
435
799
  }
436
- async function writeGlobalsDeclarationFile(config) {
437
- const filePath = resolve3(config.typesDir, "globals.d.ts");
438
- const globals2 = [...getGlobals(config), ...getEntrypointGlobals("")];
800
+ async function writeGlobalsDeclarationFile() {
801
+ const filePath = resolve4(wxt.config.typesDir, "globals.d.ts");
802
+ const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
439
803
  await writeFileIfDifferent(
440
804
  filePath,
441
805
  [
@@ -451,25 +815,25 @@ async function writeGlobalsDeclarationFile(config) {
451
815
  );
452
816
  return filePath;
453
817
  }
454
- async function writeMainDeclarationFile(references, config) {
455
- const dir = config.wxtDir;
456
- const filePath = resolve3(dir, "wxt.d.ts");
818
+ async function writeMainDeclarationFile(references) {
819
+ const dir = wxt.config.wxtDir;
820
+ const filePath = resolve4(dir, "wxt.d.ts");
457
821
  await writeFileIfDifferent(
458
822
  filePath,
459
823
  [
460
824
  "// Generated by wxt",
461
825
  `/// <reference types="wxt/vite-builder-env" />`,
462
826
  ...references.map(
463
- (ref) => `/// <reference types="./${normalizePath(relative2(dir, ref))}" />`
827
+ (ref) => `/// <reference types="./${normalizePath(relative3(dir, ref))}" />`
464
828
  )
465
829
  ].join("\n") + "\n"
466
830
  );
467
831
  return filePath;
468
832
  }
469
- async function writeTsConfigFile(mainReference, config) {
470
- const dir = config.wxtDir;
471
- const getTsconfigPath = (path6) => normalizePath(relative2(dir, path6));
472
- const paths = Object.entries(config.alias).flatMap(([alias, absolutePath]) => {
833
+ async function writeTsConfigFile(mainReference) {
834
+ const dir = wxt.config.wxtDir;
835
+ const getTsconfigPath = (path6) => normalizePath(relative3(dir, path6));
836
+ const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
473
837
  const aliasPath = getTsconfigPath(absolutePath);
474
838
  return [
475
839
  ` "${alias}": ["${aliasPath}"]`,
@@ -477,7 +841,7 @@ async function writeTsConfigFile(mainReference, config) {
477
841
  ];
478
842
  }).join(",\n");
479
843
  await writeFileIfDifferent(
480
- resolve3(dir, "tsconfig.json"),
844
+ resolve4(dir, "tsconfig.json"),
481
845
  `{
482
846
  "compilerOptions": {
483
847
  "target": "ESNext",
@@ -494,23 +858,23 @@ ${paths}
494
858
  }
495
859
  },
496
860
  "include": [
497
- "${getTsconfigPath(config.root)}/**/*",
861
+ "${getTsconfigPath(wxt.config.root)}/**/*",
498
862
  "./${getTsconfigPath(mainReference)}"
499
863
  ],
500
- "exclude": ["${getTsconfigPath(config.outBaseDir)}"]
864
+ "exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
501
865
  }`
502
866
  );
503
867
  }
504
868
 
505
- // src/core/utils/building/get-internal-config.ts
869
+ // src/core/utils/building/resolve-config.ts
506
870
  import { loadConfig } from "c12";
507
871
  import path4 from "node:path";
508
872
 
509
873
  // src/core/utils/cache.ts
510
- import fs4, { ensureDir } from "fs-extra";
511
- import { dirname as dirname2, resolve as resolve4 } from "path";
874
+ import fs5, { ensureDir } from "fs-extra";
875
+ import { dirname as dirname2, resolve as resolve5 } from "path";
512
876
  function createFsCache(wxtDir) {
513
- const getPath = (key) => resolve4(wxtDir, "cache", encodeURIComponent(key));
877
+ const getPath = (key) => resolve5(wxtDir, "cache", encodeURIComponent(key));
514
878
  return {
515
879
  async set(key, value) {
516
880
  const path6 = getPath(key);
@@ -520,7 +884,7 @@ function createFsCache(wxtDir) {
520
884
  async get(key) {
521
885
  const path6 = getPath(key);
522
886
  try {
523
- return await fs4.readFile(path6, "utf-8");
887
+ return await fs5.readFile(path6, "utf-8");
524
888
  } catch {
525
889
  return void 0;
526
890
  }
@@ -528,16 +892,16 @@ function createFsCache(wxtDir) {
528
892
  };
529
893
  }
530
894
 
531
- // src/core/utils/building/get-internal-config.ts
895
+ // src/core/utils/building/resolve-config.ts
532
896
  import consola, { LogLevels } from "consola";
533
897
 
534
898
  // src/core/builders/vite/plugins/devHtmlPrerender.ts
535
- import { parseHTML } from "linkedom";
536
- import { dirname as dirname3, relative as relative3, resolve as resolve5 } from "node:path";
899
+ import { parseHTML as parseHTML2 } from "linkedom";
900
+ import { dirname as dirname3, relative as relative4, resolve as resolve6 } from "node:path";
537
901
  var reactRefreshPreamble = "";
538
902
  function devHtmlPrerender(config) {
539
903
  const htmlReloadId = "@wxt/reload-html";
540
- const resolvedHtmlReloadId = resolve5(
904
+ const resolvedHtmlReloadId = resolve6(
541
905
  config.root,
542
906
  "node_modules/wxt/dist/virtual/reload-html.js"
543
907
  );
@@ -562,7 +926,7 @@ function devHtmlPrerender(config) {
562
926
  const server = config.server;
563
927
  if (config.command !== "serve" || server == null || !id.endsWith(".html"))
564
928
  return;
565
- const { document } = parseHTML(code);
929
+ const { document } = parseHTML2(code);
566
930
  const _pointToDevServer = (querySelector, attr) => pointToDevServer(config, server, id, document, querySelector, attr);
567
931
  _pointToDevServer("script[type=module]", "src");
568
932
  _pointToDevServer("link[rel=stylesheet]", "href");
@@ -585,7 +949,7 @@ function devHtmlPrerender(config) {
585
949
  const name = getEntrypointName(config.entrypointsDir, ctx.filename);
586
950
  const url = `${server.origin}/${name}.html`;
587
951
  const serverHtml = await server.transformHtml(url, html, originalUrl);
588
- const { document } = parseHTML(serverHtml);
952
+ const { document } = parseHTML2(serverHtml);
589
953
  const reactRefreshScript = Array.from(
590
954
  document.querySelectorAll("script[type=module]")
591
955
  ).find((script) => script.innerHTML.includes("@react-refresh"));
@@ -642,16 +1006,16 @@ function pointToDevServer(config, server, id, document, querySelector, attr) {
642
1006
  );
643
1007
  if (matchingAlias) {
644
1008
  const [alias, replacement] = matchingAlias;
645
- resolvedAbsolutePath = resolve5(
1009
+ resolvedAbsolutePath = resolve6(
646
1010
  config.root,
647
1011
  src.replace(alias, replacement)
648
1012
  );
649
1013
  } else {
650
- resolvedAbsolutePath = resolve5(dirname3(id), src);
1014
+ resolvedAbsolutePath = resolve6(dirname3(id), src);
651
1015
  }
652
1016
  if (resolvedAbsolutePath) {
653
1017
  const relativePath = normalizePath(
654
- relative3(config.root, resolvedAbsolutePath)
1018
+ relative4(config.root, resolvedAbsolutePath)
655
1019
  );
656
1020
  if (relativePath.startsWith(".")) {
657
1021
  let path6 = normalizePath(resolvedAbsolutePath);
@@ -771,8 +1135,8 @@ function download(config) {
771
1135
  }
772
1136
 
773
1137
  // src/core/builders/vite/plugins/multipageMove.ts
774
- import { dirname as dirname4, extname, resolve as resolve6, join } from "node:path";
775
- import fs5, { ensureDir as ensureDir2 } from "fs-extra";
1138
+ import { dirname as dirname4, extname, resolve as resolve7, join } from "node:path";
1139
+ import fs6, { ensureDir as ensureDir2 } from "fs-extra";
776
1140
  function multipageMove(entrypoints, config) {
777
1141
  return {
778
1142
  name: "wxt:multipage-move",
@@ -799,10 +1163,10 @@ function multipageMove(entrypoints, config) {
799
1163
  );
800
1164
  continue;
801
1165
  }
802
- const oldAbsPath = resolve6(config.outDir, oldBundlePath);
803
- const newAbsPath = resolve6(config.outDir, newBundlePath);
1166
+ const oldAbsPath = resolve7(config.outDir, oldBundlePath);
1167
+ const newAbsPath = resolve7(config.outDir, newBundlePath);
804
1168
  await ensureDir2(dirname4(newAbsPath));
805
- await fs5.move(oldAbsPath, newAbsPath, { overwrite: true });
1169
+ await fs6.move(oldAbsPath, newAbsPath, { overwrite: true });
806
1170
  const renamedChunk = {
807
1171
  ...bundle[oldBundlePath],
808
1172
  fileName: newBundlePath
@@ -815,16 +1179,16 @@ function multipageMove(entrypoints, config) {
815
1179
  };
816
1180
  }
817
1181
  async function removeEmptyDirs(dir) {
818
- const files = await fs5.readdir(dir);
1182
+ const files = await fs6.readdir(dir);
819
1183
  for (const file of files) {
820
1184
  const filePath = join(dir, file);
821
- const stats = await fs5.stat(filePath);
1185
+ const stats = await fs6.stat(filePath);
822
1186
  if (stats.isDirectory()) {
823
1187
  await removeEmptyDirs(filePath);
824
1188
  }
825
1189
  }
826
1190
  try {
827
- await fs5.rmdir(dir);
1191
+ await fs6.rmdir(dir);
828
1192
  } catch {
829
1193
  }
830
1194
  }
@@ -865,8 +1229,8 @@ function unimport(config) {
865
1229
  }
866
1230
 
867
1231
  // src/core/builders/vite/plugins/virtualEntrypoint.ts
868
- import fs6 from "fs-extra";
869
- import { resolve as resolve7 } from "path";
1232
+ import fs7 from "fs-extra";
1233
+ import { resolve as resolve8 } from "path";
870
1234
  function virtualEntrypoint(type, config) {
871
1235
  const virtualId = `virtual:wxt-${type}?`;
872
1236
  const resolvedVirtualId = `\0${virtualId}`;
@@ -883,8 +1247,8 @@ function virtualEntrypoint(type, config) {
883
1247
  if (!id.startsWith(resolvedVirtualId))
884
1248
  return;
885
1249
  const inputPath = id.replace(resolvedVirtualId, "");
886
- const template = await fs6.readFile(
887
- resolve7(
1250
+ const template = await fs7.readFile(
1251
+ resolve8(
888
1252
  config.root,
889
1253
  `node_modules/wxt/dist/virtual/${type}-entrypoint.js`
890
1254
  ),
@@ -909,9 +1273,6 @@ function tsconfigPaths(config) {
909
1273
  };
910
1274
  }
911
1275
 
912
- // src/core/utils/constants.ts
913
- var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
914
-
915
1276
  // src/core/builders/vite/plugins/noopBackground.ts
916
1277
  function noopBackground() {
917
1278
  const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
@@ -1048,6 +1409,21 @@ function entrypointGroupGlobals(entrypointGroup) {
1048
1409
  };
1049
1410
  }
1050
1411
 
1412
+ // src/core/builders/vite/plugins/defineImportMeta.ts
1413
+ function defineImportMeta() {
1414
+ return {
1415
+ name: "wxt:define",
1416
+ config() {
1417
+ return {
1418
+ define: {
1419
+ // This works for all extension contexts, including background service worker
1420
+ "import.meta.url": "self.location.href"
1421
+ }
1422
+ };
1423
+ }
1424
+ };
1425
+ }
1426
+
1051
1427
  // src/core/builders/vite/index.ts
1052
1428
  async function createViteBuilder(inlineConfig, userConfig, wxtConfig) {
1053
1429
  const vite = await import("vite");
@@ -1084,7 +1460,8 @@ async function createViteBuilder(inlineConfig, userConfig, wxtConfig) {
1084
1460
  tsconfigPaths(wxtConfig),
1085
1461
  noopBackground(),
1086
1462
  globals(wxtConfig),
1087
- excludeBrowserPolyfill(wxtConfig)
1463
+ excludeBrowserPolyfill(wxtConfig),
1464
+ defineImportMeta()
1088
1465
  );
1089
1466
  if (wxtConfig.analysis.enabled) {
1090
1467
  config.plugins.push(bundleAnalysis());
@@ -1262,9 +1639,9 @@ function getRollupEntry(entrypoint) {
1262
1639
  return virtualEntrypointType ? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}` : entrypoint.inputPath;
1263
1640
  }
1264
1641
 
1265
- // src/core/utils/building/get-internal-config.ts
1642
+ // src/core/utils/building/resolve-config.ts
1266
1643
  import defu2 from "defu";
1267
- async function getInternalConfig(inlineConfig, command, server) {
1644
+ async function resolveConfig(inlineConfig, command, server) {
1268
1645
  let userConfig = {};
1269
1646
  let userConfigMetadata;
1270
1647
  if (inlineConfig.configFile !== false) {
@@ -1358,7 +1735,8 @@ async function getInternalConfig(inlineConfig, command, server) {
1358
1735
  server,
1359
1736
  dev: {
1360
1737
  reloadCommand
1361
- }
1738
+ },
1739
+ hooks: mergedConfig.hooks ?? {}
1362
1740
  };
1363
1741
  const builder = await createViteBuilder(
1364
1742
  inlineConfig,
@@ -1395,6 +1773,10 @@ function mergeInlineConfig(inlineConfig, userConfig) {
1395
1773
  inlineConfig.zip ?? {},
1396
1774
  userConfig.zip ?? {}
1397
1775
  );
1776
+ const hooks = defu2(
1777
+ inlineConfig.hooks ?? {},
1778
+ userConfig.hooks ?? {}
1779
+ );
1398
1780
  return {
1399
1781
  root: inlineConfig.root ?? userConfig.root,
1400
1782
  browser: inlineConfig.browser ?? userConfig.browser,
@@ -1429,7 +1811,8 @@ function mergeInlineConfig(inlineConfig, userConfig) {
1429
1811
  dev: {
1430
1812
  ...userConfig.dev,
1431
1813
  ...inlineConfig.dev
1432
- }
1814
+ },
1815
+ hooks
1433
1816
  };
1434
1817
  }
1435
1818
  function resolveInternalZipConfig(root, mergedConfig) {
@@ -1497,8 +1880,8 @@ var ENTRY_TYPE_TO_GROUP_MAP = {
1497
1880
  // src/core/utils/building/import-entrypoint.ts
1498
1881
  import createJITI from "jiti";
1499
1882
  import { createUnimport as createUnimport3 } from "unimport";
1500
- import fs7 from "fs-extra";
1501
- import { relative as relative4, resolve as resolve8 } from "node:path";
1883
+ import fs8 from "fs-extra";
1884
+ import { relative as relative5, resolve as resolve9 } from "node:path";
1502
1885
 
1503
1886
  // src/core/utils/strings.ts
1504
1887
  function kebabCaseAlphanumeric(str) {
@@ -1520,30 +1903,30 @@ ${noImports}`;
1520
1903
  // src/core/utils/building/import-entrypoint.ts
1521
1904
  import { transformSync } from "esbuild";
1522
1905
  import { fileURLToPath } from "node:url";
1523
- async function importEntrypointFile(path6, config) {
1524
- config.logger.debug("Loading file metadata:", path6);
1906
+ async function importEntrypointFile(path6) {
1907
+ wxt.logger.debug("Loading file metadata:", path6);
1525
1908
  const normalPath = normalizePath(path6);
1526
1909
  const unimport2 = createUnimport3({
1527
- ...getUnimportOptions(config),
1910
+ ...getUnimportOptions(wxt.config),
1528
1911
  // Only allow specific imports, not all from the project
1529
1912
  dirs: []
1530
1913
  });
1531
1914
  await unimport2.init();
1532
- const text = await fs7.readFile(path6, "utf-8");
1915
+ const text = await fs8.readFile(path6, "utf-8");
1533
1916
  const textNoImports = removeProjectImportStatements(text);
1534
1917
  const { code } = await unimport2.injectImports(textNoImports);
1535
- config.logger.debug(
1918
+ wxt.logger.debug(
1536
1919
  ["Text:", text, "No imports:", textNoImports, "Code:", code].join("\n")
1537
1920
  );
1538
1921
  const jiti = createJITI(
1539
1922
  typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url),
1540
1923
  {
1541
1924
  cache: false,
1542
- debug: config.debug,
1925
+ debug: wxt.config.debug,
1543
1926
  esmResolve: true,
1544
1927
  alias: {
1545
- "webextension-polyfill": resolve8(
1546
- config.root,
1928
+ "webextension-polyfill": resolve9(
1929
+ wxt.config.root,
1547
1930
  "node_modules/wxt/dist/virtual/mock-browser.js"
1548
1931
  )
1549
1932
  },
@@ -1575,7 +1958,7 @@ async function importEntrypointFile(path6, config) {
1575
1958
  const res = await jiti(path6);
1576
1959
  return res.default;
1577
1960
  } catch (err) {
1578
- const filePath = relative4(config.root, path6);
1961
+ const filePath = relative5(wxt.config.root, path6);
1579
1962
  if (err instanceof ReferenceError) {
1580
1963
  const variableName = err.message.replace(" is not defined", "");
1581
1964
  throw Error(
@@ -1583,7 +1966,7 @@ async function importEntrypointFile(path6, config) {
1583
1966
  { cause: err }
1584
1967
  );
1585
1968
  } else {
1586
- config.logger.error(err);
1969
+ wxt.logger.error(err);
1587
1970
  throw Error(`Failed to load entrypoint: ${filePath}`, { cause: err });
1588
1971
  }
1589
1972
  }
@@ -1598,16 +1981,16 @@ function getEsbuildOptions(opts) {
1598
1981
  }
1599
1982
 
1600
1983
  // src/core/utils/building/internal-build.ts
1601
- import pc4 from "picocolors";
1602
- import fs11 from "fs-extra";
1984
+ import pc5 from "picocolors";
1985
+ import fs12 from "fs-extra";
1603
1986
 
1604
1987
  // src/core/utils/log/printBuildSummary.ts
1605
- import { resolve as resolve9 } from "path";
1988
+ import { resolve as resolve10 } from "path";
1606
1989
 
1607
1990
  // src/core/utils/log/printFileList.ts
1608
1991
  import path5 from "node:path";
1609
- import pc2 from "picocolors";
1610
- import fs8 from "fs-extra";
1992
+ import pc3 from "picocolors";
1993
+ import fs9 from "fs-extra";
1611
1994
  import { filesize } from "filesize";
1612
1995
 
1613
1996
  // src/core/utils/log/printTable.ts
@@ -1648,36 +2031,36 @@ async function printFileList(log, header, baseDir, files) {
1648
2031
  ];
1649
2032
  const prefix = i === files.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
1650
2033
  const color = getChunkColor(file);
1651
- const stats = await fs8.lstat(file);
2034
+ const stats = await fs9.lstat(file);
1652
2035
  totalSize += stats.size;
1653
2036
  const size = String(filesize(stats.size));
1654
2037
  return [
1655
- `${pc2.gray(prefix)} ${pc2.dim(parts[0])}${color(parts[1])}`,
1656
- pc2.dim(size)
2038
+ `${pc3.gray(prefix)} ${pc3.dim(parts[0])}${color(parts[1])}`,
2039
+ pc3.dim(size)
1657
2040
  ];
1658
2041
  })
1659
2042
  );
1660
- fileRows.push([`${pc2.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`]);
2043
+ fileRows.push([`${pc3.cyan("\u03A3 Total size:")} ${String(filesize(totalSize))}`]);
1661
2044
  printTable(log, header, fileRows);
1662
2045
  }
1663
- var DEFAULT_COLOR = pc2.blue;
2046
+ var DEFAULT_COLOR = pc3.blue;
1664
2047
  var CHUNK_COLORS = {
1665
- ".js.map": pc2.gray,
1666
- ".cjs.map": pc2.gray,
1667
- ".mjs.map": pc2.gray,
1668
- ".html": pc2.green,
1669
- ".css": pc2.magenta,
1670
- ".js": pc2.cyan,
1671
- ".cjs": pc2.cyan,
1672
- ".mjs": pc2.cyan,
1673
- ".zip": pc2.yellow
2048
+ ".js.map": pc3.gray,
2049
+ ".cjs.map": pc3.gray,
2050
+ ".mjs.map": pc3.gray,
2051
+ ".html": pc3.green,
2052
+ ".css": pc3.magenta,
2053
+ ".js": pc3.cyan,
2054
+ ".cjs": pc3.cyan,
2055
+ ".mjs": pc3.cyan,
2056
+ ".zip": pc3.yellow
1674
2057
  };
1675
2058
  function getChunkColor(filename) {
1676
2059
  return Object.entries(CHUNK_COLORS).find(([key]) => filename.endsWith(key))?.[1] ?? DEFAULT_COLOR;
1677
2060
  }
1678
2061
 
1679
2062
  // src/core/utils/log/printBuildSummary.ts
1680
- async function printBuildSummary(log, header, output, config) {
2063
+ async function printBuildSummary(log, header, output) {
1681
2064
  const chunks = [
1682
2065
  ...output.steps.flatMap((step) => step.chunks),
1683
2066
  ...output.publicAssets
@@ -1689,8 +2072,10 @@ async function printBuildSummary(log, header, output, config) {
1689
2072
  return diff;
1690
2073
  return l.fileName.localeCompare(r.fileName);
1691
2074
  });
1692
- const files = chunks.map((chunk) => resolve9(config.outDir, chunk.fileName));
1693
- await printFileList(log, header, config.outDir, files);
2075
+ const files = chunks.map(
2076
+ (chunk) => resolve10(wxt.config.outDir, chunk.fileName)
2077
+ );
2078
+ await printFileList(log, header, wxt.config.outDir, files);
1694
2079
  }
1695
2080
  var DEFAULT_SORT_WEIGHT = 100;
1696
2081
  var CHUNK_SORT_WEIGHTS = {
@@ -1707,15 +2092,15 @@ function getChunkSortWeight(filename) {
1707
2092
  }
1708
2093
 
1709
2094
  // src/core/utils/log/printHeader.ts
1710
- import pc3 from "picocolors";
2095
+ import pc4 from "picocolors";
1711
2096
  import { consola as consola2 } from "consola";
1712
2097
 
1713
2098
  // src/core/utils/building/internal-build.ts
1714
- import glob2 from "fast-glob";
2099
+ import glob3 from "fast-glob";
1715
2100
 
1716
2101
  // src/core/utils/manifest.ts
1717
- import fs10 from "fs-extra";
1718
- import { resolve as resolve11 } from "path";
2102
+ import fs11 from "fs-extra";
2103
+ import { resolve as resolve12 } from "path";
1719
2104
 
1720
2105
  // src/core/utils/content-security-policy.ts
1721
2106
  var ContentSecurityPolicy = class _ContentSecurityPolicy {
@@ -1761,8 +2146,8 @@ var ContentSecurityPolicy = class _ContentSecurityPolicy {
1761
2146
  };
1762
2147
 
1763
2148
  // src/core/utils/content-scripts.ts
1764
- function hashContentScriptOptions(options, config) {
1765
- const simplifiedOptions = mapWxtOptionsToContentScript(options, config);
2149
+ function hashContentScriptOptions(options) {
2150
+ const simplifiedOptions = mapWxtOptionsToContentScript(options);
1766
2151
  Object.keys(simplifiedOptions).forEach((key) => {
1767
2152
  if (simplifiedOptions[key] == null)
1768
2153
  delete simplifiedOptions[key];
@@ -1788,45 +2173,45 @@ function hashContentScriptOptions(options, config) {
1788
2173
  }).sort((l, r) => l[0].localeCompare(r[0]))
1789
2174
  );
1790
2175
  }
1791
- function mapWxtOptionsToContentScript(options, config) {
2176
+ function mapWxtOptionsToContentScript(options) {
1792
2177
  return {
1793
- matches: resolvePerBrowserOption(options.matches, config.browser),
1794
- all_frames: resolvePerBrowserOption(options.allFrames, config.browser),
2178
+ matches: resolvePerBrowserOption(options.matches, wxt.config.browser),
2179
+ all_frames: resolvePerBrowserOption(options.allFrames, wxt.config.browser),
1795
2180
  match_about_blank: resolvePerBrowserOption(
1796
2181
  options.matchAboutBlank,
1797
- config.browser
2182
+ wxt.config.browser
1798
2183
  ),
1799
2184
  exclude_globs: resolvePerBrowserOption(
1800
2185
  options.excludeGlobs,
1801
- config.browser
2186
+ wxt.config.browser
1802
2187
  ),
1803
2188
  exclude_matches: resolvePerBrowserOption(
1804
2189
  options.excludeMatches,
1805
- config.browser
2190
+ wxt.config.browser
1806
2191
  ),
1807
2192
  include_globs: resolvePerBrowserOption(
1808
2193
  options.includeGlobs,
1809
- config.browser
2194
+ wxt.config.browser
1810
2195
  ),
1811
- run_at: resolvePerBrowserOption(options.runAt, config.browser),
2196
+ run_at: resolvePerBrowserOption(options.runAt, wxt.config.browser),
1812
2197
  // @ts-expect-error: untyped chrome options
1813
2198
  match_origin_as_fallback: resolvePerBrowserOption(
1814
2199
  options.matchOriginAsFallback,
1815
- config.browser
2200
+ wxt.config.browser
1816
2201
  ),
1817
2202
  world: options.world
1818
2203
  };
1819
2204
  }
1820
2205
 
1821
2206
  // src/core/utils/package.ts
1822
- import { resolve as resolve10 } from "node:path";
1823
- import fs9 from "fs-extra";
1824
- async function getPackageJson(config) {
1825
- const file = resolve10(config.root, "package.json");
2207
+ import { resolve as resolve11 } from "node:path";
2208
+ import fs10 from "fs-extra";
2209
+ async function getPackageJson() {
2210
+ const file = resolve11(wxt.config.root, "package.json");
1826
2211
  try {
1827
- return await fs9.readJson(file);
2212
+ return await fs10.readJson(file);
1828
2213
  } catch (err) {
1829
- config.logger.debug(
2214
+ wxt.logger.debug(
1830
2215
  `Failed to read package.json at: ${file}. Returning undefined.`
1831
2216
  );
1832
2217
  return {};
@@ -1836,40 +2221,40 @@ async function getPackageJson(config) {
1836
2221
  // src/core/utils/manifest.ts
1837
2222
  import { produce } from "immer";
1838
2223
  import defu3 from "defu";
1839
- async function writeManifest(manifest, output, config) {
1840
- const str = config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
1841
- await fs10.ensureDir(config.outDir);
1842
- await writeFileIfDifferent(resolve11(config.outDir, "manifest.json"), str);
2224
+ async function writeManifest(manifest, output) {
2225
+ const str = wxt.config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
2226
+ await fs11.ensureDir(wxt.config.outDir);
2227
+ await writeFileIfDifferent(resolve12(wxt.config.outDir, "manifest.json"), str);
1843
2228
  output.publicAssets.unshift({
1844
2229
  type: "asset",
1845
2230
  fileName: "manifest.json"
1846
2231
  });
1847
2232
  }
1848
- async function generateManifest(entrypoints, buildOutput, config) {
2233
+ async function generateManifest(entrypoints, buildOutput) {
1849
2234
  const warnings = [];
1850
- const pkg = await getPackageJson(config);
1851
- let versionName = config.manifest.version_name ?? config.manifest.version ?? pkg?.version;
2235
+ const pkg = await getPackageJson();
2236
+ let versionName = wxt.config.manifest.version_name ?? wxt.config.manifest.version ?? pkg?.version;
1852
2237
  if (versionName == null) {
1853
2238
  versionName = "0.0.0";
1854
- config.logger.warn(
2239
+ wxt.logger.warn(
1855
2240
  'Extension version not found, defaulting to "0.0.0". Add a version to your `package.json` or `wxt.config.ts` file. For more details, see: https://wxt.dev/guide/manifest.html#version-and-version-name'
1856
2241
  );
1857
2242
  }
1858
- const version2 = config.manifest.version ?? simplifyVersion(versionName);
2243
+ const version2 = wxt.config.manifest.version ?? simplifyVersion(versionName);
1859
2244
  const baseManifest = {
1860
- manifest_version: config.manifestVersion,
2245
+ manifest_version: wxt.config.manifestVersion,
1861
2246
  name: pkg?.name,
1862
2247
  description: pkg?.description,
1863
2248
  version: version2,
1864
2249
  short_name: pkg?.shortName,
1865
2250
  icons: discoverIcons(buildOutput)
1866
2251
  };
1867
- const userManifest = config.manifest;
2252
+ const userManifest = wxt.config.manifest;
1868
2253
  const manifest = defu3(
1869
2254
  userManifest,
1870
2255
  baseManifest
1871
2256
  );
1872
- if (config.command === "serve" && config.dev.reloadCommand) {
2257
+ if (wxt.config.command === "serve" && wxt.config.dev.reloadCommand) {
1873
2258
  if (manifest.commands && Object.keys(manifest.commands).length >= 4) {
1874
2259
  warnings.push([
1875
2260
  "Extension already has 4 registered commands, WXT's reload command is disabled"
@@ -1879,20 +2264,21 @@ async function generateManifest(entrypoints, buildOutput, config) {
1879
2264
  manifest.commands["wxt:reload-extension"] = {
1880
2265
  description: "Reload the extension during development",
1881
2266
  suggested_key: {
1882
- default: config.dev.reloadCommand
2267
+ default: wxt.config.dev.reloadCommand
1883
2268
  }
1884
2269
  };
1885
2270
  }
1886
2271
  }
1887
2272
  manifest.version = version2;
1888
2273
  manifest.version_name = // Firefox doesn't support version_name
1889
- config.browser === "firefox" || versionName === version2 ? void 0 : versionName;
1890
- addEntrypoints(manifest, entrypoints, buildOutput, config);
1891
- if (config.command === "serve")
1892
- addDevModeCsp(manifest, config);
1893
- if (config.command === "serve")
1894
- addDevModePermissions(manifest, config);
1895
- const finalManifest = produce(manifest, config.transformManifest);
2274
+ wxt.config.browser === "firefox" || versionName === version2 ? void 0 : versionName;
2275
+ addEntrypoints(manifest, entrypoints, buildOutput);
2276
+ if (wxt.config.command === "serve")
2277
+ addDevModeCsp(manifest);
2278
+ if (wxt.config.command === "serve")
2279
+ addDevModePermissions(manifest);
2280
+ const finalManifest = produce(manifest, wxt.config.transformManifest);
2281
+ await wxt.hooks.callHook("build:manifestGenerated", wxt, finalManifest);
1896
2282
  if (finalManifest.name == null)
1897
2283
  throw Error(
1898
2284
  "Manifest 'name' is missing. Either:\n1. Set the name in your <rootDir>/package.json\n2. Set a name via the manifest option in your wxt.config.ts"
@@ -1917,7 +2303,7 @@ function simplifyVersion(versionName) {
1917
2303
  );
1918
2304
  return version2;
1919
2305
  }
1920
- function addEntrypoints(manifest, entrypoints, buildOutput, config) {
2306
+ function addEntrypoints(manifest, entrypoints, buildOutput) {
1921
2307
  const entriesByType = entrypoints.reduce((map, entrypoint) => {
1922
2308
  map[entrypoint.type] ??= [];
1923
2309
  map[entrypoint.type]?.push(entrypoint);
@@ -1934,13 +2320,17 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
1934
2320
  const sandboxes = entriesByType["sandbox"];
1935
2321
  const sidepanels = entriesByType["sidepanel"];
1936
2322
  if (background) {
1937
- const script = getEntrypointBundlePath(background, config.outDir, ".js");
1938
- if (config.browser === "firefox" && config.manifestVersion === 3) {
2323
+ const script = getEntrypointBundlePath(
2324
+ background,
2325
+ wxt.config.outDir,
2326
+ ".js"
2327
+ );
2328
+ if (wxt.config.browser === "firefox" && wxt.config.manifestVersion === 3) {
1939
2329
  manifest.background = {
1940
2330
  type: background.options.type,
1941
2331
  scripts: [script]
1942
2332
  };
1943
- } else if (config.manifestVersion === 3) {
2333
+ } else if (wxt.config.manifestVersion === 3) {
1944
2334
  manifest.background = {
1945
2335
  type: background.options.type,
1946
2336
  service_worker: script
@@ -1953,29 +2343,29 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
1953
2343
  }
1954
2344
  }
1955
2345
  if (bookmarks) {
1956
- if (config.browser === "firefox") {
1957
- config.logger.warn(
2346
+ if (wxt.config.browser === "firefox") {
2347
+ wxt.logger.warn(
1958
2348
  "Bookmarks are not supported by Firefox. chrome_url_overrides.bookmarks was not added to the manifest"
1959
2349
  );
1960
2350
  } else {
1961
2351
  manifest.chrome_url_overrides ??= {};
1962
2352
  manifest.chrome_url_overrides.bookmarks = getEntrypointBundlePath(
1963
2353
  bookmarks,
1964
- config.outDir,
2354
+ wxt.config.outDir,
1965
2355
  ".html"
1966
2356
  );
1967
2357
  }
1968
2358
  }
1969
2359
  if (history) {
1970
- if (config.browser === "firefox") {
1971
- config.logger.warn(
2360
+ if (wxt.config.browser === "firefox") {
2361
+ wxt.logger.warn(
1972
2362
  "Bookmarks are not supported by Firefox. chrome_url_overrides.history was not added to the manifest"
1973
2363
  );
1974
2364
  } else {
1975
2365
  manifest.chrome_url_overrides ??= {};
1976
2366
  manifest.chrome_url_overrides.history = getEntrypointBundlePath(
1977
2367
  history,
1978
- config.outDir,
2368
+ wxt.config.outDir,
1979
2369
  ".html"
1980
2370
  );
1981
2371
  }
@@ -1984,14 +2374,14 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
1984
2374
  manifest.chrome_url_overrides ??= {};
1985
2375
  manifest.chrome_url_overrides.newtab = getEntrypointBundlePath(
1986
2376
  newtab,
1987
- config.outDir,
2377
+ wxt.config.outDir,
1988
2378
  ".html"
1989
2379
  );
1990
2380
  }
1991
2381
  if (popup) {
1992
2382
  const default_popup = getEntrypointBundlePath(
1993
2383
  popup,
1994
- config.outDir,
2384
+ wxt.config.outDir,
1995
2385
  ".html"
1996
2386
  );
1997
2387
  const options2 = {};
@@ -2019,28 +2409,28 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
2019
2409
  if (devtools) {
2020
2410
  manifest.devtools_page = getEntrypointBundlePath(
2021
2411
  devtools,
2022
- config.outDir,
2412
+ wxt.config.outDir,
2023
2413
  ".html"
2024
2414
  );
2025
2415
  }
2026
2416
  if (options) {
2027
- const page = getEntrypointBundlePath(options, config.outDir, ".html");
2417
+ const page = getEntrypointBundlePath(options, wxt.config.outDir, ".html");
2028
2418
  manifest.options_ui = {
2029
2419
  open_in_tab: options.options.openInTab,
2030
- browser_style: config.browser === "firefox" ? options.options.browserStyle : void 0,
2031
- chrome_style: config.browser !== "firefox" ? options.options.chromeStyle : void 0,
2420
+ browser_style: wxt.config.browser === "firefox" ? options.options.browserStyle : void 0,
2421
+ chrome_style: wxt.config.browser !== "firefox" ? options.options.chromeStyle : void 0,
2032
2422
  page
2033
2423
  };
2034
2424
  }
2035
2425
  if (sandboxes?.length) {
2036
- if (config.browser === "firefox") {
2037
- config.logger.warn(
2426
+ if (wxt.config.browser === "firefox") {
2427
+ wxt.logger.warn(
2038
2428
  "Sandboxed pages not supported by Firefox. sandbox.pages was not added to the manifest"
2039
2429
  );
2040
2430
  } else {
2041
2431
  manifest.sandbox = {
2042
2432
  pages: sandboxes.map(
2043
- (entry) => getEntrypointBundlePath(entry, config.outDir, ".html")
2433
+ (entry) => getEntrypointBundlePath(entry, wxt.config.outDir, ".html")
2044
2434
  )
2045
2435
  };
2046
2436
  }
@@ -2049,33 +2439,33 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
2049
2439
  const defaultSidepanel = sidepanels.find((entry) => entry.name === "sidepanel") ?? sidepanels[0];
2050
2440
  const page = getEntrypointBundlePath(
2051
2441
  defaultSidepanel,
2052
- config.outDir,
2442
+ wxt.config.outDir,
2053
2443
  ".html"
2054
2444
  );
2055
- if (config.browser === "firefox") {
2445
+ if (wxt.config.browser === "firefox") {
2056
2446
  manifest.sidebar_action = {
2057
2447
  // TODO: Add options to side panel
2058
2448
  // ...defaultSidepanel.options,
2059
2449
  default_panel: page
2060
2450
  };
2061
- } else if (config.manifestVersion === 3) {
2451
+ } else if (wxt.config.manifestVersion === 3) {
2062
2452
  manifest.side_panel = {
2063
2453
  default_path: page
2064
2454
  };
2065
2455
  } else {
2066
- config.logger.warn(
2456
+ wxt.logger.warn(
2067
2457
  "Side panel not supported by Chromium using MV2. side_panel.default_path was not added to the manifest"
2068
2458
  );
2069
2459
  }
2070
2460
  }
2071
2461
  if (contentScripts?.length) {
2072
2462
  const cssMap = getContentScriptsCssMap(buildOutput, contentScripts);
2073
- if (config.command === "serve" && config.manifestVersion === 3) {
2463
+ if (wxt.config.command === "serve" && wxt.config.manifestVersion === 3) {
2074
2464
  const hostPermissions = new Set(manifest.host_permissions ?? []);
2075
2465
  contentScripts.forEach((script) => {
2076
2466
  const matches = resolvePerBrowserOption(
2077
2467
  script.options.matches,
2078
- config.browser
2468
+ wxt.config.browser
2079
2469
  );
2080
2470
  matches.forEach((matchPattern) => {
2081
2471
  hostPermissions.add(matchPattern);
@@ -2086,7 +2476,7 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
2086
2476
  );
2087
2477
  } else {
2088
2478
  const hashToEntrypointsMap = contentScripts.reduce((map, script) => {
2089
- const hash = hashContentScriptOptions(script.options, config);
2479
+ const hash = hashContentScriptOptions(script.options);
2090
2480
  if (map.has(hash))
2091
2481
  map.get(hash)?.push(script);
2092
2482
  else
@@ -2095,10 +2485,10 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
2095
2485
  }, /* @__PURE__ */ new Map());
2096
2486
  const newContentScripts = Array.from(hashToEntrypointsMap.entries()).map(
2097
2487
  ([, scripts]) => ({
2098
- ...mapWxtOptionsToContentScript(scripts[0].options, config),
2488
+ ...mapWxtOptionsToContentScript(scripts[0].options),
2099
2489
  css: getContentScriptCssFiles(scripts, cssMap),
2100
2490
  js: scripts.map(
2101
- (entry) => getEntrypointBundlePath(entry, config.outDir, ".js")
2491
+ (entry) => getEntrypointBundlePath(entry, wxt.config.outDir, ".js")
2102
2492
  )
2103
2493
  })
2104
2494
  );
@@ -2108,7 +2498,6 @@ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
2108
2498
  }
2109
2499
  }
2110
2500
  const contentScriptCssResources = getContentScriptCssWebAccessibleResources(
2111
- config,
2112
2501
  contentScripts,
2113
2502
  cssMap
2114
2503
  );
@@ -2151,9 +2540,9 @@ function discoverIcons(buildOutput) {
2151
2540
  });
2152
2541
  return icons.length > 0 ? Object.fromEntries(icons) : void 0;
2153
2542
  }
2154
- function addDevModeCsp(manifest, config) {
2155
- const permission = `http://${config.server?.hostname ?? ""}/*`;
2156
- const allowedCsp = config.server?.origin ?? "http://localhost:*";
2543
+ function addDevModeCsp(manifest) {
2544
+ const permission = `http://${wxt.config.server?.hostname ?? ""}/*`;
2545
+ const allowedCsp = wxt.config.server?.origin ?? "http://localhost:*";
2157
2546
  if (manifest.manifest_version === 3) {
2158
2547
  addHostPermission(manifest, permission);
2159
2548
  } else {
@@ -2166,7 +2555,7 @@ function addDevModeCsp(manifest, config) {
2166
2555
  ) : manifest.content_security_policy ?? "script-src 'self'; object-src 'self';"
2167
2556
  // default CSP for MV2
2168
2557
  );
2169
- if (config.server)
2558
+ if (wxt.config.server)
2170
2559
  csp.add("script-src", allowedCsp);
2171
2560
  if (manifest.manifest_version === 3) {
2172
2561
  manifest.content_security_policy ??= {};
@@ -2175,9 +2564,9 @@ function addDevModeCsp(manifest, config) {
2175
2564
  manifest.content_security_policy = csp.toString();
2176
2565
  }
2177
2566
  }
2178
- function addDevModePermissions(manifest, config) {
2567
+ function addDevModePermissions(manifest) {
2179
2568
  addPermission(manifest, "tabs");
2180
- if (config.manifestVersion === 3)
2569
+ if (wxt.config.manifestVersion === 3)
2181
2570
  addPermission(manifest, "scripting");
2182
2571
  }
2183
2572
  function getContentScriptCssFiles(contentScripts, contentScriptCssMap) {
@@ -2195,7 +2584,7 @@ function getContentScriptCssFiles(contentScripts, contentScriptCssMap) {
2195
2584
  return css;
2196
2585
  return void 0;
2197
2586
  }
2198
- function getContentScriptCssWebAccessibleResources(config, contentScripts, contentScriptCssMap) {
2587
+ function getContentScriptCssWebAccessibleResources(contentScripts, contentScriptCssMap) {
2199
2588
  const resources = [];
2200
2589
  contentScripts.forEach((script) => {
2201
2590
  if (script.options.cssInjectionMode !== "ui")
@@ -2203,14 +2592,14 @@ function getContentScriptCssWebAccessibleResources(config, contentScripts, conte
2203
2592
  const cssFile = contentScriptCssMap[script.name];
2204
2593
  if (cssFile == null)
2205
2594
  return;
2206
- if (config.manifestVersion === 2) {
2595
+ if (wxt.config.manifestVersion === 2) {
2207
2596
  resources.push(cssFile);
2208
2597
  } else {
2209
2598
  resources.push({
2210
2599
  resources: [cssFile],
2211
2600
  matches: resolvePerBrowserOption(
2212
2601
  script.options.matches,
2213
- config.browser
2602
+ wxt.config.browser
2214
2603
  ).map((matchPattern) => stripPathFromMatchPattern(matchPattern))
2215
2604
  });
2216
2605
  }
@@ -2250,28 +2639,28 @@ function stripPathFromMatchPattern(pattern) {
2250
2639
  }
2251
2640
 
2252
2641
  // src/core/utils/building/rebuild.ts
2253
- async function rebuild(config, allEntrypoints, entrypointGroups, existingOutput = {
2642
+ async function rebuild(allEntrypoints, entrypointGroups, existingOutput = {
2254
2643
  steps: [],
2255
2644
  publicAssets: []
2256
2645
  }) {
2257
2646
  const { default: ora } = await import("ora");
2258
2647
  const spinner = ora(`Preparing...`).start();
2259
- await generateTypesDir(allEntrypoints, config).catch((err) => {
2260
- config.logger.warn("Failed to update .wxt directory:", err);
2261
- if (config.command === "build")
2648
+ await generateTypesDir(allEntrypoints).catch((err) => {
2649
+ wxt.logger.warn("Failed to update .wxt directory:", err);
2650
+ if (wxt.config.command === "build")
2262
2651
  throw err;
2263
2652
  });
2264
- const newOutput = await buildEntrypoints(entrypointGroups, config, spinner);
2653
+ const newOutput = await buildEntrypoints(entrypointGroups, spinner);
2265
2654
  const mergedOutput = {
2266
2655
  steps: [...existingOutput.steps, ...newOutput.steps],
2267
2656
  publicAssets: [...existingOutput.publicAssets, ...newOutput.publicAssets]
2268
2657
  };
2269
- const { manifest: newManifest, warnings: manifestWarnings } = await generateManifest(allEntrypoints, mergedOutput, config);
2658
+ const { manifest: newManifest, warnings: manifestWarnings } = await generateManifest(allEntrypoints, mergedOutput);
2270
2659
  const finalOutput = {
2271
2660
  manifest: newManifest,
2272
2661
  ...newOutput
2273
2662
  };
2274
- await writeManifest(newManifest, finalOutput, config);
2663
+ await writeManifest(newManifest, finalOutput);
2275
2664
  spinner.clear().stop();
2276
2665
  return {
2277
2666
  output: {
@@ -2288,7 +2677,7 @@ async function rebuild(config, allEntrypoints, entrypointGroups, existingOutput
2288
2677
  }
2289
2678
 
2290
2679
  // src/core/utils/building/internal-build.ts
2291
- import { relative as relative5 } from "node:path";
2680
+ import { relative as relative6 } from "node:path";
2292
2681
 
2293
2682
  // src/core/utils/validation.ts
2294
2683
  function validateEntrypoints(entrypoints) {
@@ -2354,32 +2743,35 @@ import consola3 from "consola";
2354
2743
 
2355
2744
  // src/core/utils/exec.ts
2356
2745
  import managePath from "manage-path";
2357
- import { resolve as resolve12 } from "node:path";
2746
+ import { resolve as resolve13 } from "node:path";
2358
2747
  var managedPath = managePath(process.env);
2359
- var exec = async (config, file, args, options) => {
2748
+ var exec = async (file, args, options) => {
2360
2749
  managedPath.restore();
2361
- managedPath.push(resolve12(config.root, "node_modules/wxt/node_modules/.bin"));
2750
+ managedPath.push(
2751
+ resolve13(wxt.config.root, "node_modules/wxt/node_modules/.bin")
2752
+ );
2362
2753
  const { execa } = await import("./execa-4F7CCWCA.js");
2363
2754
  return await execa(file, args, options);
2364
2755
  };
2365
2756
 
2366
2757
  // src/core/utils/building/internal-build.ts
2367
- async function internalBuild(config) {
2368
- const verb = config.command === "serve" ? "Pre-rendering" : "Building";
2369
- const target = `${config.browser}-mv${config.manifestVersion}`;
2370
- config.logger.info(
2371
- `${verb} ${pc4.cyan(target)} for ${pc4.cyan(config.mode)} with ${pc4.green(
2372
- `${config.builder.name} ${config.builder.version}`
2758
+ async function internalBuild() {
2759
+ await wxt.hooks.callHook("build:before", wxt);
2760
+ const verb = wxt.config.command === "serve" ? "Pre-rendering" : "Building";
2761
+ const target = `${wxt.config.browser}-mv${wxt.config.manifestVersion}`;
2762
+ wxt.logger.info(
2763
+ `${verb} ${pc5.cyan(target)} for ${pc5.cyan(wxt.config.mode)} with ${pc5.green(
2764
+ `${wxt.config.builder.name} ${wxt.config.builder.version}`
2373
2765
  )}`
2374
2766
  );
2375
2767
  const startTime = Date.now();
2376
- await fs11.rm(config.outDir, { recursive: true, force: true });
2377
- await fs11.ensureDir(config.outDir);
2378
- const entrypoints = await findEntrypoints(config);
2379
- config.logger.debug("Detected entrypoints:", entrypoints);
2768
+ await fs12.rm(wxt.config.outDir, { recursive: true, force: true });
2769
+ await fs12.ensureDir(wxt.config.outDir);
2770
+ const entrypoints = await findEntrypoints();
2771
+ wxt.logger.debug("Detected entrypoints:", entrypoints);
2380
2772
  const validationResults = validateEntrypoints(entrypoints);
2381
2773
  if (validationResults.errorCount + validationResults.warningCount > 0) {
2382
- printValidationResults(config, validationResults);
2774
+ printValidationResults(validationResults);
2383
2775
  }
2384
2776
  if (validationResults.errorCount > 0) {
2385
2777
  throw new ValidationError(`Entrypoint validation failed`, {
@@ -2387,45 +2779,44 @@ async function internalBuild(config) {
2387
2779
  });
2388
2780
  }
2389
2781
  const groups = groupEntrypoints(entrypoints);
2390
- const { output, warnings } = await rebuild(
2391
- config,
2392
- entrypoints,
2393
- groups,
2394
- void 0
2395
- );
2782
+ await wxt.hooks.callHook("entrypoints:grouped", wxt, groups);
2783
+ const { output, warnings } = await rebuild(entrypoints, groups, void 0);
2784
+ await wxt.hooks.callHook("build:done", wxt, output);
2396
2785
  await printBuildSummary(
2397
- config.logger.success,
2786
+ wxt.logger.success,
2398
2787
  `Built extension in ${formatDuration(Date.now() - startTime)}`,
2399
- output,
2400
- config
2788
+ output
2401
2789
  );
2402
2790
  for (const warning of warnings) {
2403
- config.logger.warn(...warning);
2791
+ wxt.logger.warn(...warning);
2404
2792
  }
2405
- if (config.analysis.enabled) {
2406
- await combineAnalysisStats(config);
2407
- config.logger.info(
2793
+ if (wxt.config.analysis.enabled) {
2794
+ await combineAnalysisStats();
2795
+ wxt.logger.info(
2408
2796
  `Analysis complete:
2409
- ${pc4.gray("\u2514\u2500")} ${pc4.yellow("stats.html")}`
2797
+ ${pc5.gray("\u2514\u2500")} ${pc5.yellow("stats.html")}`
2410
2798
  );
2411
2799
  }
2412
2800
  return output;
2413
2801
  }
2414
- async function combineAnalysisStats(config) {
2415
- const unixFiles = await glob2(`stats-*.json`, {
2416
- cwd: config.outDir,
2802
+ async function combineAnalysisStats() {
2803
+ const unixFiles = await glob3(`stats-*.json`, {
2804
+ cwd: wxt.config.outDir,
2417
2805
  absolute: true
2418
2806
  });
2419
2807
  const absolutePaths = unixFiles.map(unnormalizePath);
2420
2808
  await exec(
2421
- config,
2422
2809
  "rollup-plugin-visualizer",
2423
- [...absolutePaths, "--template", config.analysis.template],
2424
- { cwd: config.root, stdio: "inherit" }
2810
+ [...absolutePaths, "--template", wxt.config.analysis.template],
2811
+ { cwd: wxt.config.root, stdio: "inherit" }
2425
2812
  );
2426
2813
  }
2427
- function printValidationResults(config, { errorCount, errors, warningCount }) {
2428
- (errorCount > 0 ? config.logger.error : config.logger.warn)(
2814
+ function printValidationResults({
2815
+ errorCount,
2816
+ errors,
2817
+ warningCount
2818
+ }) {
2819
+ (errorCount > 0 ? wxt.logger.error : wxt.logger.warn)(
2429
2820
  `Entrypoint validation failed: ${errorCount} error${errorCount === 1 ? "" : "s"}, ${warningCount} warning${warningCount === 1 ? "" : "s"}`
2430
2821
  );
2431
2822
  const cwd = process.cwd();
@@ -2436,355 +2827,40 @@ function printValidationResults(config, { errorCount, errors, warningCount }) {
2436
2827
  return map;
2437
2828
  }, /* @__PURE__ */ new Map());
2438
2829
  Array.from(entrypointErrors.entries()).forEach(([entrypoint, errors2]) => {
2439
- consola3.log(relative5(cwd, entrypoint.inputPath));
2830
+ consola3.log(relative6(cwd, entrypoint.inputPath));
2440
2831
  console.log();
2441
2832
  errors2.forEach((err) => {
2442
- const type = err.type === "error" ? pc4.red("ERROR") : pc4.yellow("WARN");
2443
- const recieved = pc4.dim(`(recieved: ${JSON.stringify(err.value)})`);
2833
+ const type = err.type === "error" ? pc5.red("ERROR") : pc5.yellow("WARN");
2834
+ const recieved = pc5.dim(`(recieved: ${JSON.stringify(err.value)})`);
2444
2835
  consola3.log(` - ${type} ${err.message} ${recieved}`);
2445
2836
  });
2446
2837
  console.log();
2447
2838
  });
2448
2839
  }
2449
2840
 
2450
- // src/core/utils/building/find-entrypoints.ts
2451
- import glob3 from "fast-glob";
2452
- import pc5 from "picocolors";
2453
- async function findEntrypoints(config) {
2454
- const relativePaths = await glob3(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
2455
- cwd: config.entrypointsDir
2456
- });
2457
- relativePaths.sort();
2458
- const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
2459
- const entrypointInfos = relativePaths.reduce((results, relativePath) => {
2460
- const inputPath = resolve13(config.entrypointsDir, relativePath);
2461
- const name = getEntrypointName(config.entrypointsDir, inputPath);
2462
- const matchingGlob = pathGlobs.find(
2463
- (glob4) => minimatch(relativePath, glob4)
2464
- );
2465
- if (matchingGlob) {
2466
- const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
2467
- results.push({
2468
- name,
2469
- inputPath,
2470
- type,
2471
- skipped: config.filterEntrypoints != null && !config.filterEntrypoints.has(name)
2472
- });
2473
- }
2474
- return results;
2475
- }, []);
2476
- preventNoEntrypoints(config, entrypointInfos);
2477
- preventDuplicateEntrypointNames(config, entrypointInfos);
2478
- let hasBackground = false;
2479
- const entrypoints = await Promise.all(
2480
- entrypointInfos.map(async (info) => {
2481
- const { type } = info;
2482
- switch (type) {
2483
- case "popup":
2484
- return await getPopupEntrypoint(config, info);
2485
- case "options":
2486
- return await getOptionsEntrypoint(config, info);
2487
- case "background":
2488
- hasBackground = true;
2489
- return await getBackgroundEntrypoint(config, info);
2490
- case "content-script":
2491
- return await getContentScriptEntrypoint(config, info);
2492
- case "unlisted-page":
2493
- return await getUnlistedPageEntrypoint(config, info);
2494
- case "unlisted-script":
2495
- return await getUnlistedScriptEntrypoint(config, info);
2496
- case "content-script-style":
2497
- return {
2498
- ...info,
2499
- type,
2500
- outputDir: resolve13(config.outDir, CONTENT_SCRIPT_OUT_DIR),
2501
- options: {
2502
- include: void 0,
2503
- exclude: void 0
2504
- }
2505
- };
2506
- default:
2507
- return {
2508
- ...info,
2509
- type,
2510
- outputDir: config.outDir,
2511
- options: {
2512
- include: void 0,
2513
- exclude: void 0
2514
- }
2515
- };
2516
- }
2517
- })
2518
- );
2519
- if (config.command === "serve" && !hasBackground) {
2520
- entrypoints.push(
2521
- await getBackgroundEntrypoint(config, {
2522
- inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
2523
- name: "background",
2524
- type: "background",
2525
- skipped: false
2526
- })
2527
- );
2528
- }
2529
- config.logger.debug("All entrypoints:", entrypoints);
2530
- const skippedEntrypointNames = entrypointInfos.filter((item) => item.skipped).map((item) => item.name);
2531
- if (skippedEntrypointNames.length) {
2532
- config.logger.warn(
2533
- `Filter excluded the following entrypoints:
2534
- ${skippedEntrypointNames.map((item) => `${pc5.dim("-")} ${pc5.cyan(item)}`).join("\n")}`
2535
- );
2536
- }
2537
- const targetEntrypoints = entrypoints.filter((entry) => {
2538
- const { include, exclude } = entry.options;
2539
- if (include?.length && exclude?.length) {
2540
- config.logger.warn(
2541
- `The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
2542
- );
2543
- return false;
2544
- }
2545
- if (exclude?.length && !include?.length) {
2546
- return !exclude.includes(config.browser);
2547
- }
2548
- if (include?.length && !exclude?.length) {
2549
- return include.includes(config.browser);
2550
- }
2551
- if (skippedEntrypointNames.includes(entry.name)) {
2552
- return false;
2553
- }
2554
- return true;
2555
- });
2556
- config.logger.debug(`${config.browser} entrypoints:`, targetEntrypoints);
2557
- return targetEntrypoints;
2558
- }
2559
- function preventDuplicateEntrypointNames(config, files) {
2560
- const namesToPaths = files.reduce(
2561
- (map, { name, inputPath }) => {
2562
- map[name] ??= [];
2563
- map[name].push(inputPath);
2564
- return map;
2565
- },
2566
- {}
2567
- );
2568
- const errorLines = Object.entries(namesToPaths).reduce(
2569
- (lines, [name, absolutePaths]) => {
2570
- if (absolutePaths.length > 1) {
2571
- lines.push(`- ${name}`);
2572
- absolutePaths.forEach((absolutePath) => {
2573
- lines.push(` - ${relative6(config.root, absolutePath)}`);
2574
- });
2575
- }
2576
- return lines;
2841
+ // src/core/wxt.ts
2842
+ import { createHooks } from "hookable";
2843
+ var wxt;
2844
+ async function registerWxt(command, inlineConfig = {}, server) {
2845
+ const config = await resolveConfig(inlineConfig, command, server);
2846
+ const hooks = createHooks();
2847
+ wxt = {
2848
+ config,
2849
+ hooks,
2850
+ get logger() {
2851
+ return config.logger;
2577
2852
  },
2578
- []
2579
- );
2580
- if (errorLines.length > 0) {
2581
- const errorContent = errorLines.join("\n");
2582
- throw Error(
2583
- `Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
2584
-
2585
- ${errorContent}`
2586
- );
2587
- }
2588
- }
2589
- function preventNoEntrypoints(config, files) {
2590
- if (files.length === 0) {
2591
- throw Error(`No entrypoints found in ${config.entrypointsDir}`);
2592
- }
2593
- }
2594
- function getHtmlBaseOptions(document) {
2595
- const options = {};
2596
- const includeContent = document.querySelector("meta[name='manifest.include']")?.getAttribute("content");
2597
- if (includeContent) {
2598
- options.include = JSON5.parse(includeContent);
2599
- }
2600
- const excludeContent = document.querySelector("meta[name='manifest.exclude']")?.getAttribute("content");
2601
- if (excludeContent) {
2602
- options.exclude = JSON5.parse(excludeContent);
2603
- }
2604
- return options;
2605
- }
2606
- async function getPopupEntrypoint(config, { inputPath, name, skipped }) {
2607
- const content = await fs12.readFile(inputPath, "utf-8");
2608
- const { document } = parseHTML2(content);
2609
- const options = getHtmlBaseOptions(document);
2610
- const title = document.querySelector("title");
2611
- if (title != null)
2612
- options.defaultTitle = title.textContent ?? void 0;
2613
- const defaultIconContent = document.querySelector("meta[name='manifest.default_icon']")?.getAttribute("content");
2614
- if (defaultIconContent) {
2615
- try {
2616
- options.defaultIcon = JSON5.parse(defaultIconContent);
2617
- } catch (err) {
2618
- config.logger.fatal(
2619
- `Failed to parse default_icon meta tag content as JSON5. content=${defaultIconContent}`,
2620
- err
2621
- );
2853
+ async reloadConfig() {
2854
+ wxt.config = await resolveConfig(inlineConfig, command, server);
2622
2855
  }
2623
- }
2624
- const mv2TypeContent = document.querySelector("meta[name='manifest.type']")?.getAttribute("content");
2625
- if (mv2TypeContent) {
2626
- options.mv2Key = mv2TypeContent === "page_action" ? "page_action" : "browser_action";
2627
- }
2628
- const browserStyleContent = document.querySelector("meta[name='manifest.browser_style']")?.getAttribute("content");
2629
- if (browserStyleContent) {
2630
- options.browserStyle = browserStyleContent === "true";
2631
- }
2632
- return {
2633
- type: "popup",
2634
- name: "popup",
2635
- options,
2636
- inputPath,
2637
- outputDir: config.outDir,
2638
- skipped
2639
2856
  };
2857
+ wxt.hooks.addHooks(config.hooks);
2858
+ await wxt.hooks.callHook("ready", wxt);
2640
2859
  }
2641
- async function getOptionsEntrypoint(config, { inputPath, name, skipped }) {
2642
- const content = await fs12.readFile(inputPath, "utf-8");
2643
- const { document } = parseHTML2(content);
2644
- const options = getHtmlBaseOptions(document);
2645
- const openInTabContent = document.querySelector("meta[name='manifest.open_in_tab']")?.getAttribute("content");
2646
- if (openInTabContent) {
2647
- options.openInTab = openInTabContent === "true";
2648
- }
2649
- const chromeStyleContent = document.querySelector("meta[name='manifest.chrome_style']")?.getAttribute("content");
2650
- if (chromeStyleContent) {
2651
- options.chromeStyle = chromeStyleContent === "true";
2652
- }
2653
- const browserStyleContent = document.querySelector("meta[name='manifest.browser_style']")?.getAttribute("content");
2654
- if (browserStyleContent) {
2655
- options.browserStyle = browserStyleContent === "true";
2656
- }
2657
- return {
2658
- type: "options",
2659
- name: "options",
2660
- options,
2661
- inputPath,
2662
- outputDir: config.outDir,
2663
- skipped
2664
- };
2665
- }
2666
- async function getUnlistedPageEntrypoint(config, { inputPath, name, skipped }) {
2667
- const content = await fs12.readFile(inputPath, "utf-8");
2668
- const { document } = parseHTML2(content);
2669
- return {
2670
- type: "unlisted-page",
2671
- name: getEntrypointName(config.entrypointsDir, inputPath),
2672
- inputPath,
2673
- outputDir: config.outDir,
2674
- options: getHtmlBaseOptions(document),
2675
- skipped
2676
- };
2677
- }
2678
- async function getUnlistedScriptEntrypoint(config, { inputPath, name, skipped }) {
2679
- const defaultExport = await importEntrypointFile(
2680
- inputPath,
2681
- config
2682
- );
2683
- if (defaultExport == null) {
2684
- throw Error(
2685
- `${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
2686
- );
2687
- }
2688
- const { main: _, ...moduleOptions } = defaultExport;
2689
- const options = moduleOptions;
2690
- return {
2691
- type: "unlisted-script",
2692
- name,
2693
- inputPath,
2694
- outputDir: config.outDir,
2695
- options,
2696
- skipped
2697
- };
2698
- }
2699
- async function getBackgroundEntrypoint(config, { inputPath, name, skipped }) {
2700
- let options = {};
2701
- if (inputPath !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
2702
- const defaultExport = await importEntrypointFile(
2703
- inputPath,
2704
- config
2705
- );
2706
- if (defaultExport == null) {
2707
- throw Error(
2708
- `${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
2709
- );
2710
- }
2711
- const { main: _, ...moduleOptions } = defaultExport;
2712
- options = moduleOptions;
2713
- }
2714
- if (config.manifestVersion !== 3) {
2715
- delete options.type;
2716
- }
2717
- return {
2718
- type: "background",
2719
- name,
2720
- inputPath,
2721
- outputDir: config.outDir,
2722
- options: {
2723
- ...options,
2724
- type: resolvePerBrowserOption(options.type, config.browser),
2725
- persistent: resolvePerBrowserOption(options.persistent, config.browser)
2726
- },
2727
- skipped
2728
- };
2729
- }
2730
- async function getContentScriptEntrypoint(config, { inputPath, name, skipped }) {
2731
- const { main: _, ...options } = await importEntrypointFile(inputPath, config);
2732
- if (options == null) {
2733
- throw Error(
2734
- `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
2735
- );
2736
- }
2737
- return {
2738
- type: "content-script",
2739
- name,
2740
- inputPath,
2741
- outputDir: resolve13(config.outDir, CONTENT_SCRIPT_OUT_DIR),
2742
- options,
2743
- skipped
2744
- };
2745
- }
2746
- var PATH_GLOB_TO_TYPE_MAP = {
2747
- "sandbox.html": "sandbox",
2748
- "sandbox/index.html": "sandbox",
2749
- "*.sandbox.html": "sandbox",
2750
- "*.sandbox/index.html": "sandbox",
2751
- "bookmarks.html": "bookmarks",
2752
- "bookmarks/index.html": "bookmarks",
2753
- "history.html": "history",
2754
- "history/index.html": "history",
2755
- "newtab.html": "newtab",
2756
- "newtab/index.html": "newtab",
2757
- "sidepanel.html": "sidepanel",
2758
- "sidepanel/index.html": "sidepanel",
2759
- "*.sidepanel.html": "sidepanel",
2760
- "*.sidepanel/index.html": "sidepanel",
2761
- "devtools.html": "devtools",
2762
- "devtools/index.html": "devtools",
2763
- "background.[jt]s": "background",
2764
- "background/index.[jt]s": "background",
2765
- [VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
2766
- "content.[jt]s?(x)": "content-script",
2767
- "content/index.[jt]s?(x)": "content-script",
2768
- "*.content.[jt]s?(x)": "content-script",
2769
- "*.content/index.[jt]s?(x)": "content-script",
2770
- [`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
2771
- [`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
2772
- [`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
2773
- [`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
2774
- "popup.html": "popup",
2775
- "popup/index.html": "popup",
2776
- "options.html": "options",
2777
- "options/index.html": "options",
2778
- "*.html": "unlisted-page",
2779
- "*/index.html": "unlisted-page",
2780
- "*.[jt]s?(x)": "unlisted-script",
2781
- "*/index.[jt]s?(x)": "unlisted-script",
2782
- [`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
2783
- [`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
2784
- };
2785
- var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
2786
2860
 
2787
2861
  export {
2862
+ wxt,
2863
+ registerWxt,
2788
2864
  detectDevChanges,
2789
2865
  getEntrypointBundlePath,
2790
2866
  resolvePerBrowserOption,
@@ -2796,7 +2872,7 @@ export {
2796
2872
  tsconfigPaths,
2797
2873
  globals,
2798
2874
  webextensionPolyfillMock,
2799
- getInternalConfig,
2875
+ resolveConfig,
2800
2876
  kebabCaseAlphanumeric,
2801
2877
  printFileList,
2802
2878
  version,