wxt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1482 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ build: () => build2,
34
+ createServer: () => createServer2,
35
+ defineConfig: () => defineConfig,
36
+ defineRunnerConfig: () => defineRunnerConfig,
37
+ version: () => version
38
+ });
39
+ module.exports = __toCommonJS(src_exports);
40
+
41
+ // src/core/utils/getInternalConfig.ts
42
+ var import_node_path3 = __toESM(require("path"), 1);
43
+ var vite = __toESM(require("vite"), 1);
44
+ var import_consola2 = require("consola");
45
+
46
+ // src/core/utils/importTsFile.ts
47
+ var import_consola = require("consola");
48
+ var import_jiti = __toESM(require("jiti"), 1);
49
+ var import_babel = __toESM(require("jiti/dist/babel"), 1);
50
+ var import_path = require("path");
51
+ var import_unimport = require("unimport");
52
+ async function importTsFile(root, path5) {
53
+ const clientImports = await (0, import_unimport.scanExports)(
54
+ (0, import_path.resolve)(root, "node_modules/wxt/dist/client/index.js")
55
+ );
56
+ const jiti = (0, import_jiti.default)(__filename, {
57
+ cache: false,
58
+ esmResolve: true,
59
+ interopDefault: true,
60
+ transform(opts) {
61
+ opts.source = opts.source.replace(/^import ['"].*\.css['"];?$/gm, "");
62
+ opts.source = opts.source.replace(
63
+ /^import\s+.*\s+from ['"]webextension-polyfill['"];?$/gm,
64
+ ""
65
+ );
66
+ if (opts.filename === path5) {
67
+ const imports = clientImports.map((i) => `import { ${i.name} } from "${i.from}";`).join("\n") + "\n";
68
+ opts.source = imports + opts.source;
69
+ }
70
+ return (0, import_babel.default)(opts);
71
+ }
72
+ });
73
+ try {
74
+ return await jiti(path5);
75
+ } catch (err) {
76
+ import_consola.consola.error(`Failed to import file: ${path5}`);
77
+ throw err;
78
+ }
79
+ }
80
+
81
+ // src/core/utils/network.ts
82
+ var import_node_dns = __toESM(require("dns"), 1);
83
+
84
+ // src/core/utils/promises.ts
85
+ function withTimeout(promise, duration) {
86
+ return new Promise((res, rej) => {
87
+ const timeout = setTimeout(() => {
88
+ rej(`Promise timed out after ${duration}ms`);
89
+ }, duration);
90
+ promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
91
+ });
92
+ }
93
+
94
+ // src/core/utils/network.ts
95
+ function isOffline() {
96
+ const isOffline2 = new Promise((res) => {
97
+ import_node_dns.default.resolve("google.com", (err) => {
98
+ if (err == null) {
99
+ res(false);
100
+ } else {
101
+ res(true);
102
+ }
103
+ });
104
+ });
105
+ return withTimeout(isOffline2, 1e3).catch(() => true);
106
+ }
107
+ async function isOnline() {
108
+ const offline = await isOffline();
109
+ return !offline;
110
+ }
111
+ async function fetchCached(url, config) {
112
+ let content = "";
113
+ if (await isOnline()) {
114
+ const res = await fetch(url);
115
+ if (res.status < 300) {
116
+ content = await res.text();
117
+ await config.fsCache.set(url, content);
118
+ } else {
119
+ config.logger.debug(
120
+ `Failed to download "${url}", falling back to cache...`
121
+ );
122
+ }
123
+ }
124
+ if (!content)
125
+ content = await config.fsCache.get(url) ?? "";
126
+ if (!content)
127
+ throw Error(
128
+ `Offline and "${url}" has not been cached. Try again when online.`
129
+ );
130
+ return content;
131
+ }
132
+
133
+ // src/core/vite-plugins/download.ts
134
+ function download(config) {
135
+ return {
136
+ name: "wxt:download",
137
+ resolveId(id) {
138
+ if (id.startsWith("url:"))
139
+ return "\0" + id;
140
+ },
141
+ async load(id) {
142
+ if (!id.startsWith("\0url:"))
143
+ return;
144
+ const url = id.replace("\0url:", "");
145
+ return await fetchCached(url, config);
146
+ }
147
+ };
148
+ }
149
+
150
+ // src/core/vite-plugins/unimport.ts
151
+ var import_unimport2 = require("unimport");
152
+
153
+ // src/core/utils/auto-imports.ts
154
+ var import_vite = require("vite");
155
+ function getUnimportOptions(config) {
156
+ const defaultOptions = {
157
+ debugLog: config.logger.debug,
158
+ imports: [
159
+ { name: "*", as: "browser", from: "webextension-polyfill" },
160
+ { name: "defineConfig", from: "wxt" }
161
+ ],
162
+ presets: [{ package: "wxt/client" }],
163
+ warn: config.logger.warn,
164
+ dirs: ["components", "composables", "hooks", "utils"]
165
+ };
166
+ return (0, import_vite.mergeConfig)(
167
+ defaultOptions,
168
+ config.imports
169
+ );
170
+ }
171
+
172
+ // src/core/vite-plugins/unimport.ts
173
+ function unimport(config) {
174
+ const options = getUnimportOptions(config);
175
+ const unimport2 = (0, import_unimport2.createUnimport)(options);
176
+ return {
177
+ name: "wxt:unimport",
178
+ async config() {
179
+ await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
180
+ },
181
+ async transform(code, id) {
182
+ return unimport2.injectImports(code, id);
183
+ }
184
+ };
185
+ }
186
+
187
+ // src/core/vite-plugins/multipageMove.ts
188
+ var import_node_path2 = require("path");
189
+
190
+ // src/core/utils/entrypoints.ts
191
+ var import_node_path = __toESM(require("path"), 1);
192
+ function getEntrypointName(entrypointsDir, inputPath) {
193
+ const relativePath = import_node_path.default.relative(entrypointsDir, inputPath);
194
+ const name = relativePath.split(/[\.\/]/, 2)[0];
195
+ return name;
196
+ }
197
+ function getEntrypointOutputFile(entrypoint, ext) {
198
+ return (0, import_node_path.resolve)(entrypoint.outputDir, `${entrypoint.name}${ext}`);
199
+ }
200
+ function getEntrypointBundlePath(entrypoint, outDir, ext) {
201
+ return (0, import_node_path.relative)(outDir, getEntrypointOutputFile(entrypoint, ext));
202
+ }
203
+
204
+ // src/core/vite-plugins/multipageMove.ts
205
+ var import_fs_extra = __toESM(require("fs-extra"), 1);
206
+ function multipageMove(entrypoints, config) {
207
+ return {
208
+ name: "wxt:multipage-move",
209
+ async writeBundle(_, bundle) {
210
+ for (const oldBundlePath in bundle) {
211
+ const entrypoint = entrypoints.find(
212
+ (entry) => !!entry.inputPath.endsWith(oldBundlePath)
213
+ );
214
+ if (entrypoint == null) {
215
+ config.logger.debug("No entrypoint found for", oldBundlePath);
216
+ continue;
217
+ }
218
+ const newBundlePath = getEntrypointBundlePath(
219
+ entrypoint,
220
+ config.outDir,
221
+ (0, import_node_path2.extname)(oldBundlePath)
222
+ );
223
+ if (newBundlePath === oldBundlePath) {
224
+ config.logger.debug(
225
+ "HTML file is already in the correct location",
226
+ oldBundlePath
227
+ );
228
+ continue;
229
+ }
230
+ const oldAbsPath = (0, import_node_path2.resolve)(config.outDir, oldBundlePath);
231
+ const newAbsPath = (0, import_node_path2.resolve)(config.outDir, newBundlePath);
232
+ await (0, import_fs_extra.ensureDir)((0, import_node_path2.dirname)(newAbsPath));
233
+ await import_fs_extra.default.move(oldAbsPath, newAbsPath);
234
+ const renamedChunk = {
235
+ ...bundle[oldBundlePath],
236
+ fileName: newBundlePath
237
+ };
238
+ delete bundle[oldBundlePath];
239
+ bundle[newBundlePath] = renamedChunk;
240
+ }
241
+ }
242
+ };
243
+ }
244
+
245
+ // src/core/vite-plugins/devHtmlPrerender.ts
246
+ var import_linkedom = require("linkedom");
247
+ var import_path2 = require("path");
248
+ function devHtmlPrerender(config) {
249
+ return {
250
+ apply: "build",
251
+ name: "wxt:dev-html-prerender",
252
+ async transform(html, id) {
253
+ const server = config.server;
254
+ if (config.command !== "serve" || server == null || !id.endsWith(".html"))
255
+ return;
256
+ const originalUrl = `${server.origin}${id}`;
257
+ const name = getEntrypointName(config.entrypointsDir, id);
258
+ const url = `${server.origin}/${name}.html`;
259
+ const serverHtml = await server.transformIndexHtml(
260
+ url,
261
+ html,
262
+ originalUrl
263
+ );
264
+ const { document } = (0, import_linkedom.parseHTML)(serverHtml);
265
+ const pointToDevServer = (querySelector, attr) => {
266
+ document.querySelectorAll(querySelector).forEach((element) => {
267
+ const src = element.getAttribute(attr);
268
+ if (!src)
269
+ return;
270
+ if ((0, import_path2.isAbsolute)(src)) {
271
+ element.setAttribute(attr, server.origin + src);
272
+ } else if (src.startsWith(".")) {
273
+ const abs = (0, import_path2.resolve)((0, import_path2.dirname)(id), src);
274
+ const pathname = (0, import_path2.relative)(config.root, abs);
275
+ element.setAttribute(attr, `${server.origin}/${pathname}`);
276
+ }
277
+ });
278
+ };
279
+ pointToDevServer("script[type=module]", "src");
280
+ pointToDevServer("link[rel=stylesheet]", "href");
281
+ const newHtml = document.toString();
282
+ config.logger.debug("Transformed " + id);
283
+ config.logger.debug("Old HTML:\n" + html);
284
+ config.logger.debug("New HTML:\n" + newHtml);
285
+ return newHtml;
286
+ }
287
+ };
288
+ }
289
+
290
+ // src/core/vite-plugins/virtualEntrypoint.ts
291
+ var import_fs_extra2 = __toESM(require("fs-extra"), 1);
292
+ var import_path3 = require("path");
293
+ function virtualEntrypoin(type, config) {
294
+ const virtualId = `virtual:wxt-${type}?`;
295
+ const resolvedVirtualId = `\0${virtualId}`;
296
+ return {
297
+ name: `wxt:virtual-entrypoint`,
298
+ resolveId(id) {
299
+ const index = id.indexOf(virtualId);
300
+ if (index === -1)
301
+ return;
302
+ const inputPath = id.substring(index + virtualId.length);
303
+ return resolvedVirtualId + inputPath;
304
+ },
305
+ async load(id) {
306
+ if (!id.startsWith(resolvedVirtualId))
307
+ return;
308
+ const inputPath = id.replace(resolvedVirtualId, "");
309
+ const template = await import_fs_extra2.default.readFile(
310
+ (0, import_path3.resolve)(config.root, `node_modules/wxt/templates/virtual-${type}.ts`),
311
+ "utf-8"
312
+ );
313
+ return template.replaceAll("{{moduleId}}", inputPath);
314
+ }
315
+ };
316
+ }
317
+
318
+ // src/core/utils/createFsCache.ts
319
+ var import_fs_extra3 = __toESM(require("fs-extra"), 1);
320
+ var import_path4 = require("path");
321
+ function createFsCache(wxtDir) {
322
+ const getPath = (key) => (0, import_path4.resolve)(wxtDir, "cache", encodeURIComponent(key));
323
+ return {
324
+ async set(key, value) {
325
+ const path5 = getPath(key);
326
+ await (0, import_fs_extra3.ensureDir)((0, import_path4.dirname)(path5));
327
+ await import_fs_extra3.default.writeFile(path5, value, "utf-8");
328
+ },
329
+ async get(key) {
330
+ const path5 = getPath(key);
331
+ try {
332
+ return await import_fs_extra3.default.readFile(path5, "utf-8");
333
+ } catch {
334
+ return void 0;
335
+ }
336
+ }
337
+ };
338
+ }
339
+
340
+ // src/core/utils/globals.ts
341
+ function getGlobals(config) {
342
+ return [
343
+ {
344
+ name: "__MANIFEST_VERSION__",
345
+ value: config.manifestVersion,
346
+ type: `2 | 3`
347
+ },
348
+ {
349
+ name: "__BROWSER__",
350
+ value: config.browser,
351
+ type: `"chromium" | "firefox"`
352
+ },
353
+ {
354
+ name: "__IS_CHROME__",
355
+ value: config.browser === "chrome",
356
+ type: `boolean`
357
+ },
358
+ {
359
+ name: "__IS_FIREFOX__",
360
+ value: config.browser === "firefox",
361
+ type: `boolean`
362
+ },
363
+ {
364
+ name: "__IS_SAFARI__",
365
+ value: config.browser === "safari",
366
+ type: `boolean`
367
+ },
368
+ {
369
+ name: "__IS_EDGE__",
370
+ value: config.browser === "edge",
371
+ type: `boolean`
372
+ },
373
+ {
374
+ name: "__IS_OPERA__",
375
+ value: config.browser === "opera",
376
+ type: `boolean`
377
+ }
378
+ ];
379
+ }
380
+
381
+ // src/core/utils/getInternalConfig.ts
382
+ var import_c12 = require("c12");
383
+ async function getInternalConfig(config, command) {
384
+ const root = config.root ? import_node_path3.default.resolve(config.root) : process.cwd();
385
+ const mode = config.mode ?? (command === "build" ? "production" : "development");
386
+ const browser = config.browser ?? "chrome";
387
+ const manifestVersion = config.manifestVersion ?? (browser == "firefox" ? 2 : 3);
388
+ const outBaseDir = import_node_path3.default.resolve(root, ".output");
389
+ const outDir = import_node_path3.default.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
390
+ const logger = config.logger ?? import_consola2.consola;
391
+ const baseConfig = {
392
+ root,
393
+ outDir,
394
+ outBaseDir,
395
+ storeIds: config.storeIds ?? {},
396
+ browser,
397
+ manifestVersion,
398
+ mode,
399
+ command,
400
+ logger,
401
+ vite: config.vite ?? {},
402
+ manifest: config.manifest ?? {},
403
+ imports: config.imports ?? {},
404
+ runnerConfig: await (0, import_c12.loadConfig)({
405
+ name: "web-ext",
406
+ cwd: root,
407
+ globalRc: true,
408
+ rcFile: ".webextrc",
409
+ overrides: config.runner
410
+ })
411
+ };
412
+ let userConfig = {
413
+ mode
414
+ };
415
+ if (config.configFile !== false) {
416
+ userConfig = await importTsFile(
417
+ root,
418
+ import_node_path3.default.resolve(root, config.configFile ?? "wxt.config.ts")
419
+ );
420
+ }
421
+ const merged = vite.mergeConfig(
422
+ baseConfig,
423
+ userConfig
424
+ );
425
+ const srcDir = userConfig.srcDir ? (0, import_node_path3.resolve)(root, userConfig.srcDir) : root;
426
+ const entrypointsDir = (0, import_node_path3.resolve)(
427
+ srcDir,
428
+ userConfig.entrypointsDir ?? "entrypoints"
429
+ );
430
+ const publicDir = (0, import_node_path3.resolve)(srcDir, userConfig.publicDir ?? "public");
431
+ const wxtDir = (0, import_node_path3.resolve)(srcDir, ".wxt");
432
+ const typesDir = (0, import_node_path3.resolve)(wxtDir, "types");
433
+ const finalConfig = {
434
+ ...merged,
435
+ srcDir,
436
+ entrypointsDir,
437
+ publicDir,
438
+ wxtDir,
439
+ typesDir,
440
+ fsCache: createFsCache(wxtDir)
441
+ };
442
+ finalConfig.vite.root = root;
443
+ finalConfig.vite.configFile = false;
444
+ finalConfig.vite.logLevel = "silent";
445
+ finalConfig.vite.build ??= {};
446
+ finalConfig.vite.build.outDir = outDir;
447
+ finalConfig.vite.build.emptyOutDir = false;
448
+ finalConfig.vite.plugins ??= [];
449
+ finalConfig.vite.plugins.push(download(finalConfig));
450
+ finalConfig.vite.plugins.push(devHtmlPrerender(finalConfig));
451
+ finalConfig.vite.plugins.push(unimport(finalConfig));
452
+ finalConfig.vite.plugins.push(
453
+ virtualEntrypoin("background", finalConfig)
454
+ );
455
+ finalConfig.vite.plugins.push(
456
+ virtualEntrypoin("content-script", finalConfig)
457
+ );
458
+ finalConfig.vite.define ??= {};
459
+ getGlobals(finalConfig).forEach((global) => {
460
+ finalConfig.vite.define[global.name] = JSON.stringify(global.value);
461
+ });
462
+ return finalConfig;
463
+ }
464
+
465
+ // src/core/build/findEntrypoints.ts
466
+ var import_path5 = require("path");
467
+ var import_fs_extra4 = __toESM(require("fs-extra"), 1);
468
+ var import_picomatch = __toESM(require("picomatch"), 1);
469
+ var import_linkedom2 = require("linkedom");
470
+ var import_json5 = __toESM(require("json5"), 1);
471
+ var import_fast_glob = __toESM(require("fast-glob"), 1);
472
+ async function findEntrypoints(config) {
473
+ const relativePaths = await (0, import_fast_glob.default)("**/*", {
474
+ cwd: config.entrypointsDir
475
+ });
476
+ relativePaths.sort();
477
+ const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
478
+ const existingNames = {};
479
+ const entrypoints = [];
480
+ await Promise.all(
481
+ relativePaths.map(async (relativePath) => {
482
+ const path5 = (0, import_path5.resolve)(config.entrypointsDir, relativePath);
483
+ const matchingGlob = pathGlobs.find(
484
+ (glob3) => import_picomatch.default.isMatch(relativePath, glob3)
485
+ );
486
+ if (matchingGlob == null) {
487
+ return config.logger.warn(
488
+ `${relativePath} does not match any known entrypoint. Known entrypoints:
489
+ ${JSON.stringify(
490
+ PATH_GLOB_TO_TYPE_MAP,
491
+ null,
492
+ 2
493
+ )}`
494
+ );
495
+ }
496
+ const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
497
+ if (type === "ignored")
498
+ return;
499
+ let entrypoint;
500
+ switch (type) {
501
+ case "popup":
502
+ entrypoint = await getPopupEntrypoint(config, path5);
503
+ break;
504
+ case "options":
505
+ entrypoint = await getOptionsEntrypoint(config, path5);
506
+ break;
507
+ case "background":
508
+ entrypoint = await getBackgroundEntrypoint(config, path5);
509
+ break;
510
+ case "content-script":
511
+ entrypoint = await getContentScriptEntrypoint(
512
+ config,
513
+ relativePath.split(".", 2)[0],
514
+ path5
515
+ );
516
+ break;
517
+ default:
518
+ entrypoint = {
519
+ type,
520
+ name: getEntrypointName(config.entrypointsDir, path5),
521
+ inputPath: path5,
522
+ outputDir: config.outDir
523
+ };
524
+ }
525
+ const withSameName = existingNames[entrypoint.name];
526
+ if (withSameName) {
527
+ throw Error(
528
+ `Multiple entrypoints with the name "${entrypoint.name}" detected, but only one is allowed: ${[
529
+ (0, import_path5.relative)(config.root, withSameName.inputPath),
530
+ (0, import_path5.relative)(config.root, entrypoint.inputPath)
531
+ ].join(", ")}`
532
+ );
533
+ }
534
+ entrypoints.push(entrypoint);
535
+ existingNames[entrypoint.name] = entrypoint;
536
+ })
537
+ );
538
+ return entrypoints;
539
+ }
540
+ async function getPopupEntrypoint(config, path5) {
541
+ const options = {};
542
+ const content = await import_fs_extra4.default.readFile(path5, "utf-8");
543
+ const { document } = (0, import_linkedom2.parseHTML)(content);
544
+ const title = document.querySelector("title");
545
+ if (title != null)
546
+ options.defaultTitle = title.textContent ?? void 0;
547
+ const defaultIconContent = document.querySelector("meta[name='manifest.default_icon']")?.getAttribute("content");
548
+ if (defaultIconContent) {
549
+ try {
550
+ options.defaultIcon = import_json5.default.parse(defaultIconContent);
551
+ } catch (err) {
552
+ config.logger.fatal(
553
+ `Failed to parse default_icon meta tag content as JSON5. content=${defaultIconContent}`,
554
+ err
555
+ );
556
+ }
557
+ }
558
+ const mv2KeyContent = document.querySelector("meta[name='manifest.type']")?.getAttribute("content");
559
+ if (mv2KeyContent) {
560
+ options.mv2Key = mv2KeyContent === "page_action" ? "page_action" : "browser_action";
561
+ }
562
+ return {
563
+ type: "popup",
564
+ name: "popup",
565
+ options,
566
+ inputPath: path5,
567
+ outputDir: config.outDir
568
+ };
569
+ }
570
+ async function getOptionsEntrypoint(config, path5) {
571
+ const options = {};
572
+ const content = await import_fs_extra4.default.readFile(path5, "utf-8");
573
+ const { document } = (0, import_linkedom2.parseHTML)(content);
574
+ const openInTabContent = document.querySelector("meta[name='manifest.open_in_tab']")?.getAttribute("content");
575
+ if (openInTabContent) {
576
+ options.openInTab = Boolean(openInTabContent);
577
+ }
578
+ const chromeStyleContent = document.querySelector("meta[name='manifest.chrome_style']")?.getAttribute("content");
579
+ if (chromeStyleContent) {
580
+ options.chromeStyle = Boolean(chromeStyleContent);
581
+ }
582
+ const browserStyleContent = document.querySelector("meta[name='manifest.browser_style']")?.getAttribute("content");
583
+ if (browserStyleContent) {
584
+ options.browserStyle = Boolean(browserStyleContent);
585
+ }
586
+ return {
587
+ type: "options",
588
+ name: "options",
589
+ options,
590
+ inputPath: path5,
591
+ outputDir: config.outDir
592
+ };
593
+ }
594
+ async function getBackgroundEntrypoint(config, path5) {
595
+ const { main: _, ...options } = await importTsFile(config.root, path5);
596
+ if (options == null) {
597
+ throw Error("Background script does not have a default export");
598
+ }
599
+ return {
600
+ type: "background",
601
+ name: "background",
602
+ inputPath: path5,
603
+ outputDir: config.outDir,
604
+ options
605
+ };
606
+ }
607
+ async function getContentScriptEntrypoint(config, name, path5) {
608
+ const { main: _, ...options } = await importTsFile(
609
+ config.root,
610
+ path5
611
+ );
612
+ if (options == null) {
613
+ throw Error(`Content script ${name} does not have a default export`);
614
+ }
615
+ return {
616
+ type: "content-script",
617
+ name: getEntrypointName(config.entrypointsDir, path5),
618
+ inputPath: path5,
619
+ outputDir: (0, import_path5.resolve)(config.outDir, "content-scripts"),
620
+ options
621
+ };
622
+ }
623
+ var PATH_GLOB_TO_TYPE_MAP = {
624
+ "sandbox.html": "sandbox",
625
+ "sandbox/index.html": "sandbox",
626
+ "*.sandbox.html": "sandbox",
627
+ "*.sandbox/index.html": "sandbox",
628
+ "bookmarks.html": "bookmarks",
629
+ "bookmarks/index.html": "bookmarks",
630
+ "history.html": "history",
631
+ "history/index.html": "history",
632
+ "newtab.html": "newtab",
633
+ "newtab/index.html": "newtab",
634
+ "sidepanel.html": "sidepanel",
635
+ "sidepanel/index.html": "sidepanel",
636
+ "*.sidepanel.html": "sidepanel",
637
+ "*.sidepanel/index.html": "sidepanel",
638
+ "devtools.html": "devtools",
639
+ "devtools/index.html": "devtools",
640
+ "background.ts": "background",
641
+ "*.content.ts?(x)": "content-script",
642
+ "*.content/index.ts?(x)": "content-script",
643
+ "popup.html": "popup",
644
+ "popup/index.html": "popup",
645
+ "options.html": "options",
646
+ "options/index.html": "options",
647
+ "*.html": "unlisted-page",
648
+ "*/index.html": "unlisted-page",
649
+ "*.ts": "unlisted-script",
650
+ // Don't warn about any files in subdirectories, like CSS or JS entrypoints for HTML files
651
+ "*/*": "ignored"
652
+ };
653
+
654
+ // src/core/build/buildEntrypoints.ts
655
+ var vite2 = __toESM(require("vite"), 1);
656
+
657
+ // src/core/utils/groupEntrypoints.ts
658
+ function groupEntrypoints(entrypoints) {
659
+ const groupIndexMap = {};
660
+ const groups = [];
661
+ for (const entry of entrypoints) {
662
+ const group = ENTRY_TYPE_TO_GROUP_MAP[entry.type];
663
+ if (group === "no-group") {
664
+ groups.push(entry);
665
+ } else {
666
+ let groupIndex = groupIndexMap[group];
667
+ if (groupIndex == null) {
668
+ groupIndex = groups.push([]) - 1;
669
+ groupIndexMap[group] = groupIndex;
670
+ }
671
+ groups[groupIndex].push(entry);
672
+ }
673
+ }
674
+ return groups;
675
+ }
676
+ var ENTRY_TYPE_TO_GROUP_MAP = {
677
+ sandbox: "sandbox-page",
678
+ popup: "extension-page",
679
+ newtab: "extension-page",
680
+ history: "extension-page",
681
+ options: "extension-page",
682
+ devtools: "extension-page",
683
+ bookmarks: "extension-page",
684
+ sidepanel: "extension-page",
685
+ "unlisted-page": "extension-page",
686
+ background: "no-group",
687
+ "content-script": "no-group",
688
+ "unlisted-script": "no-group"
689
+ };
690
+
691
+ // src/core/utils/removeEmptyDirs.ts
692
+ var import_fs_extra5 = __toESM(require("fs-extra"), 1);
693
+ var import_path6 = __toESM(require("path"), 1);
694
+ async function removeEmptyDirs(dir) {
695
+ const files = await import_fs_extra5.default.readdir(dir);
696
+ for (const file of files) {
697
+ const filePath = import_path6.default.join(dir, file);
698
+ const stats = await import_fs_extra5.default.stat(filePath);
699
+ if (stats.isDirectory()) {
700
+ await removeEmptyDirs(filePath);
701
+ }
702
+ }
703
+ try {
704
+ await import_fs_extra5.default.rmdir(dir);
705
+ } catch {
706
+ }
707
+ }
708
+
709
+ // src/core/build/buildEntrypoints.ts
710
+ var import_fast_glob2 = __toESM(require("fast-glob"), 1);
711
+ var import_fs_extra6 = __toESM(require("fs-extra"), 1);
712
+ var import_path7 = require("path");
713
+ async function buildEntrypoints(entrypoints, config) {
714
+ const groups = groupEntrypoints(entrypoints);
715
+ const outputs = [];
716
+ for (const group of groups) {
717
+ const output = Array.isArray(group) ? await buildMultipleEntrypoints(group, config) : await buildSingleEntrypoint(group, config);
718
+ outputs.push(output);
719
+ }
720
+ const publicOutput = await copyPublicDirectory(config);
721
+ outputs.push(publicOutput);
722
+ await removeEmptyDirs(config.outDir);
723
+ return outputs.flat();
724
+ }
725
+ async function buildSingleEntrypoint(entrypoint, config) {
726
+ const isVirtual = ["background", "content-script"].includes(entrypoint.type);
727
+ const entry = isVirtual ? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}` : entrypoint.inputPath;
728
+ const libMode = {
729
+ build: {
730
+ lib: {
731
+ entry,
732
+ formats: ["iife"],
733
+ name: entrypoint.name,
734
+ fileName: entrypoint.name
735
+ },
736
+ rollupOptions: {
737
+ output: {
738
+ entryFileNames: getEntrypointBundlePath(
739
+ entrypoint,
740
+ config.outDir,
741
+ ".js"
742
+ ),
743
+ // Output content script CSS to assets/ with a hash to prevent conflicts. Defaults to
744
+ // "[name].[ext]" in lib mode, which usually results in "style.css". That means multiple
745
+ // content scripts with styles would overwrite each other if it weren't changed below.
746
+ assetFileNames: `assets/${entrypoint.name}-[hash].[ext]`
747
+ }
748
+ }
749
+ }
750
+ };
751
+ const entryConfig = vite2.mergeConfig(
752
+ libMode,
753
+ config.vite
754
+ );
755
+ const result = await vite2.build(entryConfig);
756
+ return getBuildOutput(result);
757
+ }
758
+ async function buildMultipleEntrypoints(entrypoints, config) {
759
+ const multiPage = {
760
+ plugins: [multipageMove(entrypoints, config)],
761
+ build: {
762
+ rollupOptions: {
763
+ input: entrypoints.reduce((input, entry) => {
764
+ input[entry.name] = entry.inputPath;
765
+ return input;
766
+ }, {})
767
+ }
768
+ }
769
+ };
770
+ const entryConfig = vite2.mergeConfig(
771
+ multiPage,
772
+ config.vite
773
+ );
774
+ const result = await vite2.build(entryConfig);
775
+ return getBuildOutput(result);
776
+ }
777
+ function getBuildOutput(result) {
778
+ if ("on" in result)
779
+ throw Error("wxt does not support vite watch mode.");
780
+ if (Array.isArray(result))
781
+ return result.flatMap(({ output }) => output);
782
+ return result.output;
783
+ }
784
+ async function copyPublicDirectory(config) {
785
+ if (!await import_fs_extra6.default.exists(config.publicDir))
786
+ return [];
787
+ const files = await (0, import_fast_glob2.default)("**/*", { cwd: config.publicDir });
788
+ const outputs = [];
789
+ for (const file of files) {
790
+ const srcPath = (0, import_path7.resolve)(config.publicDir, file);
791
+ const outPath = (0, import_path7.resolve)(config.outDir, file);
792
+ await import_fs_extra6.default.ensureDir((0, import_path7.dirname)(outPath));
793
+ await import_fs_extra6.default.copyFile(srcPath, outPath);
794
+ outputs.push({
795
+ type: "asset",
796
+ fileName: file,
797
+ name: file,
798
+ needsCodeReference: false,
799
+ source: await import_fs_extra6.default.readFile(srcPath)
800
+ });
801
+ }
802
+ return outputs;
803
+ }
804
+
805
+ // src/core/utils/manifest.ts
806
+ var import_fs_extra7 = __toESM(require("fs-extra"), 1);
807
+ var import_path8 = require("path");
808
+
809
+ // src/core/utils/ContentSecurityPolicy.ts
810
+ var ContentSecurityPolicy = class _ContentSecurityPolicy {
811
+ static DIRECTIVE_ORDER = {
812
+ "default-src": 0,
813
+ "script-src": 1,
814
+ "object-src": 2
815
+ };
816
+ data;
817
+ constructor(csp) {
818
+ if (csp) {
819
+ const sections = csp.split(";").map((section) => section.trim());
820
+ this.data = sections.reduce((data, section) => {
821
+ const [key, ...values] = section.split(" ").map((item) => item.trim());
822
+ if (key)
823
+ data[key] = values;
824
+ return data;
825
+ }, {});
826
+ } else {
827
+ this.data = {};
828
+ }
829
+ }
830
+ /**
831
+ * Ensure a set of values are listed under a directive.
832
+ */
833
+ add(directive, ...newValues) {
834
+ const values = this.data[directive] ?? [];
835
+ newValues.forEach((newValue) => {
836
+ if (!values.includes(newValue))
837
+ values.push(newValue);
838
+ });
839
+ this.data[directive] = values;
840
+ return this;
841
+ }
842
+ toString() {
843
+ const directives = Object.entries(this.data).sort(([l], [r]) => {
844
+ const lo = _ContentSecurityPolicy.DIRECTIVE_ORDER[l] ?? 2;
845
+ const ro = _ContentSecurityPolicy.DIRECTIVE_ORDER[r] ?? 2;
846
+ return lo - ro;
847
+ });
848
+ return directives.map((entry) => entry.flat().join(" ")).join("; ") + ";";
849
+ }
850
+ };
851
+
852
+ // src/core/utils/manifest.ts
853
+ async function writeManifest(manifest, output, config) {
854
+ const str = config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
855
+ await import_fs_extra7.default.ensureDir(config.outDir);
856
+ await import_fs_extra7.default.writeFile((0, import_path8.resolve)(config.outDir, "manifest.json"), str, "utf-8");
857
+ output.unshift({
858
+ type: "asset",
859
+ fileName: "manifest.json",
860
+ name: "manifest",
861
+ needsCodeReference: false,
862
+ source: str
863
+ });
864
+ }
865
+ async function generateMainfest(entrypoints, buildOutput, config) {
866
+ const pkg = await getPackageJson(config);
867
+ if (pkg.version == null)
868
+ throw Error("package.json does not include a version");
869
+ if (pkg.name == null)
870
+ throw Error("package.json does not include a name");
871
+ if (pkg.description == null)
872
+ throw Error("package.json does not include a description");
873
+ const manifest = {
874
+ manifest_version: config.manifestVersion,
875
+ name: pkg.name,
876
+ short_name: pkg.shortName,
877
+ version: simplifyVersion(pkg.version),
878
+ version_name: config.browser === "firefox" ? void 0 : pkg.version,
879
+ ...config.manifest
880
+ };
881
+ addEntrypoints(manifest, entrypoints, buildOutput, config);
882
+ if (config.command === "serve")
883
+ addDevModeCsp(manifest, config);
884
+ return manifest;
885
+ }
886
+ async function getPackageJson(config) {
887
+ return await import_fs_extra7.default.readJson((0, import_path8.resolve)(config.root, "package.json"));
888
+ }
889
+ function simplifyVersion(versionName) {
890
+ const version3 = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(
891
+ versionName
892
+ )?.[1];
893
+ if (version3 == null)
894
+ throw Error(
895
+ `Cannot simplify package.json version "${versionName}" to a valid extension version, "X.Y.Z"`
896
+ );
897
+ return version3;
898
+ }
899
+ function addEntrypoints(manifest, entrypoints, buildOutput, config) {
900
+ const entriesByType = entrypoints.reduce((map, entrypoint) => {
901
+ map[entrypoint.type] ??= [];
902
+ map[entrypoint.type]?.push(entrypoint);
903
+ return map;
904
+ }, {});
905
+ const background = entriesByType["background"]?.[0];
906
+ const bookmarks = entriesByType["bookmarks"]?.[0];
907
+ const contentScripts = entriesByType["content-script"];
908
+ const devtools = entriesByType["devtools"]?.[0];
909
+ const history = entriesByType["history"]?.[0];
910
+ const newtab = entriesByType["newtab"]?.[0];
911
+ const options = entriesByType["options"]?.[0];
912
+ const popup = entriesByType["popup"]?.[0];
913
+ const sandboxes = entriesByType["sandbox"];
914
+ const sidepanels = entriesByType["sidepanel"];
915
+ if (background) {
916
+ const script = getEntrypointBundlePath(background, config.outDir, ".js");
917
+ if (manifest.manifest_version === 3) {
918
+ manifest.background = {
919
+ type: background.options.type,
920
+ service_worker: script
921
+ };
922
+ } else {
923
+ manifest.background = {
924
+ persistent: background.options.persistent,
925
+ scripts: [script]
926
+ };
927
+ }
928
+ }
929
+ if (bookmarks) {
930
+ if (config.browser === "firefox") {
931
+ config.logger.warn(
932
+ "Bookmarks are not supported by Firefox. chrome_url_overrides.bookmarks was not added to the manifest"
933
+ );
934
+ } else {
935
+ manifest.chrome_url_overrides ??= {};
936
+ manifest.chrome_url_overrides.bookmarks = getEntrypointBundlePath(
937
+ bookmarks,
938
+ config.outDir,
939
+ ".html"
940
+ );
941
+ }
942
+ }
943
+ if (history) {
944
+ if (config.browser === "firefox") {
945
+ config.logger.warn(
946
+ "Bookmarks are not supported by Firefox. chrome_url_overrides.history was not added to the manifest"
947
+ );
948
+ } else {
949
+ manifest.chrome_url_overrides ??= {};
950
+ manifest.chrome_url_overrides.history = getEntrypointBundlePath(
951
+ history,
952
+ config.outDir,
953
+ ".html"
954
+ );
955
+ }
956
+ }
957
+ if (newtab) {
958
+ manifest.chrome_url_overrides ??= {};
959
+ manifest.chrome_url_overrides.newtab = getEntrypointBundlePath(
960
+ newtab,
961
+ config.outDir,
962
+ ".html"
963
+ );
964
+ }
965
+ if (popup) {
966
+ const default_popup = getEntrypointBundlePath(
967
+ popup,
968
+ config.outDir,
969
+ ".html"
970
+ );
971
+ const options2 = {
972
+ default_icon: popup.options.defaultIcon,
973
+ default_title: popup.options.defaultTitle
974
+ };
975
+ if (manifest.manifest_version === 3) {
976
+ manifest.action = {
977
+ ...options2,
978
+ default_popup
979
+ };
980
+ } else {
981
+ manifest[popup.options.mv2Key ?? "browser_action"] = {
982
+ ...options2,
983
+ default_popup
984
+ };
985
+ }
986
+ }
987
+ if (devtools) {
988
+ manifest.devtools_page = getEntrypointBundlePath(
989
+ devtools,
990
+ config.outDir,
991
+ ".html"
992
+ );
993
+ }
994
+ if (options) {
995
+ const page = getEntrypointBundlePath(options, config.outDir, ".html");
996
+ manifest.options_ui = {
997
+ open_in_tab: options.options.openInTab,
998
+ browser_style: config.browser === "firefox" ? options.options.browserStyle : void 0,
999
+ chrome_style: config.browser !== "firefox" ? options.options.chromeStyle : void 0,
1000
+ page
1001
+ };
1002
+ }
1003
+ if (sandboxes?.length) {
1004
+ if (config.browser === "firefox") {
1005
+ config.logger.warn(
1006
+ "Sandboxed pages not supported by Firefox. sandbox.pages was not added to the manifest"
1007
+ );
1008
+ } else {
1009
+ manifest.sandbox = {
1010
+ pages: sandboxes.map(
1011
+ (entry) => getEntrypointBundlePath(entry, config.outDir, ".html")
1012
+ )
1013
+ };
1014
+ }
1015
+ }
1016
+ if (sidepanels?.length) {
1017
+ const defaultSidepanel = sidepanels.find((entry) => entry.name === "sidepanel") ?? sidepanels[0];
1018
+ const page = getEntrypointBundlePath(
1019
+ defaultSidepanel,
1020
+ config.outDir,
1021
+ ".html"
1022
+ );
1023
+ if (config.browser === "firefox") {
1024
+ manifest.sidebar_action = {
1025
+ // TODO: Add options to side panel
1026
+ // ...defaultSidepanel.options,
1027
+ default_panel: page
1028
+ };
1029
+ } else if (config.manifestVersion === 3) {
1030
+ manifest.side_panel = {
1031
+ default_path: page
1032
+ };
1033
+ } else {
1034
+ config.logger.warn(
1035
+ "Side panel not supported by Chromium using MV2. side_panel.default_path was not added to the manifest"
1036
+ );
1037
+ }
1038
+ }
1039
+ if (contentScripts?.length) {
1040
+ if (config.command === "serve") {
1041
+ const permissionsKey = config.manifestVersion === 2 ? "permissions" : "host_permissions";
1042
+ const hostPermissions = new Set(manifest[permissionsKey] ?? []);
1043
+ contentScripts.forEach((script) => {
1044
+ script.options.matches.forEach((matchPattern) => {
1045
+ hostPermissions.add(matchPattern);
1046
+ });
1047
+ });
1048
+ manifest[permissionsKey] = Array.from(hostPermissions).sort();
1049
+ } else {
1050
+ const hashToEntrypointsMap = contentScripts.reduce((map, script) => {
1051
+ const hash = JSON.stringify(script.options);
1052
+ if (!map.has(hash)) {
1053
+ map.set(hash, [script]);
1054
+ } else {
1055
+ map.get(hash)?.push(script);
1056
+ }
1057
+ return map;
1058
+ }, /* @__PURE__ */ new Map());
1059
+ manifest.content_scripts = Array.from(hashToEntrypointsMap.entries()).map(
1060
+ ([, scripts]) => ({
1061
+ ...scripts[0].options,
1062
+ // TOOD: Sorting css and js arrays here so we get consistent test results... but we
1063
+ // shouldn't have to. Where is the inconsistency coming from?
1064
+ css: getContentScriptCssFiles(scripts, buildOutput)?.sort(),
1065
+ js: scripts.map(
1066
+ (entry) => getEntrypointBundlePath(entry, config.outDir, ".js")
1067
+ ).sort()
1068
+ })
1069
+ );
1070
+ }
1071
+ }
1072
+ }
1073
+ function addDevModeCsp(manifest, config) {
1074
+ const permission = `http://${config.server?.hostname ?? ""}/*`;
1075
+ const allowedCsp = config.server?.origin ?? "http://localhost:*";
1076
+ if (manifest.manifest_version === 3) {
1077
+ manifest.host_permissions ??= [];
1078
+ if (!manifest.host_permissions.includes(permission))
1079
+ manifest.host_permissions.push(permission);
1080
+ } else {
1081
+ manifest.permissions ??= [];
1082
+ if (!manifest.permissions.includes(permission))
1083
+ manifest.permissions.push(permission);
1084
+ }
1085
+ const csp = new ContentSecurityPolicy(
1086
+ manifest.manifest_version === 3 ? (
1087
+ // @ts-expect-error: extension_pages is not typed
1088
+ manifest.content_security_policy?.extension_pages ?? "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
1089
+ ) : manifest.content_security_policy ?? "script-src 'self'; object-src 'self';"
1090
+ // default CSP for MV2
1091
+ );
1092
+ if (config.server)
1093
+ csp.add("script-src", allowedCsp);
1094
+ if (manifest.manifest_version === 3) {
1095
+ manifest.content_security_policy ??= {};
1096
+ manifest.content_security_policy.extension_pages = csp.toString();
1097
+ } else {
1098
+ manifest.content_security_policy = csp.toString();
1099
+ }
1100
+ }
1101
+ function getContentScriptCssFiles(contentScripts, buildOutput) {
1102
+ const css = [];
1103
+ contentScripts.forEach((script) => {
1104
+ const cssRegex = new RegExp(`^assets/${script.name}-[a-f0-9]{8}.css$`);
1105
+ const relatedCss = buildOutput.find(
1106
+ (chunk) => chunk.fileName.match(cssRegex)
1107
+ );
1108
+ if (relatedCss)
1109
+ css.push(relatedCss.fileName);
1110
+ });
1111
+ if (css.length > 0)
1112
+ return css;
1113
+ return void 0;
1114
+ }
1115
+
1116
+ // src/core/log/printBuildSummary.ts
1117
+ var import_path9 = __toESM(require("path"), 1);
1118
+
1119
+ // src/core/log/printTable.ts
1120
+ function printTable(log, rows, gap = 2) {
1121
+ if (rows.length === 0)
1122
+ return;
1123
+ const columnWidths = rows.reduce(
1124
+ (widths, row) => {
1125
+ for (let i = 0; i < Math.max(widths.length, row.length); i++) {
1126
+ widths[i] = Math.max(row[i]?.length ?? 0, widths[i] ?? 0);
1127
+ }
1128
+ return widths;
1129
+ },
1130
+ rows[0].map((column) => column.length)
1131
+ );
1132
+ let str = "";
1133
+ rows.forEach((row, i) => {
1134
+ row.forEach((col, j) => {
1135
+ str += col.padEnd(columnWidths[j], " ");
1136
+ if (j !== row.length - 1)
1137
+ str += "".padEnd(gap, " ");
1138
+ });
1139
+ if (i !== rows.length - 1)
1140
+ str += "\n";
1141
+ });
1142
+ log(str);
1143
+ }
1144
+
1145
+ // src/core/log/printBuildSummary.ts
1146
+ var import_picocolors = __toESM(require("picocolors"), 1);
1147
+ var import_fs_extra8 = __toESM(require("fs-extra"), 1);
1148
+ var import_filesize = require("filesize");
1149
+ async function printBuildSummary(output, config) {
1150
+ const chunks = output.sort((l, r) => {
1151
+ const lWeight = CHUNK_SORT_WEIGHTS[l.fileName] ?? CHUNK_SORT_WEIGHTS[(0, import_path9.extname)(l.fileName)] ?? DEFAULT_SORT_WEIGHT;
1152
+ const rWeight = CHUNK_SORT_WEIGHTS[r.fileName] ?? CHUNK_SORT_WEIGHTS[(0, import_path9.extname)(r.fileName)] ?? DEFAULT_SORT_WEIGHT;
1153
+ const diff = lWeight - rWeight;
1154
+ if (diff !== 0)
1155
+ return diff;
1156
+ return l.fileName.localeCompare(r.fileName);
1157
+ });
1158
+ let totalSize = 0;
1159
+ const chunkRows = await Promise.all(
1160
+ chunks.map(async (chunk, i) => {
1161
+ const file = [
1162
+ (0, import_path9.relative)(process.cwd(), config.outDir) + import_path9.default.sep,
1163
+ chunk.fileName
1164
+ ];
1165
+ const ext = (0, import_path9.extname)(chunk.fileName);
1166
+ const prefix = i === chunks.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
1167
+ const color = CHUNK_COLORS[ext] ?? DEFAULT_COLOR;
1168
+ const stats = await import_fs_extra8.default.lstat((0, import_path9.resolve)(config.outDir, chunk.fileName));
1169
+ totalSize += stats.size;
1170
+ const size = String((0, import_filesize.filesize)(stats.size));
1171
+ return [
1172
+ `${import_picocolors.default.gray(prefix)} ${import_picocolors.default.dim(file[0])}${color(file[1])}`,
1173
+ import_picocolors.default.dim(size)
1174
+ ];
1175
+ })
1176
+ );
1177
+ printTable(config.logger.log, chunkRows);
1178
+ config.logger.log(
1179
+ `${import_picocolors.default.cyan("\u03A3 Total size:")} ${String((0, import_filesize.filesize)(totalSize))}`
1180
+ );
1181
+ }
1182
+ var DEFAULT_SORT_WEIGHT = 100;
1183
+ var CHUNK_SORT_WEIGHTS = {
1184
+ "manifest.json": 0,
1185
+ ".html": 1,
1186
+ ".js": 2,
1187
+ ".css": 3
1188
+ };
1189
+ var DEFAULT_COLOR = import_picocolors.default.blue;
1190
+ var CHUNK_COLORS = {
1191
+ ".html": import_picocolors.default.green,
1192
+ ".css": import_picocolors.default.magenta,
1193
+ ".js": import_picocolors.default.cyan
1194
+ };
1195
+
1196
+ // src/index.ts
1197
+ var import_fs_extra10 = __toESM(require("fs-extra"), 1);
1198
+
1199
+ // src/core/build/generateTypesDir.ts
1200
+ var import_unimport3 = require("unimport");
1201
+ var import_fs_extra9 = __toESM(require("fs-extra"), 1);
1202
+ var import_path10 = require("path");
1203
+ async function generateTypesDir(entrypoints, config) {
1204
+ await import_fs_extra9.default.ensureDir(config.typesDir);
1205
+ const references = [];
1206
+ references.push(await writeImportsDeclarationFile(config));
1207
+ references.push(await writePathsDeclarationFile(entrypoints, config));
1208
+ references.push(await writeGlobalsDeclarationFile(config));
1209
+ const mainReference = await writeMainDeclarationFile(references, config);
1210
+ await writeTsConfigFile(mainReference, config);
1211
+ }
1212
+ async function writeImportsDeclarationFile(config) {
1213
+ const filePath = (0, import_path10.resolve)(config.typesDir, "imports.d.ts");
1214
+ const unimport2 = (0, import_unimport3.createUnimport)(getUnimportOptions(config));
1215
+ await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
1216
+ await import_fs_extra9.default.writeFile(
1217
+ filePath,
1218
+ ["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
1219
+ "\n"
1220
+ ) + "\n"
1221
+ );
1222
+ return filePath;
1223
+ }
1224
+ async function writePathsDeclarationFile(entrypoints, config) {
1225
+ const filePath = (0, import_path10.resolve)(config.typesDir, "paths.d.ts");
1226
+ await import_fs_extra9.default.writeFile(
1227
+ filePath,
1228
+ [
1229
+ "// Generated by wxt",
1230
+ "type EntrypointPath =",
1231
+ ...entrypoints.map((entry) => {
1232
+ const path5 = getEntrypointBundlePath(
1233
+ entry,
1234
+ config.outDir,
1235
+ entry.inputPath.endsWith(".html") ? ".html" : ".js"
1236
+ );
1237
+ return ` | "/${path5}"`;
1238
+ }).sort()
1239
+ ].join("\n") + "\n"
1240
+ );
1241
+ return filePath;
1242
+ }
1243
+ async function writeGlobalsDeclarationFile(config) {
1244
+ const filePath = (0, import_path10.resolve)(config.typesDir, "globals.d.ts");
1245
+ const globals = getGlobals(config);
1246
+ await import_fs_extra9.default.writeFile(
1247
+ filePath,
1248
+ [
1249
+ "// Generated by wxt",
1250
+ "export {}",
1251
+ "declare global {",
1252
+ ...globals.map((global) => ` const ${global.name}: ${global.type};`),
1253
+ "}"
1254
+ ].join("\n") + "\n",
1255
+ "utf-8"
1256
+ );
1257
+ return filePath;
1258
+ }
1259
+ async function writeMainDeclarationFile(references, config) {
1260
+ const dir = config.wxtDir;
1261
+ const filePath = (0, import_path10.resolve)(dir, "wxt.d.ts");
1262
+ await import_fs_extra9.default.writeFile(
1263
+ filePath,
1264
+ [
1265
+ "// Generated by wxt",
1266
+ ...references.map(
1267
+ (ref) => `/// <reference types="./${(0, import_path10.relative)(dir, ref)}" />`
1268
+ )
1269
+ ].join("\n") + "\n"
1270
+ );
1271
+ return filePath;
1272
+ }
1273
+ async function writeTsConfigFile(mainReference, config) {
1274
+ const dir = config.wxtDir;
1275
+ await import_fs_extra9.default.writeFile(
1276
+ (0, import_path10.resolve)(dir, "tsconfig.json"),
1277
+ `{
1278
+ "compilerOptions": {
1279
+ "target": "ESNext",
1280
+ "module": "ESNext",
1281
+ "moduleResolution": "Bundler",
1282
+ "noEmit": true,
1283
+ "esModuleInterop": true,
1284
+ "forceConsistentCasingInFileNames": true,
1285
+ "resolveJsonModule": true,
1286
+
1287
+ /* Type Checking */
1288
+ "strict": true,
1289
+
1290
+ /* Completeness */
1291
+ "skipLibCheck": true
1292
+ },
1293
+ "include": [
1294
+ "${(0, import_path10.relative)(dir, config.root)}/**/*",
1295
+ "./${(0, import_path10.relative)(dir, mainReference)}"
1296
+ ],
1297
+ "exclude": ["${(0, import_path10.relative)(dir, config.outBaseDir)}"]
1298
+ }`
1299
+ );
1300
+ }
1301
+
1302
+ // src/index.ts
1303
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
1304
+ var vite3 = __toESM(require("vite"), 1);
1305
+
1306
+ // src/core/utils/findOpenPort.ts
1307
+ var import_node_net = __toESM(require("net"), 1);
1308
+ function findOpenPort(startPort, endPort) {
1309
+ return findOpenPortRecursive(startPort, startPort, endPort);
1310
+ }
1311
+ function findOpenPortRecursive(port, startPort, endPort) {
1312
+ return new Promise((resolve13, reject) => {
1313
+ if (port > endPort)
1314
+ return reject(
1315
+ Error(`Could not find open port between ${startPort}-${endPort}`)
1316
+ );
1317
+ const server = import_node_net.default.createServer();
1318
+ server.listen(port, () => {
1319
+ server.once("close", () => resolve13(port));
1320
+ server.close();
1321
+ });
1322
+ server.on(
1323
+ "error",
1324
+ () => resolve13(findOpenPortRecursive(port + 1, startPort, endPort))
1325
+ );
1326
+ });
1327
+ }
1328
+
1329
+ // src/core/utils/formatDuration.ts
1330
+ function formatDuration(duration) {
1331
+ if (duration < 1e3)
1332
+ return `${duration} ms`;
1333
+ if (duration < 1e4)
1334
+ return `${(duration / 1e3).toFixed(3)} s`;
1335
+ if (duration < 6e4)
1336
+ return `${(duration / 1e3).toFixed(1)} s`;
1337
+ return `${(duration / 1e3).toFixed(0)} s`;
1338
+ }
1339
+
1340
+ // src/core/runners/createWebExtRunner.ts
1341
+ function createWebExtRunner() {
1342
+ let runner;
1343
+ return {
1344
+ async openBrowser(config) {
1345
+ if (config.browser === "safari") {
1346
+ config.logger.warn("Cannot open safari automatically.");
1347
+ return;
1348
+ }
1349
+ const webExtLogger = await import("web-ext/util/logger");
1350
+ webExtLogger.consoleStream.write = ({ level, msg, name }) => {
1351
+ if (level >= ERROR_LOG_LEVEL)
1352
+ config.logger.error(name, msg);
1353
+ if (level >= WARN_LOG_LEVEL)
1354
+ config.logger.warn(msg);
1355
+ };
1356
+ const wxtUserConfig = config.runnerConfig.config;
1357
+ const userConfig = {
1358
+ console: wxtUserConfig?.openConsole,
1359
+ devtools: wxtUserConfig?.openDevtools,
1360
+ startUrl: wxtUserConfig?.startUrls,
1361
+ ...config.browser === "firefox" ? {
1362
+ firefox: wxtUserConfig?.binaries?.firefox,
1363
+ firefoxProfile: wxtUserConfig?.firefoxProfile,
1364
+ prefs: wxtUserConfig?.firefoxPrefs,
1365
+ args: wxtUserConfig?.firefoxArgs
1366
+ } : {
1367
+ chromiumBinary: wxtUserConfig?.binaries?.[config.browser],
1368
+ chromiumProfile: wxtUserConfig?.chromiumProfile,
1369
+ args: wxtUserConfig?.chromiumArgs
1370
+ }
1371
+ };
1372
+ const finalConfig = {
1373
+ ...userConfig,
1374
+ target: config.browser === "firefox" ? "firefox-desktop" : "chromium",
1375
+ sourceDir: config.outDir,
1376
+ // WXT handles reloads, so disable auto-reload behaviors in web-ext
1377
+ noReload: true,
1378
+ noInput: true
1379
+ };
1380
+ const options = {
1381
+ // Don't call `process.exit(0)` after starting web-ext
1382
+ shouldExitProgram: false
1383
+ };
1384
+ config.logger.debug("web-ext config:", finalConfig);
1385
+ config.logger.debug("web-ext options:", options);
1386
+ const webExt = await import("web-ext");
1387
+ runner = await webExt.default.cmd.run(finalConfig, options);
1388
+ },
1389
+ async closeBrowser() {
1390
+ return await runner?.exit();
1391
+ }
1392
+ };
1393
+ }
1394
+ var WARN_LOG_LEVEL = 40;
1395
+ var ERROR_LOG_LEVEL = 50;
1396
+
1397
+ // package.json
1398
+ var version = "0.0.1";
1399
+
1400
+ // src/core/utils/defineConfig.ts
1401
+ function defineConfig(config) {
1402
+ return config;
1403
+ }
1404
+
1405
+ // src/core/utils/defineRunnerConfig.ts
1406
+ function defineRunnerConfig(config) {
1407
+ return config;
1408
+ }
1409
+
1410
+ // src/index.ts
1411
+ async function build2(config) {
1412
+ const internalConfig = await getInternalConfig(config, "build");
1413
+ return await buildInternal(internalConfig);
1414
+ }
1415
+ async function createServer2(config) {
1416
+ const port = await findOpenPort(3e3, 3010);
1417
+ const hostname = "localhost";
1418
+ const origin = `http://${hostname}:${port}`;
1419
+ const serverConfig = {
1420
+ server: {
1421
+ origin
1422
+ }
1423
+ };
1424
+ const internalConfig = await getInternalConfig(
1425
+ vite3.mergeConfig(serverConfig, config ?? {}),
1426
+ "serve"
1427
+ );
1428
+ const runner = createWebExtRunner();
1429
+ const viteServer = await vite3.createServer(internalConfig.vite);
1430
+ const server = {
1431
+ ...viteServer,
1432
+ async listen(port2, isRestart) {
1433
+ const res = await viteServer.listen(port2, isRestart);
1434
+ if (!isRestart) {
1435
+ internalConfig.logger.success(`Started dev server @ ${origin}`);
1436
+ internalConfig.logger.info("Opening browser...");
1437
+ await runner.openBrowser(internalConfig);
1438
+ internalConfig.logger.success("Opened!");
1439
+ }
1440
+ return res;
1441
+ },
1442
+ logger: internalConfig.logger,
1443
+ port,
1444
+ hostname,
1445
+ origin
1446
+ };
1447
+ internalConfig.logger.info("Created dev server");
1448
+ internalConfig.server = server;
1449
+ await buildInternal(internalConfig);
1450
+ return server;
1451
+ }
1452
+ async function buildInternal(config) {
1453
+ const verb = config.command === "serve" ? "Pre-rendering" : "Building";
1454
+ const target = `${config.browser}-mv${config.manifestVersion}`;
1455
+ config.logger.info(
1456
+ `${verb} ${import_picocolors2.default.cyan(target)} for ${import_picocolors2.default.cyan(config.mode)} with ${import_picocolors2.default.green(
1457
+ `Vite ${vite3.version}`
1458
+ )}`
1459
+ );
1460
+ const startTime = Date.now();
1461
+ await import_fs_extra10.default.rm(config.outDir, { recursive: true, force: true });
1462
+ await import_fs_extra10.default.ensureDir(config.outDir);
1463
+ const entrypoints = await findEntrypoints(config);
1464
+ await generateTypesDir(entrypoints, config);
1465
+ const output = await buildEntrypoints(entrypoints, config);
1466
+ const manifest = await generateMainfest(entrypoints, output, config);
1467
+ await writeManifest(manifest, output, config);
1468
+ config.logger.success(
1469
+ `Built extension in ${formatDuration(Date.now() - startTime)}`
1470
+ );
1471
+ await printBuildSummary(output, config);
1472
+ return output;
1473
+ }
1474
+ // Annotate the CommonJS export names for ESM import in node:
1475
+ 0 && (module.exports = {
1476
+ build,
1477
+ createServer,
1478
+ defineConfig,
1479
+ defineRunnerConfig,
1480
+ version
1481
+ });
1482
+ //# sourceMappingURL=index.cjs.map