wxt 0.17.8 → 0.17.10
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/{chunk-5XQOZCZF.js → chunk-2SH4GQGN.js} +1567 -1600
- package/dist/cli.js +1584 -1613
- package/dist/{index-cFBbMXAl.d.cts → index-w7ohFTEX.d.cts} +41 -15
- package/dist/{index-cFBbMXAl.d.ts → index-w7ohFTEX.d.ts} +41 -15
- package/dist/index.cjs +1575 -1609
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +55 -58
- package/dist/testing.cjs +74 -690
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +5 -9
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import cac from "cac";
|
|
8
8
|
|
|
9
9
|
// src/core/utils/fs.ts
|
|
10
|
-
import
|
|
10
|
+
import fs3 from "fs-extra";
|
|
11
11
|
import glob from "fast-glob";
|
|
12
12
|
|
|
13
13
|
// src/core/utils/paths.ts
|
|
@@ -230,206 +230,15 @@ var packageManagers = {
|
|
|
230
230
|
yarn
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
-
// src/core/wxt.ts
|
|
234
|
-
var wxt;
|
|
235
|
-
async function registerWxt(command, inlineConfig = {}, server) {
|
|
236
|
-
const config = await resolveConfig(inlineConfig, command, server);
|
|
237
|
-
const hooks = createHooks();
|
|
238
|
-
const pm = await createWxtPackageManager(config.root);
|
|
239
|
-
wxt = {
|
|
240
|
-
config,
|
|
241
|
-
hooks,
|
|
242
|
-
get logger() {
|
|
243
|
-
return config.logger;
|
|
244
|
-
},
|
|
245
|
-
async reloadConfig() {
|
|
246
|
-
wxt.config = await resolveConfig(inlineConfig, command, server);
|
|
247
|
-
},
|
|
248
|
-
pm
|
|
249
|
-
};
|
|
250
|
-
wxt.hooks.addHooks(config.hooks);
|
|
251
|
-
await wxt.hooks.callHook("ready", wxt);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// src/core/utils/fs.ts
|
|
255
|
-
async function writeFileIfDifferent(file, newContents) {
|
|
256
|
-
const existingContents = await fs.readFile(file, "utf-8").catch(() => void 0);
|
|
257
|
-
if (existingContents !== newContents) {
|
|
258
|
-
await fs.writeFile(file, newContents);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
async function getPublicFiles() {
|
|
262
|
-
if (!await fs.exists(wxt.config.publicDir))
|
|
263
|
-
return [];
|
|
264
|
-
const files = await glob("**/*", { cwd: wxt.config.publicDir });
|
|
265
|
-
return files.map(unnormalizePath);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// src/core/utils/building/build-entrypoints.ts
|
|
269
|
-
import fs2 from "fs-extra";
|
|
270
|
-
import { dirname, resolve } from "path";
|
|
271
|
-
import pc from "picocolors";
|
|
272
|
-
async function buildEntrypoints(groups, spinner) {
|
|
273
|
-
const steps = [];
|
|
274
|
-
for (let i = 0; i < groups.length; i++) {
|
|
275
|
-
const group = groups[i];
|
|
276
|
-
const groupNames = [group].flat().map((e) => e.name);
|
|
277
|
-
const groupNameColored = groupNames.join(pc.dim(", "));
|
|
278
|
-
spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
|
279
|
-
try {
|
|
280
|
-
steps.push(await wxt.config.builder.build(group));
|
|
281
|
-
} catch (err) {
|
|
282
|
-
spinner.stop().clear();
|
|
283
|
-
wxt.logger.error(err);
|
|
284
|
-
throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
const publicAssets = await copyPublicDirectory();
|
|
288
|
-
return { publicAssets, steps };
|
|
289
|
-
}
|
|
290
|
-
async function copyPublicDirectory() {
|
|
291
|
-
const files = await getPublicFiles();
|
|
292
|
-
if (files.length === 0)
|
|
293
|
-
return [];
|
|
294
|
-
const publicAssets = [];
|
|
295
|
-
for (const file of files) {
|
|
296
|
-
const srcPath = resolve(wxt.config.publicDir, file);
|
|
297
|
-
const outPath = resolve(wxt.config.outDir, file);
|
|
298
|
-
await fs2.ensureDir(dirname(outPath));
|
|
299
|
-
await fs2.copyFile(srcPath, outPath);
|
|
300
|
-
publicAssets.push({
|
|
301
|
-
type: "asset",
|
|
302
|
-
fileName: file
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
return publicAssets;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// src/core/utils/arrays.ts
|
|
309
|
-
function every(array, predicate) {
|
|
310
|
-
for (let i = 0; i < array.length; i++)
|
|
311
|
-
if (!predicate(array[i], i))
|
|
312
|
-
return false;
|
|
313
|
-
return true;
|
|
314
|
-
}
|
|
315
|
-
function some(array, predicate) {
|
|
316
|
-
for (let i = 0; i < array.length; i++)
|
|
317
|
-
if (predicate(array[i], i))
|
|
318
|
-
return true;
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// src/core/utils/building/detect-dev-changes.ts
|
|
323
|
-
function detectDevChanges(changedFiles, currentOutput) {
|
|
324
|
-
const isConfigChange = some(
|
|
325
|
-
changedFiles,
|
|
326
|
-
(file) => file === wxt.config.userConfigMetadata.configFile
|
|
327
|
-
);
|
|
328
|
-
if (isConfigChange)
|
|
329
|
-
return { type: "full-restart" };
|
|
330
|
-
const isRunnerChange = some(
|
|
331
|
-
changedFiles,
|
|
332
|
-
(file) => file === wxt.config.runnerConfig.configFile
|
|
333
|
-
);
|
|
334
|
-
if (isRunnerChange)
|
|
335
|
-
return { type: "browser-restart" };
|
|
336
|
-
const changedSteps = new Set(
|
|
337
|
-
changedFiles.flatMap(
|
|
338
|
-
(changedFile) => findEffectedSteps(changedFile, currentOutput)
|
|
339
|
-
)
|
|
340
|
-
);
|
|
341
|
-
if (changedSteps.size === 0)
|
|
342
|
-
return { type: "no-change" };
|
|
343
|
-
const unchangedOutput = {
|
|
344
|
-
manifest: currentOutput.manifest,
|
|
345
|
-
steps: [],
|
|
346
|
-
publicAssets: []
|
|
347
|
-
};
|
|
348
|
-
const changedOutput = {
|
|
349
|
-
manifest: currentOutput.manifest,
|
|
350
|
-
steps: [],
|
|
351
|
-
publicAssets: []
|
|
352
|
-
};
|
|
353
|
-
for (const step of currentOutput.steps) {
|
|
354
|
-
if (changedSteps.has(step)) {
|
|
355
|
-
changedOutput.steps.push(step);
|
|
356
|
-
} else {
|
|
357
|
-
unchangedOutput.steps.push(step);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
for (const asset of currentOutput.publicAssets) {
|
|
361
|
-
if (changedSteps.has(asset)) {
|
|
362
|
-
changedOutput.publicAssets.push(asset);
|
|
363
|
-
} else {
|
|
364
|
-
unchangedOutput.publicAssets.push(asset);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
|
|
368
|
-
if (isOnlyHtmlChanges) {
|
|
369
|
-
return {
|
|
370
|
-
type: "html-reload",
|
|
371
|
-
cachedOutput: unchangedOutput,
|
|
372
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
|
|
376
|
-
changedOutput.steps.flatMap((step) => step.entrypoints),
|
|
377
|
-
(entry) => entry.type === "content-script"
|
|
378
|
-
);
|
|
379
|
-
if (isOnlyContentScripts) {
|
|
380
|
-
return {
|
|
381
|
-
type: "content-script-reload",
|
|
382
|
-
cachedOutput: unchangedOutput,
|
|
383
|
-
changedSteps: changedOutput.steps,
|
|
384
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
return {
|
|
388
|
-
type: "extension-reload",
|
|
389
|
-
cachedOutput: unchangedOutput,
|
|
390
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
function findEffectedSteps(changedFile, currentOutput) {
|
|
394
|
-
const changes = [];
|
|
395
|
-
const changedPath = normalizePath(changedFile);
|
|
396
|
-
const isChunkEffected = (chunk) => (
|
|
397
|
-
// If it's an HTML file with the same path, is is effected because HTML files need to be re-rendered
|
|
398
|
-
// - fileName is normalized, relative bundle path, "<entrypoint-name>.html"
|
|
399
|
-
chunk.type === "asset" && changedPath.replace("/index.html", ".html").endsWith(chunk.fileName) || // If it's a chunk that depends on the changed file, it is effected
|
|
400
|
-
// - moduleIds are absolute, normalized paths
|
|
401
|
-
chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
|
|
402
|
-
);
|
|
403
|
-
for (const step of currentOutput.steps) {
|
|
404
|
-
const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
|
|
405
|
-
if (effectedChunk)
|
|
406
|
-
changes.push(step);
|
|
407
|
-
}
|
|
408
|
-
const effectedAsset = currentOutput.publicAssets.find(
|
|
409
|
-
(chunk) => isChunkEffected(chunk)
|
|
410
|
-
);
|
|
411
|
-
if (effectedAsset)
|
|
412
|
-
changes.push(effectedAsset);
|
|
413
|
-
return changes;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// src/core/utils/building/find-entrypoints.ts
|
|
417
|
-
import { relative as relative2, resolve as resolve3 } from "path";
|
|
418
|
-
import fs3 from "fs-extra";
|
|
419
|
-
import { minimatch } from "minimatch";
|
|
420
|
-
import { parseHTML } from "linkedom";
|
|
421
|
-
import JSON5 from "json5";
|
|
422
|
-
import glob2 from "fast-glob";
|
|
423
|
-
|
|
424
233
|
// src/core/utils/entrypoints.ts
|
|
425
|
-
import path2, { relative, resolve
|
|
234
|
+
import path2, { relative, resolve } from "node:path";
|
|
426
235
|
function getEntrypointName(entrypointsDir, inputPath) {
|
|
427
236
|
const relativePath = path2.relative(entrypointsDir, inputPath);
|
|
428
237
|
const name = relativePath.split(/[\.\/\\]/, 2)[0];
|
|
429
238
|
return name;
|
|
430
239
|
}
|
|
431
240
|
function getEntrypointOutputFile(entrypoint, ext) {
|
|
432
|
-
return
|
|
241
|
+
return resolve(entrypoint.outputDir, `${entrypoint.name}${ext}`);
|
|
433
242
|
}
|
|
434
243
|
function getEntrypointBundlePath(entrypoint, outDir, ext) {
|
|
435
244
|
return normalizePath(
|
|
@@ -453,386 +262,445 @@ function isHtmlEntrypoint(entrypoint) {
|
|
|
453
262
|
return entrypoint.inputPath.endsWith(".html");
|
|
454
263
|
}
|
|
455
264
|
|
|
456
|
-
// src/core/
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
relativePaths.sort();
|
|
466
|
-
const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
|
|
467
|
-
const entrypointInfos = relativePaths.reduce((results, relativePath) => {
|
|
468
|
-
const inputPath = resolve3(wxt.config.entrypointsDir, relativePath);
|
|
469
|
-
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
|
|
470
|
-
const matchingGlob = pathGlobs.find(
|
|
471
|
-
(glob6) => minimatch(relativePath, glob6)
|
|
472
|
-
);
|
|
473
|
-
if (matchingGlob) {
|
|
474
|
-
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
|
|
475
|
-
results.push({
|
|
476
|
-
name,
|
|
477
|
-
inputPath,
|
|
478
|
-
type,
|
|
479
|
-
skipped: wxt.config.filterEntrypoints != null && !wxt.config.filterEntrypoints.has(name)
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
return results;
|
|
483
|
-
}, []);
|
|
484
|
-
preventNoEntrypoints(entrypointInfos);
|
|
485
|
-
preventDuplicateEntrypointNames(entrypointInfos);
|
|
486
|
-
let hasBackground = false;
|
|
487
|
-
const entrypoints = await Promise.all(
|
|
488
|
-
entrypointInfos.map(async (info) => {
|
|
489
|
-
const { type } = info;
|
|
490
|
-
switch (type) {
|
|
491
|
-
case "popup":
|
|
492
|
-
return await getPopupEntrypoint(info);
|
|
493
|
-
case "sidepanel":
|
|
494
|
-
return await getSidepanelEntrypoint(info);
|
|
495
|
-
case "options":
|
|
496
|
-
return await getOptionsEntrypoint(info);
|
|
497
|
-
case "background":
|
|
498
|
-
hasBackground = true;
|
|
499
|
-
return await getBackgroundEntrypoint(info);
|
|
500
|
-
case "content-script":
|
|
501
|
-
return await getContentScriptEntrypoint(info);
|
|
502
|
-
case "unlisted-page":
|
|
503
|
-
return await getUnlistedPageEntrypoint(info);
|
|
504
|
-
case "unlisted-script":
|
|
505
|
-
return await getUnlistedScriptEntrypoint(info);
|
|
506
|
-
case "content-script-style":
|
|
507
|
-
return {
|
|
508
|
-
...info,
|
|
509
|
-
type,
|
|
510
|
-
outputDir: resolve3(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
511
|
-
options: {
|
|
512
|
-
include: void 0,
|
|
513
|
-
exclude: void 0
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
default:
|
|
517
|
-
return {
|
|
518
|
-
...info,
|
|
519
|
-
type,
|
|
520
|
-
outputDir: wxt.config.outDir,
|
|
521
|
-
options: {
|
|
522
|
-
include: void 0,
|
|
523
|
-
exclude: void 0
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
})
|
|
265
|
+
// src/core/builders/vite/plugins/devHtmlPrerender.ts
|
|
266
|
+
import { parseHTML } from "linkedom";
|
|
267
|
+
import { dirname, relative as relative2, resolve as resolve2 } from "node:path";
|
|
268
|
+
var reactRefreshPreamble = "";
|
|
269
|
+
function devHtmlPrerender(config, server) {
|
|
270
|
+
const htmlReloadId = "@wxt/reload-html";
|
|
271
|
+
const resolvedHtmlReloadId = resolve2(
|
|
272
|
+
config.wxtModuleDir,
|
|
273
|
+
"dist/virtual/reload-html.js"
|
|
528
274
|
);
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
275
|
+
const virtualReactRefreshId = "@wxt/virtual-react-refresh";
|
|
276
|
+
const resolvedVirtualReactRefreshId = "\0" + virtualReactRefreshId;
|
|
277
|
+
return [
|
|
278
|
+
{
|
|
279
|
+
apply: "build",
|
|
280
|
+
name: "wxt:dev-html-prerender",
|
|
281
|
+
config() {
|
|
282
|
+
return {
|
|
283
|
+
resolve: {
|
|
284
|
+
alias: {
|
|
285
|
+
[htmlReloadId]: resolvedHtmlReloadId
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
},
|
|
290
|
+
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
|
291
|
+
// before the paths are replaced with their bundled path
|
|
292
|
+
transform(code, id) {
|
|
293
|
+
if (config.command !== "serve" || server == null || !id.endsWith(".html"))
|
|
294
|
+
return;
|
|
295
|
+
const { document } = parseHTML(code);
|
|
296
|
+
const _pointToDevServer = (querySelector, attr) => pointToDevServer(config, server, id, document, querySelector, attr);
|
|
297
|
+
_pointToDevServer("script[type=module]", "src");
|
|
298
|
+
_pointToDevServer("link[rel=stylesheet]", "href");
|
|
299
|
+
const reloader = document.createElement("script");
|
|
300
|
+
reloader.src = htmlReloadId;
|
|
301
|
+
reloader.type = "module";
|
|
302
|
+
document.head.appendChild(reloader);
|
|
303
|
+
const newHtml = document.toString();
|
|
304
|
+
config.logger.debug("transform " + id);
|
|
305
|
+
config.logger.debug("Old HTML:\n" + code);
|
|
306
|
+
config.logger.debug("New HTML:\n" + newHtml);
|
|
307
|
+
return newHtml;
|
|
308
|
+
},
|
|
309
|
+
// Pass the HTML through the dev server to add dev-mode specific code
|
|
310
|
+
async transformIndexHtml(html, ctx) {
|
|
311
|
+
if (config.command !== "serve" || server == null)
|
|
312
|
+
return;
|
|
313
|
+
const originalUrl = `${server.origin}${ctx.path}`;
|
|
314
|
+
const name = getEntrypointName(config.entrypointsDir, ctx.filename);
|
|
315
|
+
const url = `${server.origin}/${name}.html`;
|
|
316
|
+
const serverHtml = await server.transformHtml(url, html, originalUrl);
|
|
317
|
+
const { document } = parseHTML(serverHtml);
|
|
318
|
+
const reactRefreshScript = Array.from(
|
|
319
|
+
document.querySelectorAll("script[type=module]")
|
|
320
|
+
).find((script) => script.innerHTML.includes("@react-refresh"));
|
|
321
|
+
if (reactRefreshScript) {
|
|
322
|
+
reactRefreshPreamble = reactRefreshScript.innerHTML;
|
|
323
|
+
const virtualScript = document.createElement("script");
|
|
324
|
+
virtualScript.type = "module";
|
|
325
|
+
virtualScript.src = `${server.origin}/${virtualReactRefreshId}`;
|
|
326
|
+
reactRefreshScript.replaceWith(virtualScript);
|
|
327
|
+
}
|
|
328
|
+
const viteClientScript = document.querySelector(
|
|
329
|
+
"script[src='/@vite/client']"
|
|
330
|
+
);
|
|
331
|
+
if (viteClientScript) {
|
|
332
|
+
viteClientScript.src = `${server.origin}${viteClientScript.src}`;
|
|
333
|
+
}
|
|
334
|
+
const newHtml = document.toString();
|
|
335
|
+
config.logger.debug("transformIndexHtml " + ctx.filename);
|
|
336
|
+
config.logger.debug("Old HTML:\n" + html);
|
|
337
|
+
config.logger.debug("New HTML:\n" + newHtml);
|
|
338
|
+
return newHtml;
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "wxt:virtualize-react-refresh",
|
|
343
|
+
apply: "serve",
|
|
344
|
+
resolveId(id) {
|
|
345
|
+
if (id === `/${virtualReactRefreshId}`) {
|
|
346
|
+
return resolvedVirtualReactRefreshId;
|
|
347
|
+
}
|
|
348
|
+
if (id.startsWith("/chunks/")) {
|
|
349
|
+
return "\0noop";
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
load(id) {
|
|
353
|
+
if (id === resolvedVirtualReactRefreshId) {
|
|
354
|
+
return reactRefreshPreamble;
|
|
355
|
+
}
|
|
356
|
+
if (id === "\0noop") {
|
|
357
|
+
return "";
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
];
|
|
362
|
+
}
|
|
363
|
+
function pointToDevServer(config, server, id, document, querySelector, attr) {
|
|
364
|
+
document.querySelectorAll(querySelector).forEach((element) => {
|
|
365
|
+
const src = element.getAttribute(attr);
|
|
366
|
+
if (!src || isUrl(src))
|
|
367
|
+
return;
|
|
368
|
+
let resolvedAbsolutePath;
|
|
369
|
+
const matchingAlias = Object.entries(config.alias).find(
|
|
370
|
+
([key]) => src.startsWith(key)
|
|
545
371
|
);
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
`The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
|
|
372
|
+
if (matchingAlias) {
|
|
373
|
+
const [alias, replacement] = matchingAlias;
|
|
374
|
+
resolvedAbsolutePath = resolve2(
|
|
375
|
+
config.root,
|
|
376
|
+
src.replace(alias, replacement)
|
|
552
377
|
);
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (exclude?.length && !include?.length) {
|
|
556
|
-
return !exclude.includes(wxt.config.browser);
|
|
557
|
-
}
|
|
558
|
-
if (include?.length && !exclude?.length) {
|
|
559
|
-
return include.includes(wxt.config.browser);
|
|
378
|
+
} else {
|
|
379
|
+
resolvedAbsolutePath = resolve2(dirname(id), src);
|
|
560
380
|
}
|
|
561
|
-
if (
|
|
562
|
-
|
|
381
|
+
if (resolvedAbsolutePath) {
|
|
382
|
+
const relativePath = normalizePath(
|
|
383
|
+
relative2(config.root, resolvedAbsolutePath)
|
|
384
|
+
);
|
|
385
|
+
if (relativePath.startsWith(".")) {
|
|
386
|
+
let path10 = normalizePath(resolvedAbsolutePath);
|
|
387
|
+
if (!path10.startsWith("/"))
|
|
388
|
+
path10 = "/" + path10;
|
|
389
|
+
element.setAttribute(attr, `${server.origin}/@fs${path10}`);
|
|
390
|
+
} else {
|
|
391
|
+
const url = new URL(relativePath, server.origin);
|
|
392
|
+
element.setAttribute(attr, url.href);
|
|
393
|
+
}
|
|
563
394
|
}
|
|
564
|
-
return true;
|
|
565
395
|
});
|
|
566
|
-
wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
|
|
567
|
-
await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
|
|
568
|
-
return targetEntrypoints;
|
|
569
|
-
}
|
|
570
|
-
function preventDuplicateEntrypointNames(files) {
|
|
571
|
-
const namesToPaths = files.reduce(
|
|
572
|
-
(map, { name, inputPath }) => {
|
|
573
|
-
map[name] ??= [];
|
|
574
|
-
map[name].push(inputPath);
|
|
575
|
-
return map;
|
|
576
|
-
},
|
|
577
|
-
{}
|
|
578
|
-
);
|
|
579
|
-
const errorLines = Object.entries(namesToPaths).reduce(
|
|
580
|
-
(lines, [name, absolutePaths]) => {
|
|
581
|
-
if (absolutePaths.length > 1) {
|
|
582
|
-
lines.push(`- ${name}`);
|
|
583
|
-
absolutePaths.forEach((absolutePath) => {
|
|
584
|
-
lines.push(` - ${relative2(wxt.config.root, absolutePath)}`);
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
return lines;
|
|
588
|
-
},
|
|
589
|
-
[]
|
|
590
|
-
);
|
|
591
|
-
if (errorLines.length > 0) {
|
|
592
|
-
const errorContent = errorLines.join("\n");
|
|
593
|
-
throw Error(
|
|
594
|
-
`Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
|
|
595
|
-
|
|
596
|
-
${errorContent}`
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
396
|
}
|
|
600
|
-
function
|
|
601
|
-
|
|
602
|
-
|
|
397
|
+
function isUrl(str) {
|
|
398
|
+
try {
|
|
399
|
+
new URL(str);
|
|
400
|
+
return true;
|
|
401
|
+
} catch {
|
|
402
|
+
return false;
|
|
603
403
|
}
|
|
604
404
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
{
|
|
609
|
-
browserStyle: "browse_style",
|
|
610
|
-
exclude: "exclude",
|
|
611
|
-
include: "include",
|
|
612
|
-
defaultIcon: "default_icon",
|
|
613
|
-
defaultTitle: "default_title",
|
|
614
|
-
mv2Key: "type"
|
|
615
|
-
},
|
|
616
|
-
{
|
|
617
|
-
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
defaultTitle: (content) => content,
|
|
621
|
-
mv2Key: (content) => content === "page_action" ? "page_action" : "browser_action"
|
|
622
|
-
}
|
|
623
|
-
);
|
|
405
|
+
|
|
406
|
+
// src/core/builders/vite/plugins/devServerGlobals.ts
|
|
407
|
+
function devServerGlobals(config, server) {
|
|
624
408
|
return {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
{
|
|
637
|
-
browserStyle: "browse_style",
|
|
638
|
-
chromeStyle: "chrome_style",
|
|
639
|
-
exclude: "exclude",
|
|
640
|
-
include: "include",
|
|
641
|
-
openInTab: "open_in_tab"
|
|
409
|
+
name: "wxt:dev-server-globals",
|
|
410
|
+
config() {
|
|
411
|
+
if (server == null || config.command == "build")
|
|
412
|
+
return;
|
|
413
|
+
return {
|
|
414
|
+
define: {
|
|
415
|
+
__DEV_SERVER_PROTOCOL__: JSON.stringify("ws:"),
|
|
416
|
+
__DEV_SERVER_HOSTNAME__: JSON.stringify(server.hostname),
|
|
417
|
+
__DEV_SERVER_PORT__: JSON.stringify(server.port)
|
|
418
|
+
}
|
|
419
|
+
};
|
|
642
420
|
}
|
|
643
|
-
);
|
|
644
|
-
return {
|
|
645
|
-
type: "options",
|
|
646
|
-
name: "options",
|
|
647
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
648
|
-
inputPath: info.inputPath,
|
|
649
|
-
outputDir: wxt.config.outDir,
|
|
650
|
-
skipped: info.skipped
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
async function getUnlistedPageEntrypoint(info) {
|
|
654
|
-
const options = await getHtmlEntrypointOptions(info, {
|
|
655
|
-
exclude: "exclude",
|
|
656
|
-
include: "include"
|
|
657
|
-
});
|
|
658
|
-
return {
|
|
659
|
-
type: "unlisted-page",
|
|
660
|
-
name: info.name,
|
|
661
|
-
inputPath: info.inputPath,
|
|
662
|
-
outputDir: wxt.config.outDir,
|
|
663
|
-
options,
|
|
664
|
-
skipped: info.skipped
|
|
665
421
|
};
|
|
666
422
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
if (
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
)
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
return {
|
|
680
|
-
type: "unlisted-script",
|
|
681
|
-
name,
|
|
682
|
-
inputPath,
|
|
683
|
-
outputDir: wxt.config.outDir,
|
|
684
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
685
|
-
skipped
|
|
686
|
-
};
|
|
423
|
+
|
|
424
|
+
// src/core/utils/network.ts
|
|
425
|
+
import dns from "node:dns";
|
|
426
|
+
|
|
427
|
+
// src/core/utils/time.ts
|
|
428
|
+
function formatDuration(duration) {
|
|
429
|
+
if (duration < 1e3)
|
|
430
|
+
return `${duration} ms`;
|
|
431
|
+
if (duration < 1e4)
|
|
432
|
+
return `${(duration / 1e3).toFixed(3)} s`;
|
|
433
|
+
if (duration < 6e4)
|
|
434
|
+
return `${(duration / 1e3).toFixed(1)} s`;
|
|
435
|
+
return `${(duration / 1e3).toFixed(0)} s`;
|
|
687
436
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
437
|
+
function withTimeout(promise, duration) {
|
|
438
|
+
return new Promise((res, rej) => {
|
|
439
|
+
const timeout = setTimeout(() => {
|
|
440
|
+
rej(`Promise timed out after ${duration}ms`);
|
|
441
|
+
}, duration);
|
|
442
|
+
promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/core/utils/network.ts
|
|
447
|
+
function isOffline() {
|
|
448
|
+
const isOffline2 = new Promise((res) => {
|
|
449
|
+
dns.resolve("google.com", (err) => {
|
|
450
|
+
if (err == null) {
|
|
451
|
+
res(false);
|
|
452
|
+
} else {
|
|
453
|
+
res(true);
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
return withTimeout(isOffline2, 1e3).catch(() => true);
|
|
458
|
+
}
|
|
459
|
+
async function isOnline() {
|
|
460
|
+
const offline = await isOffline();
|
|
461
|
+
return !offline;
|
|
462
|
+
}
|
|
463
|
+
async function fetchCached(url, config) {
|
|
464
|
+
let content = "";
|
|
465
|
+
if (await isOnline()) {
|
|
466
|
+
const res = await fetch(url);
|
|
467
|
+
if (res.status < 300) {
|
|
468
|
+
content = await res.text();
|
|
469
|
+
await config.fsCache.set(url, content);
|
|
470
|
+
} else {
|
|
471
|
+
config.logger.debug(
|
|
472
|
+
`Failed to download "${url}", falling back to cache...`
|
|
699
473
|
);
|
|
700
474
|
}
|
|
701
|
-
const { main: _, ...moduleOptions } = defaultExport;
|
|
702
|
-
options = moduleOptions;
|
|
703
475
|
}
|
|
704
|
-
if (
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
return {
|
|
708
|
-
type: "background",
|
|
709
|
-
name,
|
|
710
|
-
inputPath,
|
|
711
|
-
outputDir: wxt.config.outDir,
|
|
712
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
713
|
-
skipped
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
async function getContentScriptEntrypoint({
|
|
717
|
-
inputPath,
|
|
718
|
-
name,
|
|
719
|
-
skipped
|
|
720
|
-
}) {
|
|
721
|
-
const { main: _, ...options } = await importEntrypointFile(inputPath);
|
|
722
|
-
if (options == null) {
|
|
476
|
+
if (!content)
|
|
477
|
+
content = await config.fsCache.get(url) ?? "";
|
|
478
|
+
if (!content)
|
|
723
479
|
throw Error(
|
|
724
|
-
|
|
480
|
+
`Offline and "${url}" has not been cached. Try again when online.`
|
|
725
481
|
);
|
|
726
|
-
|
|
727
|
-
return {
|
|
728
|
-
type: "content-script",
|
|
729
|
-
name,
|
|
730
|
-
inputPath,
|
|
731
|
-
outputDir: resolve3(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
732
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
733
|
-
skipped
|
|
734
|
-
};
|
|
482
|
+
return content;
|
|
735
483
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
defaultTitle: "default_title",
|
|
745
|
-
openAtInstall: "open_at_install"
|
|
746
|
-
},
|
|
747
|
-
{
|
|
748
|
-
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
484
|
+
|
|
485
|
+
// src/core/builders/vite/plugins/download.ts
|
|
486
|
+
function download(config) {
|
|
487
|
+
return {
|
|
488
|
+
name: "wxt:download",
|
|
489
|
+
resolveId(id) {
|
|
490
|
+
if (id.startsWith("url:"))
|
|
491
|
+
return "\0" + id;
|
|
749
492
|
},
|
|
750
|
-
{
|
|
751
|
-
|
|
493
|
+
async load(id) {
|
|
494
|
+
if (!id.startsWith("\0url:"))
|
|
495
|
+
return;
|
|
496
|
+
const url = id.replace("\0url:", "");
|
|
497
|
+
return await fetchCached(url, config);
|
|
752
498
|
}
|
|
753
|
-
);
|
|
754
|
-
return {
|
|
755
|
-
type: "sidepanel",
|
|
756
|
-
name: info.name,
|
|
757
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
758
|
-
inputPath: info.inputPath,
|
|
759
|
-
outputDir: wxt.config.outDir,
|
|
760
|
-
skipped: info.skipped
|
|
761
499
|
};
|
|
762
500
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
501
|
+
|
|
502
|
+
// src/core/builders/vite/plugins/multipageMove.ts
|
|
503
|
+
import { dirname as dirname2, extname, resolve as resolve3, join } from "node:path";
|
|
504
|
+
import fs, { ensureDir as ensureDir2 } from "fs-extra";
|
|
505
|
+
function multipageMove(entrypoints, config) {
|
|
506
|
+
return {
|
|
507
|
+
name: "wxt:multipage-move",
|
|
508
|
+
async writeBundle(_, bundle) {
|
|
509
|
+
for (const oldBundlePath in bundle) {
|
|
510
|
+
const entrypoint = entrypoints.find(
|
|
511
|
+
(entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath)
|
|
512
|
+
);
|
|
513
|
+
if (entrypoint == null) {
|
|
514
|
+
config.logger.debug(
|
|
515
|
+
`No entrypoint found for ${oldBundlePath}, leaving in chunks directory`
|
|
516
|
+
);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
const newBundlePath = getEntrypointBundlePath(
|
|
520
|
+
entrypoint,
|
|
521
|
+
config.outDir,
|
|
522
|
+
extname(oldBundlePath)
|
|
778
523
|
);
|
|
524
|
+
if (newBundlePath === oldBundlePath) {
|
|
525
|
+
config.logger.debug(
|
|
526
|
+
"HTML file is already in the correct location",
|
|
527
|
+
oldBundlePath
|
|
528
|
+
);
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const oldAbsPath = resolve3(config.outDir, oldBundlePath);
|
|
532
|
+
const newAbsPath = resolve3(config.outDir, newBundlePath);
|
|
533
|
+
await ensureDir2(dirname2(newAbsPath));
|
|
534
|
+
await fs.move(oldAbsPath, newAbsPath, { overwrite: true });
|
|
535
|
+
const renamedChunk = {
|
|
536
|
+
...bundle[oldBundlePath],
|
|
537
|
+
fileName: newBundlePath
|
|
538
|
+
};
|
|
539
|
+
delete bundle[oldBundlePath];
|
|
540
|
+
bundle[newBundlePath] = renamedChunk;
|
|
779
541
|
}
|
|
542
|
+
removeEmptyDirs(config.outDir);
|
|
780
543
|
}
|
|
781
|
-
}
|
|
782
|
-
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
async function removeEmptyDirs(dir) {
|
|
547
|
+
const files = await fs.readdir(dir);
|
|
548
|
+
for (const file of files) {
|
|
549
|
+
const filePath = join(dir, file);
|
|
550
|
+
const stats = await fs.stat(filePath);
|
|
551
|
+
if (stats.isDirectory()) {
|
|
552
|
+
await removeEmptyDirs(filePath);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
await fs.rmdir(dir);
|
|
557
|
+
} catch {
|
|
558
|
+
}
|
|
783
559
|
}
|
|
784
|
-
var PATH_GLOB_TO_TYPE_MAP = {
|
|
785
|
-
"sandbox.html": "sandbox",
|
|
786
|
-
"sandbox/index.html": "sandbox",
|
|
787
|
-
"*.sandbox.html": "sandbox",
|
|
788
|
-
"*.sandbox/index.html": "sandbox",
|
|
789
|
-
"bookmarks.html": "bookmarks",
|
|
790
|
-
"bookmarks/index.html": "bookmarks",
|
|
791
|
-
"history.html": "history",
|
|
792
|
-
"history/index.html": "history",
|
|
793
|
-
"newtab.html": "newtab",
|
|
794
|
-
"newtab/index.html": "newtab",
|
|
795
|
-
"sidepanel.html": "sidepanel",
|
|
796
|
-
"sidepanel/index.html": "sidepanel",
|
|
797
|
-
"*.sidepanel.html": "sidepanel",
|
|
798
|
-
"*.sidepanel/index.html": "sidepanel",
|
|
799
|
-
"devtools.html": "devtools",
|
|
800
|
-
"devtools/index.html": "devtools",
|
|
801
|
-
"background.[jt]s": "background",
|
|
802
|
-
"background/index.[jt]s": "background",
|
|
803
|
-
[VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
|
|
804
|
-
"content.[jt]s?(x)": "content-script",
|
|
805
|
-
"content/index.[jt]s?(x)": "content-script",
|
|
806
|
-
"*.content.[jt]s?(x)": "content-script",
|
|
807
|
-
"*.content/index.[jt]s?(x)": "content-script",
|
|
808
|
-
[`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
809
|
-
[`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
810
|
-
[`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
811
|
-
[`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
812
|
-
"popup.html": "popup",
|
|
813
|
-
"popup/index.html": "popup",
|
|
814
|
-
"options.html": "options",
|
|
815
|
-
"options/index.html": "options",
|
|
816
|
-
"*.html": "unlisted-page",
|
|
817
|
-
"*/index.html": "unlisted-page",
|
|
818
|
-
"*.[jt]s?(x)": "unlisted-script",
|
|
819
|
-
"*/index.[jt]s?(x)": "unlisted-script",
|
|
820
|
-
[`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
|
|
821
|
-
[`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
|
|
822
|
-
};
|
|
823
|
-
var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
|
|
824
560
|
|
|
825
|
-
// src/core/
|
|
561
|
+
// src/core/builders/vite/plugins/unimport.ts
|
|
826
562
|
import { createUnimport } from "unimport";
|
|
827
|
-
import
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
563
|
+
import { extname as extname2 } from "path";
|
|
564
|
+
var ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
565
|
+
".js",
|
|
566
|
+
".jsx",
|
|
567
|
+
".ts",
|
|
568
|
+
".tsx",
|
|
569
|
+
".vue",
|
|
570
|
+
".svelte"
|
|
571
|
+
]);
|
|
572
|
+
function unimport(config) {
|
|
573
|
+
const options = config.imports;
|
|
574
|
+
if (options === false)
|
|
575
|
+
return [];
|
|
576
|
+
const unimport2 = createUnimport(options);
|
|
577
|
+
return {
|
|
578
|
+
name: "wxt:unimport",
|
|
579
|
+
async config() {
|
|
580
|
+
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
581
|
+
},
|
|
582
|
+
async transform(code, id) {
|
|
583
|
+
if (id.includes("node_modules"))
|
|
584
|
+
return;
|
|
585
|
+
if (!ENABLED_EXTENSIONS.has(extname2(id)))
|
|
586
|
+
return;
|
|
587
|
+
const injected = await unimport2.injectImports(code, id);
|
|
588
|
+
return {
|
|
589
|
+
code: injected.code,
|
|
590
|
+
map: injected.s.generateMap({ hires: "boundary", source: id })
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/core/builders/vite/plugins/virtualEntrypoint.ts
|
|
597
|
+
import fs2 from "fs-extra";
|
|
598
|
+
import { resolve as resolve4 } from "path";
|
|
599
|
+
function virtualEntrypoint(type, config) {
|
|
600
|
+
const virtualId = `virtual:wxt-${type}?`;
|
|
601
|
+
const resolvedVirtualId = `\0${virtualId}`;
|
|
602
|
+
return {
|
|
603
|
+
name: `wxt:virtual-entrypoint`,
|
|
604
|
+
resolveId(id) {
|
|
605
|
+
const index = id.indexOf(virtualId);
|
|
606
|
+
if (index === -1)
|
|
607
|
+
return;
|
|
608
|
+
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
|
609
|
+
return resolvedVirtualId + inputPath;
|
|
610
|
+
},
|
|
611
|
+
async load(id) {
|
|
612
|
+
if (!id.startsWith(resolvedVirtualId))
|
|
613
|
+
return;
|
|
614
|
+
const inputPath = id.replace(resolvedVirtualId, "");
|
|
615
|
+
const template = await fs2.readFile(
|
|
616
|
+
resolve4(config.wxtModuleDir, `dist/virtual/${type}-entrypoint.js`),
|
|
617
|
+
"utf-8"
|
|
618
|
+
);
|
|
619
|
+
return template.replace(`virtual:user-${type}`, inputPath);
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// src/core/builders/vite/plugins/tsconfigPaths.ts
|
|
625
|
+
function tsconfigPaths(config) {
|
|
626
|
+
return {
|
|
627
|
+
name: "wxt:aliases",
|
|
628
|
+
async config() {
|
|
629
|
+
return {
|
|
630
|
+
resolve: {
|
|
631
|
+
alias: config.alias
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/core/utils/constants.ts
|
|
639
|
+
var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
|
|
640
|
+
|
|
641
|
+
// src/core/builders/vite/plugins/noopBackground.ts
|
|
642
|
+
function noopBackground() {
|
|
643
|
+
const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
|
|
644
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
645
|
+
return {
|
|
646
|
+
name: "wxt:noop-background",
|
|
647
|
+
resolveId(id) {
|
|
648
|
+
if (id === virtualModuleId)
|
|
649
|
+
return resolvedVirtualModuleId;
|
|
650
|
+
},
|
|
651
|
+
load(id) {
|
|
652
|
+
if (id === resolvedVirtualModuleId) {
|
|
653
|
+
return `import { defineBackground } from 'wxt/sandbox';
|
|
654
|
+
export default defineBackground(() => void 0)`;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/core/builders/vite/plugins/cssEntrypoints.ts
|
|
661
|
+
function cssEntrypoints(entrypoint, config) {
|
|
662
|
+
return {
|
|
663
|
+
name: "wxt:css-entrypoint",
|
|
664
|
+
config() {
|
|
665
|
+
return {
|
|
666
|
+
build: {
|
|
667
|
+
rollupOptions: {
|
|
668
|
+
output: {
|
|
669
|
+
assetFileNames: () => getEntrypointBundlePath(entrypoint, config.outDir, ".css")
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
},
|
|
675
|
+
generateBundle(_, bundle) {
|
|
676
|
+
Object.keys(bundle).forEach((file) => {
|
|
677
|
+
if (file.endsWith(".js"))
|
|
678
|
+
delete bundle[file];
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// src/core/builders/vite/plugins/bundleAnalysis.ts
|
|
685
|
+
import { visualizer } from "@aklinker1/rollup-plugin-visualizer";
|
|
686
|
+
import path3 from "node:path";
|
|
687
|
+
var increment = 0;
|
|
688
|
+
function bundleAnalysis(config) {
|
|
689
|
+
return visualizer({
|
|
690
|
+
template: "raw-data",
|
|
691
|
+
filename: path3.resolve(
|
|
692
|
+
config.analysis.outputDir,
|
|
693
|
+
`${config.analysis.outputName}-${increment++}.json`
|
|
694
|
+
)
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// src/core/utils/globals.ts
|
|
699
|
+
function getGlobals(config) {
|
|
700
|
+
return [
|
|
701
|
+
{
|
|
702
|
+
name: "MANIFEST_VERSION",
|
|
703
|
+
value: config.manifestVersion,
|
|
836
704
|
type: `2 | 3`
|
|
837
705
|
},
|
|
838
706
|
{
|
|
@@ -882,985 +750,1108 @@ function getEntrypointGlobals(entrypointName) {
|
|
|
882
750
|
];
|
|
883
751
|
}
|
|
884
752
|
|
|
885
|
-
// src/core/
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
message: "<ltr|rtl>",
|
|
900
|
-
description: 'The text direction for the current locale, either "ltr" for left-to-right languages such as English or "rtl" for right-to-left languages such as Japanese.'
|
|
901
|
-
},
|
|
902
|
-
"@@bidi_reversed_dir": {
|
|
903
|
-
message: "<rtl|ltr>",
|
|
904
|
-
description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
|
|
905
|
-
},
|
|
906
|
-
"@@bidi_start_edge": {
|
|
907
|
-
message: "<left|right>",
|
|
908
|
-
description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
|
|
909
|
-
},
|
|
910
|
-
"@@bidi_end_edge": {
|
|
911
|
-
message: "<right|left>",
|
|
912
|
-
description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
|
|
913
|
-
}
|
|
914
|
-
};
|
|
915
|
-
function parseI18nMessages(messagesJson) {
|
|
916
|
-
return Object.entries({
|
|
917
|
-
...predefinedMessages,
|
|
918
|
-
...messagesJson
|
|
919
|
-
}).map(([name, details]) => ({
|
|
920
|
-
name,
|
|
921
|
-
...details
|
|
922
|
-
}));
|
|
753
|
+
// src/core/builders/vite/plugins/globals.ts
|
|
754
|
+
function globals(config) {
|
|
755
|
+
return {
|
|
756
|
+
name: "wxt:globals",
|
|
757
|
+
config() {
|
|
758
|
+
const define = {};
|
|
759
|
+
for (const global of getGlobals(config)) {
|
|
760
|
+
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
761
|
+
}
|
|
762
|
+
return {
|
|
763
|
+
define
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
};
|
|
923
767
|
}
|
|
924
768
|
|
|
925
|
-
// src/core/
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
769
|
+
// src/core/builders/vite/plugins/excludeBrowserPolyfill.ts
|
|
770
|
+
function excludeBrowserPolyfill(config) {
|
|
771
|
+
const virtualId = "virtual:wxt-webextension-polyfill-disabled";
|
|
772
|
+
return {
|
|
773
|
+
name: "wxt:exclude-browser-polyfill",
|
|
774
|
+
config() {
|
|
775
|
+
if (config.experimental.includeBrowserPolyfill)
|
|
776
|
+
return;
|
|
777
|
+
return {
|
|
778
|
+
resolve: {
|
|
779
|
+
alias: {
|
|
780
|
+
"webextension-polyfill": virtualId
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
},
|
|
785
|
+
load(id) {
|
|
786
|
+
if (id === virtualId) {
|
|
787
|
+
return "export default chrome";
|
|
788
|
+
}
|
|
934
789
|
}
|
|
935
|
-
}
|
|
936
|
-
references.push(await writePathsDeclarationFile(entrypoints));
|
|
937
|
-
references.push(await writeI18nDeclarationFile());
|
|
938
|
-
references.push(await writeGlobalsDeclarationFile());
|
|
939
|
-
const mainReference = await writeMainDeclarationFile(references);
|
|
940
|
-
await writeTsConfigFile(mainReference);
|
|
941
|
-
}
|
|
942
|
-
async function writeImportsDeclarationFile(unimport2) {
|
|
943
|
-
const filePath = resolve4(wxt.config.typesDir, "imports.d.ts");
|
|
944
|
-
await unimport2.scanImportsFromDir(void 0, { cwd: wxt.config.srcDir });
|
|
945
|
-
await writeFileIfDifferent(
|
|
946
|
-
filePath,
|
|
947
|
-
["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
|
|
948
|
-
"\n"
|
|
949
|
-
) + "\n"
|
|
950
|
-
);
|
|
951
|
-
return filePath;
|
|
952
|
-
}
|
|
953
|
-
async function writeImportsEslintFile(unimport2, options) {
|
|
954
|
-
const globals2 = {};
|
|
955
|
-
const eslintrc = { globals: globals2 };
|
|
956
|
-
(await unimport2.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().forEach((name) => {
|
|
957
|
-
eslintrc.globals[name] = options.eslintrc.globalsPropValue;
|
|
958
|
-
});
|
|
959
|
-
await fs4.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
|
|
790
|
+
};
|
|
960
791
|
}
|
|
961
|
-
async function writePathsDeclarationFile(entrypoints) {
|
|
962
|
-
const filePath = resolve4(wxt.config.typesDir, "paths.d.ts");
|
|
963
|
-
const unions = entrypoints.map(
|
|
964
|
-
(entry) => getEntrypointBundlePath(
|
|
965
|
-
entry,
|
|
966
|
-
wxt.config.outDir,
|
|
967
|
-
isHtmlEntrypoint(entry) ? ".html" : ".js"
|
|
968
|
-
)
|
|
969
|
-
).concat(await getPublicFiles()).map(normalizePath).map((path10) => ` | "/${path10}"`).sort().join("\n");
|
|
970
|
-
const template = `// Generated by wxt
|
|
971
|
-
import "wxt/browser";
|
|
972
792
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
{
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
);
|
|
987
|
-
return filePath;
|
|
988
|
-
}
|
|
989
|
-
async function writeI18nDeclarationFile() {
|
|
990
|
-
const filePath = resolve4(wxt.config.typesDir, "i18n.d.ts");
|
|
991
|
-
const defaultLocale = wxt.config.manifest.default_locale;
|
|
992
|
-
const template = `// Generated by wxt
|
|
993
|
-
import "wxt/browser";
|
|
994
|
-
|
|
995
|
-
declare module "wxt/browser" {
|
|
996
|
-
/**
|
|
997
|
-
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
998
|
-
*/
|
|
999
|
-
interface GetMessageOptions {
|
|
1000
|
-
/**
|
|
1001
|
-
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
1002
|
-
*/
|
|
1003
|
-
escapeLt?: boolean
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
export interface WxtI18n extends I18n.Static {
|
|
1007
|
-
{{ overrides }}
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
`;
|
|
1011
|
-
let messages;
|
|
1012
|
-
if (defaultLocale) {
|
|
1013
|
-
const defaultLocalePath = path3.resolve(
|
|
1014
|
-
wxt.config.publicDir,
|
|
1015
|
-
"_locales",
|
|
1016
|
-
defaultLocale,
|
|
1017
|
-
"messages.json"
|
|
1018
|
-
);
|
|
1019
|
-
const content = JSON.parse(await fs4.readFile(defaultLocalePath, "utf-8"));
|
|
1020
|
-
messages = parseI18nMessages(content);
|
|
1021
|
-
} else {
|
|
1022
|
-
messages = parseI18nMessages({});
|
|
1023
|
-
}
|
|
1024
|
-
const overrides = messages.map((message) => {
|
|
1025
|
-
return ` /**
|
|
1026
|
-
* ${message.description || "No message description."}
|
|
1027
|
-
*
|
|
1028
|
-
* "${message.message}"
|
|
1029
|
-
*/
|
|
1030
|
-
getMessage(
|
|
1031
|
-
messageName: "${message.name}",
|
|
1032
|
-
substitutions?: string | string[],
|
|
1033
|
-
options?: GetMessageOptions,
|
|
1034
|
-
): string;`;
|
|
1035
|
-
});
|
|
1036
|
-
await writeFileIfDifferent(
|
|
1037
|
-
filePath,
|
|
1038
|
-
template.replace("{{ overrides }}", overrides.join("\n"))
|
|
1039
|
-
);
|
|
1040
|
-
return filePath;
|
|
1041
|
-
}
|
|
1042
|
-
async function writeGlobalsDeclarationFile() {
|
|
1043
|
-
const filePath = resolve4(wxt.config.typesDir, "globals.d.ts");
|
|
1044
|
-
const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
|
|
1045
|
-
await writeFileIfDifferent(
|
|
1046
|
-
filePath,
|
|
1047
|
-
[
|
|
1048
|
-
"// Generated by wxt",
|
|
1049
|
-
"export {}",
|
|
1050
|
-
"interface ImportMetaEnv {",
|
|
1051
|
-
...globals2.map((global) => ` readonly ${global.name}: ${global.type};`),
|
|
1052
|
-
"}",
|
|
1053
|
-
"interface ImportMeta {",
|
|
1054
|
-
" readonly env: ImportMetaEnv",
|
|
1055
|
-
"}"
|
|
1056
|
-
].join("\n") + "\n"
|
|
1057
|
-
);
|
|
1058
|
-
return filePath;
|
|
1059
|
-
}
|
|
1060
|
-
async function writeMainDeclarationFile(references) {
|
|
1061
|
-
const dir = wxt.config.wxtDir;
|
|
1062
|
-
const filePath = resolve4(dir, "wxt.d.ts");
|
|
1063
|
-
await writeFileIfDifferent(
|
|
1064
|
-
filePath,
|
|
1065
|
-
[
|
|
1066
|
-
"// Generated by wxt",
|
|
1067
|
-
`/// <reference types="wxt/vite-builder-env" />`,
|
|
1068
|
-
...references.map(
|
|
1069
|
-
(ref) => `/// <reference types="./${normalizePath(relative3(dir, ref))}" />`
|
|
1070
|
-
)
|
|
1071
|
-
].join("\n") + "\n"
|
|
1072
|
-
);
|
|
1073
|
-
return filePath;
|
|
1074
|
-
}
|
|
1075
|
-
async function writeTsConfigFile(mainReference) {
|
|
1076
|
-
const dir = wxt.config.wxtDir;
|
|
1077
|
-
const getTsconfigPath = (path10) => normalizePath(relative3(dir, path10));
|
|
1078
|
-
const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
|
|
1079
|
-
const aliasPath = getTsconfigPath(absolutePath);
|
|
1080
|
-
return [
|
|
1081
|
-
` "${alias}": ["${aliasPath}"]`,
|
|
1082
|
-
` "${alias}/*": ["${aliasPath}/*"]`
|
|
1083
|
-
];
|
|
1084
|
-
}).join(",\n");
|
|
1085
|
-
await writeFileIfDifferent(
|
|
1086
|
-
resolve4(dir, "tsconfig.json"),
|
|
1087
|
-
`{
|
|
1088
|
-
"compilerOptions": {
|
|
1089
|
-
"target": "ESNext",
|
|
1090
|
-
"module": "ESNext",
|
|
1091
|
-
"moduleResolution": "Bundler",
|
|
1092
|
-
"noEmit": true,
|
|
1093
|
-
"esModuleInterop": true,
|
|
1094
|
-
"forceConsistentCasingInFileNames": true,
|
|
1095
|
-
"resolveJsonModule": true,
|
|
1096
|
-
"strict": true,
|
|
1097
|
-
"skipLibCheck": true,
|
|
1098
|
-
"paths": {
|
|
1099
|
-
${paths}
|
|
793
|
+
// src/core/builders/vite/plugins/entrypointGroupGlobals.ts
|
|
794
|
+
function entrypointGroupGlobals(entrypointGroup) {
|
|
795
|
+
return {
|
|
796
|
+
name: "wxt:entrypoint-group-globals",
|
|
797
|
+
config() {
|
|
798
|
+
const define = {};
|
|
799
|
+
let name = Array.isArray(entrypointGroup) ? "html" : entrypointGroup.name;
|
|
800
|
+
for (const global of getEntrypointGlobals(name)) {
|
|
801
|
+
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
802
|
+
}
|
|
803
|
+
return {
|
|
804
|
+
define
|
|
805
|
+
};
|
|
1100
806
|
}
|
|
1101
|
-
}
|
|
1102
|
-
"include": [
|
|
1103
|
-
"${getTsconfigPath(wxt.config.root)}/**/*",
|
|
1104
|
-
"./${getTsconfigPath(mainReference)}"
|
|
1105
|
-
],
|
|
1106
|
-
"exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
|
|
1107
|
-
}`
|
|
1108
|
-
);
|
|
807
|
+
};
|
|
1109
808
|
}
|
|
1110
809
|
|
|
1111
|
-
// src/core/
|
|
1112
|
-
|
|
1113
|
-
import path5 from "node:path";
|
|
1114
|
-
|
|
1115
|
-
// src/core/utils/cache.ts
|
|
1116
|
-
import fs5, { ensureDir as ensureDir2 } from "fs-extra";
|
|
1117
|
-
import { dirname as dirname2, resolve as resolve5 } from "path";
|
|
1118
|
-
function createFsCache(wxtDir) {
|
|
1119
|
-
const getPath = (key) => resolve5(wxtDir, "cache", encodeURIComponent(key));
|
|
810
|
+
// src/core/builders/vite/plugins/defineImportMeta.ts
|
|
811
|
+
function defineImportMeta() {
|
|
1120
812
|
return {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
return await fs5.readFile(path10, "utf-8");
|
|
1130
|
-
} catch {
|
|
1131
|
-
return void 0;
|
|
1132
|
-
}
|
|
813
|
+
name: "wxt:define",
|
|
814
|
+
config() {
|
|
815
|
+
return {
|
|
816
|
+
define: {
|
|
817
|
+
// This works for all extension contexts, including background service worker
|
|
818
|
+
"import.meta.url": "self.location.href"
|
|
819
|
+
}
|
|
820
|
+
};
|
|
1133
821
|
}
|
|
1134
822
|
};
|
|
1135
823
|
}
|
|
1136
824
|
|
|
1137
|
-
// src/core/
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
config.
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
825
|
+
// src/core/builders/vite/index.ts
|
|
826
|
+
async function createViteBuilder(wxtConfig, server) {
|
|
827
|
+
const vite = await import("vite");
|
|
828
|
+
const getBaseConfig = async () => {
|
|
829
|
+
const config = await wxtConfig.vite(wxtConfig.env);
|
|
830
|
+
config.root = wxtConfig.root;
|
|
831
|
+
config.configFile = false;
|
|
832
|
+
config.logLevel = "warn";
|
|
833
|
+
config.mode = wxtConfig.mode;
|
|
834
|
+
config.build ??= {};
|
|
835
|
+
config.build.outDir = wxtConfig.outDir;
|
|
836
|
+
config.build.emptyOutDir = false;
|
|
837
|
+
if (config.build.minify == null && wxtConfig.command === "serve") {
|
|
838
|
+
config.build.minify = false;
|
|
839
|
+
}
|
|
840
|
+
if (config.build.sourcemap == null && wxtConfig.command === "serve") {
|
|
841
|
+
config.build.sourcemap = "inline";
|
|
842
|
+
}
|
|
843
|
+
config.plugins ??= [];
|
|
844
|
+
config.plugins.push(
|
|
845
|
+
download(wxtConfig),
|
|
846
|
+
devHtmlPrerender(wxtConfig, server),
|
|
847
|
+
unimport(wxtConfig),
|
|
848
|
+
virtualEntrypoint("background", wxtConfig),
|
|
849
|
+
virtualEntrypoint("content-script-isolated-world", wxtConfig),
|
|
850
|
+
virtualEntrypoint("content-script-main-world", wxtConfig),
|
|
851
|
+
virtualEntrypoint("unlisted-script", wxtConfig),
|
|
852
|
+
devServerGlobals(wxtConfig, server),
|
|
853
|
+
tsconfigPaths(wxtConfig),
|
|
854
|
+
noopBackground(),
|
|
855
|
+
globals(wxtConfig),
|
|
856
|
+
excludeBrowserPolyfill(wxtConfig),
|
|
857
|
+
defineImportMeta()
|
|
858
|
+
);
|
|
859
|
+
if (wxtConfig.analysis.enabled) {
|
|
860
|
+
config.plugins.push(bundleAnalysis(wxtConfig));
|
|
861
|
+
}
|
|
862
|
+
return config;
|
|
863
|
+
};
|
|
864
|
+
const getLibModeConfig = (entrypoint) => {
|
|
865
|
+
const entry = getRollupEntry(entrypoint);
|
|
866
|
+
const plugins = [
|
|
867
|
+
entrypointGroupGlobals(entrypoint)
|
|
868
|
+
];
|
|
869
|
+
if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
|
|
870
|
+
plugins.push(cssEntrypoints(entrypoint, wxtConfig));
|
|
871
|
+
}
|
|
872
|
+
const libMode = {
|
|
873
|
+
mode: wxtConfig.mode,
|
|
874
|
+
plugins,
|
|
875
|
+
build: {
|
|
876
|
+
lib: {
|
|
877
|
+
entry,
|
|
878
|
+
formats: ["iife"],
|
|
879
|
+
name: "_",
|
|
880
|
+
fileName: entrypoint.name
|
|
881
|
+
},
|
|
882
|
+
rollupOptions: {
|
|
883
|
+
output: {
|
|
884
|
+
// There's only a single output for this build, so we use the desired bundle path for the
|
|
885
|
+
// entry output (like "content-scripts/overlay.js")
|
|
886
|
+
entryFileNames: getEntrypointBundlePath(
|
|
887
|
+
entrypoint,
|
|
888
|
+
wxtConfig.outDir,
|
|
889
|
+
".js"
|
|
890
|
+
),
|
|
891
|
+
// Output content script CSS to `content-scripts/`, but all other scripts are written to
|
|
892
|
+
// `assets/`.
|
|
893
|
+
assetFileNames: ({ name }) => {
|
|
894
|
+
if (entrypoint.type === "content-script" && name?.endsWith("css")) {
|
|
895
|
+
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
896
|
+
} else {
|
|
897
|
+
return `assets/${entrypoint.name}.[ext]`;
|
|
898
|
+
}
|
|
1161
899
|
}
|
|
1162
900
|
}
|
|
1163
|
-
}
|
|
901
|
+
}
|
|
1164
902
|
},
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
const server = config.server;
|
|
1169
|
-
if (config.command !== "serve" || server == null || !id.endsWith(".html"))
|
|
1170
|
-
return;
|
|
1171
|
-
const { document } = parseHTML2(code);
|
|
1172
|
-
const _pointToDevServer = (querySelector, attr) => pointToDevServer(config, server, id, document, querySelector, attr);
|
|
1173
|
-
_pointToDevServer("script[type=module]", "src");
|
|
1174
|
-
_pointToDevServer("link[rel=stylesheet]", "href");
|
|
1175
|
-
const reloader = document.createElement("script");
|
|
1176
|
-
reloader.src = htmlReloadId;
|
|
1177
|
-
reloader.type = "module";
|
|
1178
|
-
document.head.appendChild(reloader);
|
|
1179
|
-
const newHtml = document.toString();
|
|
1180
|
-
config.logger.debug("transform " + id);
|
|
1181
|
-
config.logger.debug("Old HTML:\n" + code);
|
|
1182
|
-
config.logger.debug("New HTML:\n" + newHtml);
|
|
1183
|
-
return newHtml;
|
|
1184
|
-
},
|
|
1185
|
-
// Pass the HTML through the dev server to add dev-mode specific code
|
|
1186
|
-
async transformIndexHtml(html, ctx) {
|
|
1187
|
-
const server = config.server;
|
|
1188
|
-
if (config.command !== "serve" || server == null)
|
|
1189
|
-
return;
|
|
1190
|
-
const originalUrl = `${server.origin}${ctx.path}`;
|
|
1191
|
-
const name = getEntrypointName(config.entrypointsDir, ctx.filename);
|
|
1192
|
-
const url = `${server.origin}/${name}.html`;
|
|
1193
|
-
const serverHtml = await server.transformHtml(url, html, originalUrl);
|
|
1194
|
-
const { document } = parseHTML2(serverHtml);
|
|
1195
|
-
const reactRefreshScript = Array.from(
|
|
1196
|
-
document.querySelectorAll("script[type=module]")
|
|
1197
|
-
).find((script) => script.innerHTML.includes("@react-refresh"));
|
|
1198
|
-
if (reactRefreshScript) {
|
|
1199
|
-
reactRefreshPreamble = reactRefreshScript.innerHTML;
|
|
1200
|
-
const virtualScript = document.createElement("script");
|
|
1201
|
-
virtualScript.type = "module";
|
|
1202
|
-
virtualScript.src = `${server.origin}/${virtualReactRefreshId}`;
|
|
1203
|
-
reactRefreshScript.replaceWith(virtualScript);
|
|
1204
|
-
}
|
|
1205
|
-
const viteClientScript = document.querySelector(
|
|
1206
|
-
"script[src='/@vite/client']"
|
|
1207
|
-
);
|
|
1208
|
-
if (viteClientScript) {
|
|
1209
|
-
viteClientScript.src = `${server.origin}${viteClientScript.src}`;
|
|
1210
|
-
}
|
|
1211
|
-
const newHtml = document.toString();
|
|
1212
|
-
config.logger.debug("transformIndexHtml " + ctx.filename);
|
|
1213
|
-
config.logger.debug("Old HTML:\n" + html);
|
|
1214
|
-
config.logger.debug("New HTML:\n" + newHtml);
|
|
1215
|
-
return newHtml;
|
|
903
|
+
define: {
|
|
904
|
+
// See https://github.com/aklinker1/vite-plugin-web-extension/issues/96
|
|
905
|
+
"process.env.NODE_ENV": JSON.stringify(wxtConfig.mode)
|
|
1216
906
|
}
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
907
|
+
};
|
|
908
|
+
return libMode;
|
|
909
|
+
};
|
|
910
|
+
const getMultiPageConfig = (entrypoints) => {
|
|
911
|
+
const htmlEntrypoints = new Set(
|
|
912
|
+
entrypoints.filter(isHtmlEntrypoint).map((e) => e.name)
|
|
913
|
+
);
|
|
914
|
+
return {
|
|
915
|
+
mode: wxtConfig.mode,
|
|
916
|
+
plugins: [
|
|
917
|
+
multipageMove(entrypoints, wxtConfig),
|
|
918
|
+
entrypointGroupGlobals(entrypoints)
|
|
919
|
+
],
|
|
920
|
+
build: {
|
|
921
|
+
rollupOptions: {
|
|
922
|
+
input: entrypoints.reduce((input, entry) => {
|
|
923
|
+
input[entry.name] = getRollupEntry(entry);
|
|
924
|
+
return input;
|
|
925
|
+
}, {}),
|
|
926
|
+
output: {
|
|
927
|
+
// Include a hash to prevent conflicts
|
|
928
|
+
chunkFileNames: "chunks/[name]-[hash].js",
|
|
929
|
+
entryFileNames: ({ name }) => {
|
|
930
|
+
if (htmlEntrypoints.has(name))
|
|
931
|
+
return "chunks/[name]-[hash].js";
|
|
932
|
+
return "[name].js";
|
|
933
|
+
},
|
|
934
|
+
// We can't control the "name", so we need a hash to prevent conflicts
|
|
935
|
+
assetFileNames: "assets/[name]-[hash].[ext]"
|
|
936
|
+
}
|
|
1235
937
|
}
|
|
1236
938
|
}
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if (resolvedAbsolutePath) {
|
|
1259
|
-
const relativePath = normalizePath(
|
|
1260
|
-
relative4(config.root, resolvedAbsolutePath)
|
|
1261
|
-
);
|
|
1262
|
-
if (relativePath.startsWith(".")) {
|
|
1263
|
-
let path10 = normalizePath(resolvedAbsolutePath);
|
|
1264
|
-
if (!path10.startsWith("/"))
|
|
1265
|
-
path10 = "/" + path10;
|
|
1266
|
-
element.setAttribute(attr, `${server.origin}/@fs${path10}`);
|
|
1267
|
-
} else {
|
|
1268
|
-
const url = new URL(relativePath, server.origin);
|
|
1269
|
-
element.setAttribute(attr, url.href);
|
|
939
|
+
};
|
|
940
|
+
};
|
|
941
|
+
const getCssConfig = (entrypoint) => {
|
|
942
|
+
return {
|
|
943
|
+
mode: wxtConfig.mode,
|
|
944
|
+
plugins: [entrypointGroupGlobals(entrypoint)],
|
|
945
|
+
build: {
|
|
946
|
+
rollupOptions: {
|
|
947
|
+
input: {
|
|
948
|
+
[entrypoint.name]: entrypoint.inputPath
|
|
949
|
+
},
|
|
950
|
+
output: {
|
|
951
|
+
assetFileNames: () => {
|
|
952
|
+
if (entrypoint.type === "content-script-style") {
|
|
953
|
+
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
954
|
+
} else {
|
|
955
|
+
return `assets/${entrypoint.name}.[ext]`;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
1270
960
|
}
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
function isUrl(str) {
|
|
1275
|
-
try {
|
|
1276
|
-
new URL(str);
|
|
1277
|
-
return true;
|
|
1278
|
-
} catch {
|
|
1279
|
-
return false;
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
// src/core/builders/vite/plugins/devServerGlobals.ts
|
|
1284
|
-
function devServerGlobals(config) {
|
|
961
|
+
};
|
|
962
|
+
};
|
|
1285
963
|
return {
|
|
1286
|
-
name: "
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
964
|
+
name: "Vite",
|
|
965
|
+
version: vite.version,
|
|
966
|
+
async build(group) {
|
|
967
|
+
let entryConfig;
|
|
968
|
+
if (Array.isArray(group))
|
|
969
|
+
entryConfig = getMultiPageConfig(group);
|
|
970
|
+
else if (group.inputPath.endsWith(".css"))
|
|
971
|
+
entryConfig = getCssConfig(group);
|
|
972
|
+
else
|
|
973
|
+
entryConfig = getLibModeConfig(group);
|
|
974
|
+
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
|
|
975
|
+
const result = await vite.build(buildConfig);
|
|
1290
976
|
return {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
977
|
+
entrypoints: group,
|
|
978
|
+
chunks: getBuildOutputChunks(result)
|
|
979
|
+
};
|
|
980
|
+
},
|
|
981
|
+
async createServer(info) {
|
|
982
|
+
const serverConfig = {
|
|
983
|
+
server: {
|
|
984
|
+
port: info.port,
|
|
985
|
+
strictPort: true,
|
|
986
|
+
host: info.hostname,
|
|
987
|
+
origin: info.origin
|
|
1295
988
|
}
|
|
1296
989
|
};
|
|
990
|
+
const baseConfig = await getBaseConfig();
|
|
991
|
+
const viteServer = await vite.createServer(
|
|
992
|
+
vite.mergeConfig(baseConfig, serverConfig)
|
|
993
|
+
);
|
|
994
|
+
const server2 = {
|
|
995
|
+
async listen() {
|
|
996
|
+
await viteServer.listen(info.port);
|
|
997
|
+
},
|
|
998
|
+
async close() {
|
|
999
|
+
await viteServer.close();
|
|
1000
|
+
},
|
|
1001
|
+
transformHtml(...args) {
|
|
1002
|
+
return viteServer.transformIndexHtml(...args);
|
|
1003
|
+
},
|
|
1004
|
+
ws: {
|
|
1005
|
+
send(message, payload) {
|
|
1006
|
+
return viteServer.ws.send(message, payload);
|
|
1007
|
+
},
|
|
1008
|
+
on(message, cb) {
|
|
1009
|
+
viteServer.ws.on(message, cb);
|
|
1010
|
+
}
|
|
1011
|
+
},
|
|
1012
|
+
watcher: viteServer.watcher
|
|
1013
|
+
};
|
|
1014
|
+
return server2;
|
|
1297
1015
|
}
|
|
1298
1016
|
};
|
|
1299
1017
|
}
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
if (duration < 1e3)
|
|
1307
|
-
return `${duration} ms`;
|
|
1308
|
-
if (duration < 1e4)
|
|
1309
|
-
return `${(duration / 1e3).toFixed(3)} s`;
|
|
1310
|
-
if (duration < 6e4)
|
|
1311
|
-
return `${(duration / 1e3).toFixed(1)} s`;
|
|
1312
|
-
return `${(duration / 1e3).toFixed(0)} s`;
|
|
1018
|
+
function getBuildOutputChunks(result) {
|
|
1019
|
+
if ("on" in result)
|
|
1020
|
+
throw Error("wxt does not support vite watch mode.");
|
|
1021
|
+
if (Array.isArray(result))
|
|
1022
|
+
return result.flatMap(({ output }) => output);
|
|
1023
|
+
return result.output;
|
|
1313
1024
|
}
|
|
1314
|
-
function
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1025
|
+
function getRollupEntry(entrypoint) {
|
|
1026
|
+
let virtualEntrypointType;
|
|
1027
|
+
switch (entrypoint.type) {
|
|
1028
|
+
case "background":
|
|
1029
|
+
case "unlisted-script":
|
|
1030
|
+
virtualEntrypointType = entrypoint.type;
|
|
1031
|
+
break;
|
|
1032
|
+
case "content-script":
|
|
1033
|
+
virtualEntrypointType = entrypoint.options.world === "MAIN" ? "content-script-main-world" : "content-script-isolated-world";
|
|
1034
|
+
break;
|
|
1035
|
+
}
|
|
1036
|
+
return virtualEntrypointType ? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}` : entrypoint.inputPath;
|
|
1321
1037
|
}
|
|
1322
1038
|
|
|
1323
|
-
// src/core/
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
async function isOnline() {
|
|
1337
|
-
const offline = await isOffline();
|
|
1338
|
-
return !offline;
|
|
1339
|
-
}
|
|
1340
|
-
async function fetchCached(url, config) {
|
|
1341
|
-
let content = "";
|
|
1342
|
-
if (await isOnline()) {
|
|
1343
|
-
const res = await fetch(url);
|
|
1344
|
-
if (res.status < 300) {
|
|
1345
|
-
content = await res.text();
|
|
1346
|
-
await config.fsCache.set(url, content);
|
|
1347
|
-
} else {
|
|
1348
|
-
config.logger.debug(
|
|
1349
|
-
`Failed to download "${url}", falling back to cache...`
|
|
1350
|
-
);
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
if (!content)
|
|
1354
|
-
content = await config.fsCache.get(url) ?? "";
|
|
1355
|
-
if (!content)
|
|
1356
|
-
throw Error(
|
|
1357
|
-
`Offline and "${url}" has not been cached. Try again when online.`
|
|
1358
|
-
);
|
|
1359
|
-
return content;
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// src/core/builders/vite/plugins/download.ts
|
|
1363
|
-
function download(config) {
|
|
1364
|
-
return {
|
|
1365
|
-
name: "wxt:download",
|
|
1366
|
-
resolveId(id) {
|
|
1367
|
-
if (id.startsWith("url:"))
|
|
1368
|
-
return "\0" + id;
|
|
1039
|
+
// src/core/wxt.ts
|
|
1040
|
+
var wxt;
|
|
1041
|
+
async function registerWxt(command, inlineConfig = {}, getServer) {
|
|
1042
|
+
const hooks = createHooks();
|
|
1043
|
+
const config = await resolveConfig(inlineConfig, command);
|
|
1044
|
+
const server = await getServer?.(config);
|
|
1045
|
+
const builder = await createViteBuilder(config, server);
|
|
1046
|
+
const pm = await createWxtPackageManager(config.root);
|
|
1047
|
+
wxt = {
|
|
1048
|
+
config,
|
|
1049
|
+
hooks,
|
|
1050
|
+
get logger() {
|
|
1051
|
+
return config.logger;
|
|
1369
1052
|
},
|
|
1370
|
-
async
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1053
|
+
async reloadConfig() {
|
|
1054
|
+
wxt.config = await resolveConfig(inlineConfig, command);
|
|
1055
|
+
},
|
|
1056
|
+
pm,
|
|
1057
|
+
builder,
|
|
1058
|
+
server
|
|
1376
1059
|
};
|
|
1060
|
+
wxt.hooks.addHooks(config.hooks);
|
|
1061
|
+
await wxt.hooks.callHook("ready", wxt);
|
|
1377
1062
|
}
|
|
1378
1063
|
|
|
1379
|
-
// src/core/
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
name: "wxt:multipage-move",
|
|
1385
|
-
async writeBundle(_, bundle) {
|
|
1386
|
-
for (const oldBundlePath in bundle) {
|
|
1387
|
-
const entrypoint = entrypoints.find(
|
|
1388
|
-
(entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath)
|
|
1389
|
-
);
|
|
1390
|
-
if (entrypoint == null) {
|
|
1391
|
-
config.logger.debug(
|
|
1392
|
-
`No entrypoint found for ${oldBundlePath}, leaving in chunks directory`
|
|
1393
|
-
);
|
|
1394
|
-
continue;
|
|
1395
|
-
}
|
|
1396
|
-
const newBundlePath = getEntrypointBundlePath(
|
|
1397
|
-
entrypoint,
|
|
1398
|
-
config.outDir,
|
|
1399
|
-
extname(oldBundlePath)
|
|
1400
|
-
);
|
|
1401
|
-
if (newBundlePath === oldBundlePath) {
|
|
1402
|
-
config.logger.debug(
|
|
1403
|
-
"HTML file is already in the correct location",
|
|
1404
|
-
oldBundlePath
|
|
1405
|
-
);
|
|
1406
|
-
continue;
|
|
1407
|
-
}
|
|
1408
|
-
const oldAbsPath = resolve7(config.outDir, oldBundlePath);
|
|
1409
|
-
const newAbsPath = resolve7(config.outDir, newBundlePath);
|
|
1410
|
-
await ensureDir3(dirname4(newAbsPath));
|
|
1411
|
-
await fs6.move(oldAbsPath, newAbsPath, { overwrite: true });
|
|
1412
|
-
const renamedChunk = {
|
|
1413
|
-
...bundle[oldBundlePath],
|
|
1414
|
-
fileName: newBundlePath
|
|
1415
|
-
};
|
|
1416
|
-
delete bundle[oldBundlePath];
|
|
1417
|
-
bundle[newBundlePath] = renamedChunk;
|
|
1418
|
-
}
|
|
1419
|
-
removeEmptyDirs(config.outDir);
|
|
1420
|
-
}
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
async function removeEmptyDirs(dir) {
|
|
1424
|
-
const files = await fs6.readdir(dir);
|
|
1425
|
-
for (const file of files) {
|
|
1426
|
-
const filePath = join(dir, file);
|
|
1427
|
-
const stats = await fs6.stat(filePath);
|
|
1428
|
-
if (stats.isDirectory()) {
|
|
1429
|
-
await removeEmptyDirs(filePath);
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
try {
|
|
1433
|
-
await fs6.rmdir(dir);
|
|
1434
|
-
} catch {
|
|
1064
|
+
// src/core/utils/fs.ts
|
|
1065
|
+
async function writeFileIfDifferent(file, newContents) {
|
|
1066
|
+
const existingContents = await fs3.readFile(file, "utf-8").catch(() => void 0);
|
|
1067
|
+
if (existingContents !== newContents) {
|
|
1068
|
+
await fs3.writeFile(file, newContents);
|
|
1435
1069
|
}
|
|
1436
1070
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
import { createUnimport as createUnimport2 } from "unimport";
|
|
1440
|
-
import { extname as extname2 } from "path";
|
|
1441
|
-
var ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1442
|
-
".js",
|
|
1443
|
-
".jsx",
|
|
1444
|
-
".ts",
|
|
1445
|
-
".tsx",
|
|
1446
|
-
".vue",
|
|
1447
|
-
".svelte"
|
|
1448
|
-
]);
|
|
1449
|
-
function unimport(config) {
|
|
1450
|
-
const options = config.imports;
|
|
1451
|
-
if (options === false)
|
|
1071
|
+
async function getPublicFiles() {
|
|
1072
|
+
if (!await fs3.exists(wxt.config.publicDir))
|
|
1452
1073
|
return [];
|
|
1453
|
-
const
|
|
1454
|
-
return
|
|
1455
|
-
name: "wxt:unimport",
|
|
1456
|
-
async config() {
|
|
1457
|
-
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
1458
|
-
},
|
|
1459
|
-
async transform(code, id) {
|
|
1460
|
-
if (id.includes("node_modules"))
|
|
1461
|
-
return;
|
|
1462
|
-
if (!ENABLED_EXTENSIONS.has(extname2(id)))
|
|
1463
|
-
return;
|
|
1464
|
-
const injected = await unimport2.injectImports(code, id);
|
|
1465
|
-
return {
|
|
1466
|
-
code: injected.code,
|
|
1467
|
-
map: injected.s.generateMap({ hires: "boundary", source: id })
|
|
1468
|
-
};
|
|
1469
|
-
}
|
|
1470
|
-
};
|
|
1074
|
+
const files = await glob("**/*", { cwd: wxt.config.publicDir });
|
|
1075
|
+
return files.map(unnormalizePath);
|
|
1471
1076
|
}
|
|
1472
1077
|
|
|
1473
|
-
// src/core/
|
|
1474
|
-
import
|
|
1475
|
-
import { resolve as
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
return;
|
|
1491
|
-
const inputPath = id.replace(resolvedVirtualId, "");
|
|
1492
|
-
const template = await fs7.readFile(
|
|
1493
|
-
resolve8(config.wxtModuleDir, `dist/virtual/${type}-entrypoint.js`),
|
|
1494
|
-
"utf-8"
|
|
1495
|
-
);
|
|
1496
|
-
return template.replace(`virtual:user-${type}`, inputPath);
|
|
1078
|
+
// src/core/utils/building/build-entrypoints.ts
|
|
1079
|
+
import fs4 from "fs-extra";
|
|
1080
|
+
import { dirname as dirname3, resolve as resolve5 } from "path";
|
|
1081
|
+
import pc from "picocolors";
|
|
1082
|
+
async function buildEntrypoints(groups, spinner) {
|
|
1083
|
+
const steps = [];
|
|
1084
|
+
for (let i = 0; i < groups.length; i++) {
|
|
1085
|
+
const group = groups[i];
|
|
1086
|
+
const groupNames = [group].flat().map((e) => e.name);
|
|
1087
|
+
const groupNameColored = groupNames.join(pc.dim(", "));
|
|
1088
|
+
spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
|
1089
|
+
try {
|
|
1090
|
+
steps.push(await wxt.builder.build(group));
|
|
1091
|
+
} catch (err) {
|
|
1092
|
+
spinner.stop().clear();
|
|
1093
|
+
wxt.logger.error(err);
|
|
1094
|
+
throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
|
|
1497
1095
|
}
|
|
1498
|
-
}
|
|
1096
|
+
}
|
|
1097
|
+
const publicAssets = await copyPublicDirectory();
|
|
1098
|
+
return { publicAssets, steps };
|
|
1499
1099
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1100
|
+
async function copyPublicDirectory() {
|
|
1101
|
+
const files = await getPublicFiles();
|
|
1102
|
+
if (files.length === 0)
|
|
1103
|
+
return [];
|
|
1104
|
+
const publicAssets = [];
|
|
1105
|
+
for (const file of files) {
|
|
1106
|
+
const srcPath = resolve5(wxt.config.publicDir, file);
|
|
1107
|
+
const outPath = resolve5(wxt.config.outDir, file);
|
|
1108
|
+
await fs4.ensureDir(dirname3(outPath));
|
|
1109
|
+
await fs4.copyFile(srcPath, outPath);
|
|
1110
|
+
publicAssets.push({
|
|
1111
|
+
type: "asset",
|
|
1112
|
+
fileName: file
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
return publicAssets;
|
|
1513
1116
|
}
|
|
1514
1117
|
|
|
1515
|
-
// src/core/
|
|
1516
|
-
function
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
return `import { defineBackground } from 'wxt/sandbox';
|
|
1528
|
-
export default defineBackground(() => void 0)`;
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
};
|
|
1118
|
+
// src/core/utils/arrays.ts
|
|
1119
|
+
function every(array, predicate) {
|
|
1120
|
+
for (let i = 0; i < array.length; i++)
|
|
1121
|
+
if (!predicate(array[i], i))
|
|
1122
|
+
return false;
|
|
1123
|
+
return true;
|
|
1124
|
+
}
|
|
1125
|
+
function some(array, predicate) {
|
|
1126
|
+
for (let i = 0; i < array.length; i++)
|
|
1127
|
+
if (predicate(array[i], i))
|
|
1128
|
+
return true;
|
|
1129
|
+
return false;
|
|
1532
1130
|
}
|
|
1533
1131
|
|
|
1534
|
-
// src/core/
|
|
1535
|
-
function
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
if (file.endsWith(".js"))
|
|
1552
|
-
delete bundle[file];
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
// src/core/builders/vite/plugins/bundleAnalysis.ts
|
|
1559
|
-
import { visualizer } from "@aklinker1/rollup-plugin-visualizer";
|
|
1560
|
-
import path4 from "node:path";
|
|
1561
|
-
var increment = 0;
|
|
1562
|
-
function bundleAnalysis(config) {
|
|
1563
|
-
return visualizer({
|
|
1564
|
-
template: "raw-data",
|
|
1565
|
-
filename: path4.resolve(
|
|
1566
|
-
config.analysis.outputDir,
|
|
1567
|
-
`${config.analysis.outputName}-${increment++}.json`
|
|
1132
|
+
// src/core/utils/building/detect-dev-changes.ts
|
|
1133
|
+
function detectDevChanges(changedFiles, currentOutput) {
|
|
1134
|
+
const isConfigChange = some(
|
|
1135
|
+
changedFiles,
|
|
1136
|
+
(file) => file === wxt.config.userConfigMetadata.configFile
|
|
1137
|
+
);
|
|
1138
|
+
if (isConfigChange)
|
|
1139
|
+
return { type: "full-restart" };
|
|
1140
|
+
const isRunnerChange = some(
|
|
1141
|
+
changedFiles,
|
|
1142
|
+
(file) => file === wxt.config.runnerConfig.configFile
|
|
1143
|
+
);
|
|
1144
|
+
if (isRunnerChange)
|
|
1145
|
+
return { type: "browser-restart" };
|
|
1146
|
+
const changedSteps = new Set(
|
|
1147
|
+
changedFiles.flatMap(
|
|
1148
|
+
(changedFile) => findEffectedSteps(changedFile, currentOutput)
|
|
1568
1149
|
)
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
config() {
|
|
1577
|
-
const define = {};
|
|
1578
|
-
for (const global of getGlobals(config)) {
|
|
1579
|
-
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
1580
|
-
}
|
|
1581
|
-
return {
|
|
1582
|
-
define
|
|
1583
|
-
};
|
|
1584
|
-
}
|
|
1150
|
+
);
|
|
1151
|
+
if (changedSteps.size === 0)
|
|
1152
|
+
return { type: "no-change" };
|
|
1153
|
+
const unchangedOutput = {
|
|
1154
|
+
manifest: currentOutput.manifest,
|
|
1155
|
+
steps: [],
|
|
1156
|
+
publicAssets: []
|
|
1585
1157
|
};
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
const virtualId = "virtual:wxt-webextension-polyfill-disabled";
|
|
1591
|
-
return {
|
|
1592
|
-
name: "wxt:exclude-browser-polyfill",
|
|
1593
|
-
config() {
|
|
1594
|
-
if (config.experimental.includeBrowserPolyfill)
|
|
1595
|
-
return;
|
|
1596
|
-
return {
|
|
1597
|
-
resolve: {
|
|
1598
|
-
alias: {
|
|
1599
|
-
"webextension-polyfill": virtualId
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
};
|
|
1603
|
-
},
|
|
1604
|
-
load(id) {
|
|
1605
|
-
if (id === virtualId) {
|
|
1606
|
-
return "export default chrome";
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1158
|
+
const changedOutput = {
|
|
1159
|
+
manifest: currentOutput.manifest,
|
|
1160
|
+
steps: [],
|
|
1161
|
+
publicAssets: []
|
|
1609
1162
|
};
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
name: "wxt:entrypoint-group-globals",
|
|
1616
|
-
config() {
|
|
1617
|
-
const define = {};
|
|
1618
|
-
let name = Array.isArray(entrypointGroup) ? "html" : entrypointGroup.name;
|
|
1619
|
-
for (const global of getEntrypointGlobals(name)) {
|
|
1620
|
-
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
1621
|
-
}
|
|
1622
|
-
return {
|
|
1623
|
-
define
|
|
1624
|
-
};
|
|
1163
|
+
for (const step of currentOutput.steps) {
|
|
1164
|
+
if (changedSteps.has(step)) {
|
|
1165
|
+
changedOutput.steps.push(step);
|
|
1166
|
+
} else {
|
|
1167
|
+
unchangedOutput.steps.push(step);
|
|
1625
1168
|
}
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
name: "wxt:define",
|
|
1633
|
-
config() {
|
|
1634
|
-
return {
|
|
1635
|
-
define: {
|
|
1636
|
-
// This works for all extension contexts, including background service worker
|
|
1637
|
-
"import.meta.url": "self.location.href"
|
|
1638
|
-
}
|
|
1639
|
-
};
|
|
1169
|
+
}
|
|
1170
|
+
for (const asset of currentOutput.publicAssets) {
|
|
1171
|
+
if (changedSteps.has(asset)) {
|
|
1172
|
+
changedOutput.publicAssets.push(asset);
|
|
1173
|
+
} else {
|
|
1174
|
+
unchangedOutput.publicAssets.push(asset);
|
|
1640
1175
|
}
|
|
1176
|
+
}
|
|
1177
|
+
const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
|
|
1178
|
+
if (isOnlyHtmlChanges) {
|
|
1179
|
+
return {
|
|
1180
|
+
type: "html-reload",
|
|
1181
|
+
cachedOutput: unchangedOutput,
|
|
1182
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
|
|
1186
|
+
changedOutput.steps.flatMap((step) => step.entrypoints),
|
|
1187
|
+
(entry) => entry.type === "content-script"
|
|
1188
|
+
);
|
|
1189
|
+
if (isOnlyContentScripts) {
|
|
1190
|
+
return {
|
|
1191
|
+
type: "content-script-reload",
|
|
1192
|
+
cachedOutput: unchangedOutput,
|
|
1193
|
+
changedSteps: changedOutput.steps,
|
|
1194
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
return {
|
|
1198
|
+
type: "extension-reload",
|
|
1199
|
+
cachedOutput: unchangedOutput,
|
|
1200
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
1641
1201
|
};
|
|
1642
1202
|
}
|
|
1203
|
+
function findEffectedSteps(changedFile, currentOutput) {
|
|
1204
|
+
const changes = [];
|
|
1205
|
+
const changedPath = normalizePath(changedFile);
|
|
1206
|
+
const isChunkEffected = (chunk) => (
|
|
1207
|
+
// If it's an HTML file with the same path, is is effected because HTML files need to be re-rendered
|
|
1208
|
+
// - fileName is normalized, relative bundle path, "<entrypoint-name>.html"
|
|
1209
|
+
chunk.type === "asset" && changedPath.replace("/index.html", ".html").endsWith(chunk.fileName) || // If it's a chunk that depends on the changed file, it is effected
|
|
1210
|
+
// - moduleIds are absolute, normalized paths
|
|
1211
|
+
chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
|
|
1212
|
+
);
|
|
1213
|
+
for (const step of currentOutput.steps) {
|
|
1214
|
+
const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
|
|
1215
|
+
if (effectedChunk)
|
|
1216
|
+
changes.push(step);
|
|
1217
|
+
}
|
|
1218
|
+
const effectedAsset = currentOutput.publicAssets.find(
|
|
1219
|
+
(chunk) => isChunkEffected(chunk)
|
|
1220
|
+
);
|
|
1221
|
+
if (effectedAsset)
|
|
1222
|
+
changes.push(effectedAsset);
|
|
1223
|
+
return changes;
|
|
1224
|
+
}
|
|
1643
1225
|
|
|
1644
|
-
// src/core/
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
config.
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
config.
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
}
|
|
1664
|
-
if (config.build.sourcemap == null && wxtConfig.command === "serve") {
|
|
1665
|
-
config.build.sourcemap = "inline";
|
|
1666
|
-
}
|
|
1667
|
-
config.plugins ??= [];
|
|
1668
|
-
config.plugins.push(
|
|
1669
|
-
download(wxtConfig),
|
|
1670
|
-
devHtmlPrerender(wxtConfig),
|
|
1671
|
-
unimport(wxtConfig),
|
|
1672
|
-
virtualEntrypoint("background", wxtConfig),
|
|
1673
|
-
virtualEntrypoint("content-script-isolated-world", wxtConfig),
|
|
1674
|
-
virtualEntrypoint("content-script-main-world", wxtConfig),
|
|
1675
|
-
virtualEntrypoint("unlisted-script", wxtConfig),
|
|
1676
|
-
devServerGlobals(wxtConfig),
|
|
1677
|
-
tsconfigPaths(wxtConfig),
|
|
1678
|
-
noopBackground(),
|
|
1679
|
-
globals(wxtConfig),
|
|
1680
|
-
excludeBrowserPolyfill(wxtConfig),
|
|
1681
|
-
defineImportMeta()
|
|
1226
|
+
// src/core/utils/building/find-entrypoints.ts
|
|
1227
|
+
import { relative as relative3, resolve as resolve6 } from "path";
|
|
1228
|
+
import fs5 from "fs-extra";
|
|
1229
|
+
import { minimatch } from "minimatch";
|
|
1230
|
+
import { parseHTML as parseHTML2 } from "linkedom";
|
|
1231
|
+
import JSON5 from "json5";
|
|
1232
|
+
import glob2 from "fast-glob";
|
|
1233
|
+
import pc2 from "picocolors";
|
|
1234
|
+
async function findEntrypoints() {
|
|
1235
|
+
const relativePaths = await glob2(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
|
|
1236
|
+
cwd: wxt.config.entrypointsDir
|
|
1237
|
+
});
|
|
1238
|
+
relativePaths.sort();
|
|
1239
|
+
const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
|
|
1240
|
+
const entrypointInfos = relativePaths.reduce((results, relativePath) => {
|
|
1241
|
+
const inputPath = resolve6(wxt.config.entrypointsDir, relativePath);
|
|
1242
|
+
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
|
|
1243
|
+
const matchingGlob = pathGlobs.find(
|
|
1244
|
+
(glob6) => minimatch(relativePath, glob6)
|
|
1682
1245
|
);
|
|
1683
|
-
if (
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
entrypointGroupGlobals(entrypoint)
|
|
1692
|
-
];
|
|
1693
|
-
if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
|
|
1694
|
-
plugins.push(cssEntrypoints(entrypoint, wxtConfig));
|
|
1246
|
+
if (matchingGlob) {
|
|
1247
|
+
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
|
|
1248
|
+
results.push({
|
|
1249
|
+
name,
|
|
1250
|
+
inputPath,
|
|
1251
|
+
type,
|
|
1252
|
+
skipped: wxt.config.filterEntrypoints != null && !wxt.config.filterEntrypoints.has(name)
|
|
1253
|
+
});
|
|
1695
1254
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1255
|
+
return results;
|
|
1256
|
+
}, []);
|
|
1257
|
+
preventNoEntrypoints(entrypointInfos);
|
|
1258
|
+
preventDuplicateEntrypointNames(entrypointInfos);
|
|
1259
|
+
let hasBackground = false;
|
|
1260
|
+
const entrypoints = await Promise.all(
|
|
1261
|
+
entrypointInfos.map(async (info) => {
|
|
1262
|
+
const { type } = info;
|
|
1263
|
+
switch (type) {
|
|
1264
|
+
case "popup":
|
|
1265
|
+
return await getPopupEntrypoint(info);
|
|
1266
|
+
case "sidepanel":
|
|
1267
|
+
return await getSidepanelEntrypoint(info);
|
|
1268
|
+
case "options":
|
|
1269
|
+
return await getOptionsEntrypoint(info);
|
|
1270
|
+
case "background":
|
|
1271
|
+
hasBackground = true;
|
|
1272
|
+
return await getBackgroundEntrypoint(info);
|
|
1273
|
+
case "content-script":
|
|
1274
|
+
return await getContentScriptEntrypoint(info);
|
|
1275
|
+
case "unlisted-page":
|
|
1276
|
+
return await getUnlistedPageEntrypoint(info);
|
|
1277
|
+
case "unlisted-script":
|
|
1278
|
+
return await getUnlistedScriptEntrypoint(info);
|
|
1279
|
+
case "content-script-style":
|
|
1280
|
+
return {
|
|
1281
|
+
...info,
|
|
1282
|
+
type,
|
|
1283
|
+
outputDir: resolve6(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
1284
|
+
options: {
|
|
1285
|
+
include: void 0,
|
|
1286
|
+
exclude: void 0
|
|
1723
1287
|
}
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1288
|
+
};
|
|
1289
|
+
default:
|
|
1290
|
+
return {
|
|
1291
|
+
...info,
|
|
1292
|
+
type,
|
|
1293
|
+
outputDir: wxt.config.outDir,
|
|
1294
|
+
options: {
|
|
1295
|
+
include: void 0,
|
|
1296
|
+
exclude: void 0
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1730
1299
|
}
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1300
|
+
})
|
|
1301
|
+
);
|
|
1302
|
+
if (wxt.config.command === "serve" && !hasBackground) {
|
|
1303
|
+
entrypoints.push(
|
|
1304
|
+
await getBackgroundEntrypoint({
|
|
1305
|
+
inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
|
|
1306
|
+
name: "background",
|
|
1307
|
+
type: "background",
|
|
1308
|
+
skipped: false
|
|
1309
|
+
})
|
|
1737
1310
|
);
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1311
|
+
}
|
|
1312
|
+
wxt.logger.debug("All entrypoints:", entrypoints);
|
|
1313
|
+
const skippedEntrypointNames = entrypointInfos.filter((item) => item.skipped).map((item) => item.name);
|
|
1314
|
+
if (skippedEntrypointNames.length) {
|
|
1315
|
+
wxt.logger.warn(
|
|
1316
|
+
`Filter excluded the following entrypoints:
|
|
1317
|
+
${skippedEntrypointNames.map((item) => `${pc2.dim("-")} ${pc2.cyan(item)}`).join("\n")}`
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
const targetEntrypoints = entrypoints.filter((entry) => {
|
|
1321
|
+
const { include, exclude } = entry.options;
|
|
1322
|
+
if (include?.length && exclude?.length) {
|
|
1323
|
+
wxt.logger.warn(
|
|
1324
|
+
`The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
|
|
1325
|
+
);
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1328
|
+
if (exclude?.length && !include?.length) {
|
|
1329
|
+
return !exclude.includes(wxt.config.browser);
|
|
1330
|
+
}
|
|
1331
|
+
if (include?.length && !exclude?.length) {
|
|
1332
|
+
return include.includes(wxt.config.browser);
|
|
1333
|
+
}
|
|
1334
|
+
if (skippedEntrypointNames.includes(entry.name)) {
|
|
1335
|
+
return false;
|
|
1336
|
+
}
|
|
1337
|
+
return true;
|
|
1338
|
+
});
|
|
1339
|
+
wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
|
|
1340
|
+
await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
|
|
1341
|
+
return targetEntrypoints;
|
|
1342
|
+
}
|
|
1343
|
+
function preventDuplicateEntrypointNames(files) {
|
|
1344
|
+
const namesToPaths = files.reduce(
|
|
1345
|
+
(map, { name, inputPath }) => {
|
|
1346
|
+
map[name] ??= [];
|
|
1347
|
+
map[name].push(inputPath);
|
|
1348
|
+
return map;
|
|
1349
|
+
},
|
|
1350
|
+
{}
|
|
1351
|
+
);
|
|
1352
|
+
const errorLines = Object.entries(namesToPaths).reduce(
|
|
1353
|
+
(lines, [name, absolutePaths]) => {
|
|
1354
|
+
if (absolutePaths.length > 1) {
|
|
1355
|
+
lines.push(`- ${name}`);
|
|
1356
|
+
absolutePaths.forEach((absolutePath) => {
|
|
1357
|
+
lines.push(` - ${relative3(wxt.config.root, absolutePath)}`);
|
|
1358
|
+
});
|
|
1762
1359
|
}
|
|
1763
|
-
|
|
1360
|
+
return lines;
|
|
1361
|
+
},
|
|
1362
|
+
[]
|
|
1363
|
+
);
|
|
1364
|
+
if (errorLines.length > 0) {
|
|
1365
|
+
const errorContent = errorLines.join("\n");
|
|
1366
|
+
throw Error(
|
|
1367
|
+
`Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
|
|
1368
|
+
|
|
1369
|
+
${errorContent}`
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
function preventNoEntrypoints(files) {
|
|
1374
|
+
if (files.length === 0) {
|
|
1375
|
+
throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
async function getPopupEntrypoint(info) {
|
|
1379
|
+
const options = await getHtmlEntrypointOptions(
|
|
1380
|
+
info,
|
|
1381
|
+
{
|
|
1382
|
+
browserStyle: "browse_style",
|
|
1383
|
+
exclude: "exclude",
|
|
1384
|
+
include: "include",
|
|
1385
|
+
defaultIcon: "default_icon",
|
|
1386
|
+
defaultTitle: "default_title",
|
|
1387
|
+
mv2Key: "type"
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
defaultTitle: (content) => content,
|
|
1394
|
+
mv2Key: (content) => content === "page_action" ? "page_action" : "browser_action"
|
|
1395
|
+
}
|
|
1396
|
+
);
|
|
1397
|
+
return {
|
|
1398
|
+
type: "popup",
|
|
1399
|
+
name: "popup",
|
|
1400
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1401
|
+
inputPath: info.inputPath,
|
|
1402
|
+
outputDir: wxt.config.outDir,
|
|
1403
|
+
skipped: info.skipped
|
|
1764
1404
|
};
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1405
|
+
}
|
|
1406
|
+
async function getOptionsEntrypoint(info) {
|
|
1407
|
+
const options = await getHtmlEntrypointOptions(
|
|
1408
|
+
info,
|
|
1409
|
+
{
|
|
1410
|
+
browserStyle: "browse_style",
|
|
1411
|
+
chromeStyle: "chrome_style",
|
|
1412
|
+
exclude: "exclude",
|
|
1413
|
+
include: "include",
|
|
1414
|
+
openInTab: "open_in_tab"
|
|
1415
|
+
}
|
|
1416
|
+
);
|
|
1417
|
+
return {
|
|
1418
|
+
type: "options",
|
|
1419
|
+
name: "options",
|
|
1420
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1421
|
+
inputPath: info.inputPath,
|
|
1422
|
+
outputDir: wxt.config.outDir,
|
|
1423
|
+
skipped: info.skipped
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
async function getUnlistedPageEntrypoint(info) {
|
|
1427
|
+
const options = await getHtmlEntrypointOptions(info, {
|
|
1428
|
+
exclude: "exclude",
|
|
1429
|
+
include: "include"
|
|
1430
|
+
});
|
|
1431
|
+
return {
|
|
1432
|
+
type: "unlisted-page",
|
|
1433
|
+
name: info.name,
|
|
1434
|
+
inputPath: info.inputPath,
|
|
1435
|
+
outputDir: wxt.config.outDir,
|
|
1436
|
+
options,
|
|
1437
|
+
skipped: info.skipped
|
|
1786
1438
|
};
|
|
1439
|
+
}
|
|
1440
|
+
async function getUnlistedScriptEntrypoint({
|
|
1441
|
+
inputPath,
|
|
1442
|
+
name,
|
|
1443
|
+
skipped
|
|
1444
|
+
}) {
|
|
1445
|
+
const defaultExport = await importEntrypointFile(inputPath);
|
|
1446
|
+
if (defaultExport == null) {
|
|
1447
|
+
throw Error(
|
|
1448
|
+
`${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
const { main: _, ...options } = defaultExport;
|
|
1452
|
+
return {
|
|
1453
|
+
type: "unlisted-script",
|
|
1454
|
+
name,
|
|
1455
|
+
inputPath,
|
|
1456
|
+
outputDir: wxt.config.outDir,
|
|
1457
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1458
|
+
skipped
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
async function getBackgroundEntrypoint({
|
|
1462
|
+
inputPath,
|
|
1463
|
+
name,
|
|
1464
|
+
skipped
|
|
1465
|
+
}) {
|
|
1466
|
+
let options = {};
|
|
1467
|
+
if (inputPath !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
|
|
1468
|
+
const defaultExport = await importEntrypointFile(inputPath);
|
|
1469
|
+
if (defaultExport == null) {
|
|
1470
|
+
throw Error(
|
|
1471
|
+
`${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
const { main: _, ...moduleOptions } = defaultExport;
|
|
1475
|
+
options = moduleOptions;
|
|
1476
|
+
}
|
|
1477
|
+
if (wxt.config.manifestVersion !== 3) {
|
|
1478
|
+
delete options.type;
|
|
1479
|
+
}
|
|
1480
|
+
return {
|
|
1481
|
+
type: "background",
|
|
1482
|
+
name,
|
|
1483
|
+
inputPath,
|
|
1484
|
+
outputDir: wxt.config.outDir,
|
|
1485
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1486
|
+
skipped
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
async function getContentScriptEntrypoint({
|
|
1490
|
+
inputPath,
|
|
1491
|
+
name,
|
|
1492
|
+
skipped
|
|
1493
|
+
}) {
|
|
1494
|
+
const { main: _, ...options } = await importEntrypointFile(inputPath);
|
|
1495
|
+
if (options == null) {
|
|
1496
|
+
throw Error(
|
|
1497
|
+
`${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1500
|
+
return {
|
|
1501
|
+
type: "content-script",
|
|
1502
|
+
name,
|
|
1503
|
+
inputPath,
|
|
1504
|
+
outputDir: resolve6(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
1505
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1506
|
+
skipped
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
async function getSidepanelEntrypoint(info) {
|
|
1510
|
+
const options = await getHtmlEntrypointOptions(
|
|
1511
|
+
info,
|
|
1512
|
+
{
|
|
1513
|
+
browserStyle: "browse_style",
|
|
1514
|
+
exclude: "exclude",
|
|
1515
|
+
include: "include",
|
|
1516
|
+
defaultIcon: "default_icon",
|
|
1517
|
+
defaultTitle: "default_title",
|
|
1518
|
+
openAtInstall: "open_at_install"
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
defaultTitle: (content) => content
|
|
1525
|
+
}
|
|
1526
|
+
);
|
|
1527
|
+
return {
|
|
1528
|
+
type: "sidepanel",
|
|
1529
|
+
name: info.name,
|
|
1530
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1531
|
+
inputPath: info.inputPath,
|
|
1532
|
+
outputDir: wxt.config.outDir,
|
|
1533
|
+
skipped: info.skipped
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
|
|
1537
|
+
const content = await fs5.readFile(info.inputPath, "utf-8");
|
|
1538
|
+
const { document } = parseHTML2(content);
|
|
1539
|
+
const options = {};
|
|
1540
|
+
const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
|
|
1541
|
+
Object.entries(keyMap).forEach(([_key, manifestKey]) => {
|
|
1542
|
+
const key = _key;
|
|
1543
|
+
const content2 = queries?.[key] ? queries[key](document, manifestKey) : defaultQuery(manifestKey);
|
|
1544
|
+
if (content2) {
|
|
1545
|
+
try {
|
|
1546
|
+
options[key] = (parsers?.[key] ?? JSON5.parse)(content2);
|
|
1547
|
+
} catch (err) {
|
|
1548
|
+
wxt.logger.fatal(
|
|
1549
|
+
`Failed to parse meta tag content. Usually this means you have invalid JSON5 content (content=${content2})`,
|
|
1550
|
+
err
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
});
|
|
1555
|
+
return options;
|
|
1556
|
+
}
|
|
1557
|
+
var PATH_GLOB_TO_TYPE_MAP = {
|
|
1558
|
+
"sandbox.html": "sandbox",
|
|
1559
|
+
"sandbox/index.html": "sandbox",
|
|
1560
|
+
"*.sandbox.html": "sandbox",
|
|
1561
|
+
"*.sandbox/index.html": "sandbox",
|
|
1562
|
+
"bookmarks.html": "bookmarks",
|
|
1563
|
+
"bookmarks/index.html": "bookmarks",
|
|
1564
|
+
"history.html": "history",
|
|
1565
|
+
"history/index.html": "history",
|
|
1566
|
+
"newtab.html": "newtab",
|
|
1567
|
+
"newtab/index.html": "newtab",
|
|
1568
|
+
"sidepanel.html": "sidepanel",
|
|
1569
|
+
"sidepanel/index.html": "sidepanel",
|
|
1570
|
+
"*.sidepanel.html": "sidepanel",
|
|
1571
|
+
"*.sidepanel/index.html": "sidepanel",
|
|
1572
|
+
"devtools.html": "devtools",
|
|
1573
|
+
"devtools/index.html": "devtools",
|
|
1574
|
+
"background.[jt]s": "background",
|
|
1575
|
+
"background/index.[jt]s": "background",
|
|
1576
|
+
[VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
|
|
1577
|
+
"content.[jt]s?(x)": "content-script",
|
|
1578
|
+
"content/index.[jt]s?(x)": "content-script",
|
|
1579
|
+
"*.content.[jt]s?(x)": "content-script",
|
|
1580
|
+
"*.content/index.[jt]s?(x)": "content-script",
|
|
1581
|
+
[`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1582
|
+
[`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1583
|
+
[`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1584
|
+
[`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1585
|
+
"popup.html": "popup",
|
|
1586
|
+
"popup/index.html": "popup",
|
|
1587
|
+
"options.html": "options",
|
|
1588
|
+
"options/index.html": "options",
|
|
1589
|
+
"*.html": "unlisted-page",
|
|
1590
|
+
"*/index.html": "unlisted-page",
|
|
1591
|
+
"*.[jt]s?(x)": "unlisted-script",
|
|
1592
|
+
"*/index.[jt]s?(x)": "unlisted-script",
|
|
1593
|
+
[`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
|
|
1594
|
+
[`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
|
|
1595
|
+
};
|
|
1596
|
+
var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
|
|
1597
|
+
|
|
1598
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
1599
|
+
import { createUnimport as createUnimport2 } from "unimport";
|
|
1600
|
+
import fs6 from "fs-extra";
|
|
1601
|
+
import { relative as relative4, resolve as resolve7 } from "path";
|
|
1602
|
+
import path4 from "node:path";
|
|
1603
|
+
|
|
1604
|
+
// src/core/utils/i18n.ts
|
|
1605
|
+
var predefinedMessages = {
|
|
1606
|
+
"@@extension_id": {
|
|
1607
|
+
message: "<browser.runtime.id>",
|
|
1608
|
+
description: "The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message.\nNote: You can't use this message in a manifest file."
|
|
1609
|
+
},
|
|
1610
|
+
"@@ui_locale": {
|
|
1611
|
+
message: "<browser.i18n.getUiLocale()>",
|
|
1612
|
+
description: ""
|
|
1613
|
+
},
|
|
1614
|
+
"@@bidi_dir": {
|
|
1615
|
+
message: "<ltr|rtl>",
|
|
1616
|
+
description: 'The text direction for the current locale, either "ltr" for left-to-right languages such as English or "rtl" for right-to-left languages such as Japanese.'
|
|
1617
|
+
},
|
|
1618
|
+
"@@bidi_reversed_dir": {
|
|
1619
|
+
message: "<rtl|ltr>",
|
|
1620
|
+
description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
|
|
1621
|
+
},
|
|
1622
|
+
"@@bidi_start_edge": {
|
|
1623
|
+
message: "<left|right>",
|
|
1624
|
+
description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
|
|
1625
|
+
},
|
|
1626
|
+
"@@bidi_end_edge": {
|
|
1627
|
+
message: "<right|left>",
|
|
1628
|
+
description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
function parseI18nMessages(messagesJson) {
|
|
1632
|
+
return Object.entries({
|
|
1633
|
+
...predefinedMessages,
|
|
1634
|
+
...messagesJson
|
|
1635
|
+
}).map(([name, details]) => ({
|
|
1636
|
+
name,
|
|
1637
|
+
...details
|
|
1638
|
+
}));
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
1642
|
+
async function generateTypesDir(entrypoints) {
|
|
1643
|
+
await fs6.ensureDir(wxt.config.typesDir);
|
|
1644
|
+
const references = [];
|
|
1645
|
+
if (wxt.config.imports !== false) {
|
|
1646
|
+
const unimport2 = createUnimport2(wxt.config.imports);
|
|
1647
|
+
references.push(await writeImportsDeclarationFile(unimport2));
|
|
1648
|
+
if (wxt.config.imports.eslintrc.enabled) {
|
|
1649
|
+
await writeImportsEslintFile(unimport2, wxt.config.imports);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
references.push(await writePathsDeclarationFile(entrypoints));
|
|
1653
|
+
references.push(await writeI18nDeclarationFile());
|
|
1654
|
+
references.push(await writeGlobalsDeclarationFile());
|
|
1655
|
+
const mainReference = await writeMainDeclarationFile(references);
|
|
1656
|
+
await writeTsConfigFile(mainReference);
|
|
1657
|
+
}
|
|
1658
|
+
async function writeImportsDeclarationFile(unimport2) {
|
|
1659
|
+
const filePath = resolve7(wxt.config.typesDir, "imports.d.ts");
|
|
1660
|
+
await unimport2.scanImportsFromDir(void 0, { cwd: wxt.config.srcDir });
|
|
1661
|
+
await writeFileIfDifferent(
|
|
1662
|
+
filePath,
|
|
1663
|
+
["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
|
|
1664
|
+
"\n"
|
|
1665
|
+
) + "\n"
|
|
1666
|
+
);
|
|
1667
|
+
return filePath;
|
|
1668
|
+
}
|
|
1669
|
+
async function writeImportsEslintFile(unimport2, options) {
|
|
1670
|
+
const globals2 = {};
|
|
1671
|
+
const eslintrc = { globals: globals2 };
|
|
1672
|
+
(await unimport2.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().forEach((name) => {
|
|
1673
|
+
eslintrc.globals[name] = options.eslintrc.globalsPropValue;
|
|
1674
|
+
});
|
|
1675
|
+
await fs6.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
|
|
1676
|
+
}
|
|
1677
|
+
async function writePathsDeclarationFile(entrypoints) {
|
|
1678
|
+
const filePath = resolve7(wxt.config.typesDir, "paths.d.ts");
|
|
1679
|
+
const unions = entrypoints.map(
|
|
1680
|
+
(entry) => getEntrypointBundlePath(
|
|
1681
|
+
entry,
|
|
1682
|
+
wxt.config.outDir,
|
|
1683
|
+
isHtmlEntrypoint(entry) ? ".html" : ".js"
|
|
1684
|
+
)
|
|
1685
|
+
).concat(await getPublicFiles()).map(normalizePath).map((path10) => ` | "/${path10}"`).sort().join("\n");
|
|
1686
|
+
const template = `// Generated by wxt
|
|
1687
|
+
import "wxt/browser";
|
|
1688
|
+
|
|
1689
|
+
declare module "wxt/browser" {
|
|
1690
|
+
export type PublicPath =
|
|
1691
|
+
{{ union }}
|
|
1692
|
+
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
|
|
1693
|
+
export interface WxtRuntime extends Runtime.Static {
|
|
1694
|
+
getURL(path: PublicPath): string;
|
|
1695
|
+
getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
`;
|
|
1699
|
+
await writeFileIfDifferent(
|
|
1700
|
+
filePath,
|
|
1701
|
+
template.replace("{{ union }}", unions || " | never")
|
|
1702
|
+
);
|
|
1703
|
+
return filePath;
|
|
1704
|
+
}
|
|
1705
|
+
async function writeI18nDeclarationFile() {
|
|
1706
|
+
const filePath = resolve7(wxt.config.typesDir, "i18n.d.ts");
|
|
1707
|
+
const defaultLocale = wxt.config.manifest.default_locale;
|
|
1708
|
+
const template = `// Generated by wxt
|
|
1709
|
+
import "wxt/browser";
|
|
1710
|
+
|
|
1711
|
+
declare module "wxt/browser" {
|
|
1712
|
+
/**
|
|
1713
|
+
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
1714
|
+
*/
|
|
1715
|
+
interface GetMessageOptions {
|
|
1716
|
+
/**
|
|
1717
|
+
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
1718
|
+
*/
|
|
1719
|
+
escapeLt?: boolean
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
export interface WxtI18n extends I18n.Static {
|
|
1723
|
+
{{ overrides }}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
`;
|
|
1727
|
+
let messages;
|
|
1728
|
+
if (defaultLocale) {
|
|
1729
|
+
const defaultLocalePath = path4.resolve(
|
|
1730
|
+
wxt.config.publicDir,
|
|
1731
|
+
"_locales",
|
|
1732
|
+
defaultLocale,
|
|
1733
|
+
"messages.json"
|
|
1734
|
+
);
|
|
1735
|
+
const content = JSON.parse(await fs6.readFile(defaultLocalePath, "utf-8"));
|
|
1736
|
+
messages = parseI18nMessages(content);
|
|
1737
|
+
} else {
|
|
1738
|
+
messages = parseI18nMessages({});
|
|
1739
|
+
}
|
|
1740
|
+
const overrides = messages.map((message) => {
|
|
1741
|
+
return ` /**
|
|
1742
|
+
* ${message.description || "No message description."}
|
|
1743
|
+
*
|
|
1744
|
+
* "${message.message}"
|
|
1745
|
+
*/
|
|
1746
|
+
getMessage(
|
|
1747
|
+
messageName: "${message.name}",
|
|
1748
|
+
substitutions?: string | string[],
|
|
1749
|
+
options?: GetMessageOptions,
|
|
1750
|
+
): string;`;
|
|
1751
|
+
});
|
|
1752
|
+
await writeFileIfDifferent(
|
|
1753
|
+
filePath,
|
|
1754
|
+
template.replace("{{ overrides }}", overrides.join("\n"))
|
|
1755
|
+
);
|
|
1756
|
+
return filePath;
|
|
1757
|
+
}
|
|
1758
|
+
async function writeGlobalsDeclarationFile() {
|
|
1759
|
+
const filePath = resolve7(wxt.config.typesDir, "globals.d.ts");
|
|
1760
|
+
const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
|
|
1761
|
+
await writeFileIfDifferent(
|
|
1762
|
+
filePath,
|
|
1763
|
+
[
|
|
1764
|
+
"// Generated by wxt",
|
|
1765
|
+
"export {}",
|
|
1766
|
+
"interface ImportMetaEnv {",
|
|
1767
|
+
...globals2.map((global) => ` readonly ${global.name}: ${global.type};`),
|
|
1768
|
+
"}",
|
|
1769
|
+
"interface ImportMeta {",
|
|
1770
|
+
" readonly env: ImportMetaEnv",
|
|
1771
|
+
"}"
|
|
1772
|
+
].join("\n") + "\n"
|
|
1773
|
+
);
|
|
1774
|
+
return filePath;
|
|
1775
|
+
}
|
|
1776
|
+
async function writeMainDeclarationFile(references) {
|
|
1777
|
+
const dir = wxt.config.wxtDir;
|
|
1778
|
+
const filePath = resolve7(dir, "wxt.d.ts");
|
|
1779
|
+
await writeFileIfDifferent(
|
|
1780
|
+
filePath,
|
|
1781
|
+
[
|
|
1782
|
+
"// Generated by wxt",
|
|
1783
|
+
`/// <reference types="wxt/vite-builder-env" />`,
|
|
1784
|
+
...references.map(
|
|
1785
|
+
(ref) => `/// <reference types="./${normalizePath(relative4(dir, ref))}" />`
|
|
1786
|
+
)
|
|
1787
|
+
].join("\n") + "\n"
|
|
1788
|
+
);
|
|
1789
|
+
return filePath;
|
|
1790
|
+
}
|
|
1791
|
+
async function writeTsConfigFile(mainReference) {
|
|
1792
|
+
const dir = wxt.config.wxtDir;
|
|
1793
|
+
const getTsconfigPath = (path10) => normalizePath(relative4(dir, path10));
|
|
1794
|
+
const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
|
|
1795
|
+
const aliasPath = getTsconfigPath(absolutePath);
|
|
1796
|
+
return [
|
|
1797
|
+
` "${alias}": ["${aliasPath}"]`,
|
|
1798
|
+
` "${alias}/*": ["${aliasPath}/*"]`
|
|
1799
|
+
];
|
|
1800
|
+
}).join(",\n");
|
|
1801
|
+
await writeFileIfDifferent(
|
|
1802
|
+
resolve7(dir, "tsconfig.json"),
|
|
1803
|
+
`{
|
|
1804
|
+
"compilerOptions": {
|
|
1805
|
+
"target": "ESNext",
|
|
1806
|
+
"module": "ESNext",
|
|
1807
|
+
"moduleResolution": "Bundler",
|
|
1808
|
+
"noEmit": true,
|
|
1809
|
+
"esModuleInterop": true,
|
|
1810
|
+
"forceConsistentCasingInFileNames": true,
|
|
1811
|
+
"resolveJsonModule": true,
|
|
1812
|
+
"strict": true,
|
|
1813
|
+
"skipLibCheck": true,
|
|
1814
|
+
"paths": {
|
|
1815
|
+
${paths}
|
|
1816
|
+
}
|
|
1817
|
+
},
|
|
1818
|
+
"include": [
|
|
1819
|
+
"${getTsconfigPath(wxt.config.root)}/**/*",
|
|
1820
|
+
"./${getTsconfigPath(mainReference)}"
|
|
1821
|
+
],
|
|
1822
|
+
"exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
|
|
1823
|
+
}`
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
// src/core/utils/building/resolve-config.ts
|
|
1828
|
+
import { loadConfig } from "c12";
|
|
1829
|
+
import path5 from "node:path";
|
|
1830
|
+
|
|
1831
|
+
// src/core/utils/cache.ts
|
|
1832
|
+
import fs7, { ensureDir as ensureDir3 } from "fs-extra";
|
|
1833
|
+
import { dirname as dirname4, resolve as resolve8 } from "path";
|
|
1834
|
+
function createFsCache(wxtDir) {
|
|
1835
|
+
const getPath = (key) => resolve8(wxtDir, "cache", encodeURIComponent(key));
|
|
1787
1836
|
return {
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
if (Array.isArray(group))
|
|
1793
|
-
entryConfig = getMultiPageConfig(group);
|
|
1794
|
-
else if (group.inputPath.endsWith(".css"))
|
|
1795
|
-
entryConfig = getCssConfig(group);
|
|
1796
|
-
else
|
|
1797
|
-
entryConfig = getLibModeConfig(group);
|
|
1798
|
-
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
|
|
1799
|
-
const result = await vite.build(buildConfig);
|
|
1800
|
-
return {
|
|
1801
|
-
entrypoints: group,
|
|
1802
|
-
chunks: getBuildOutputChunks(result)
|
|
1803
|
-
};
|
|
1837
|
+
async set(key, value) {
|
|
1838
|
+
const path10 = getPath(key);
|
|
1839
|
+
await ensureDir3(dirname4(path10));
|
|
1840
|
+
await writeFileIfDifferent(path10, value);
|
|
1804
1841
|
},
|
|
1805
|
-
async
|
|
1806
|
-
const
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
}
|
|
1813
|
-
};
|
|
1814
|
-
const baseConfig = await getBaseConfig();
|
|
1815
|
-
const viteServer = await vite.createServer(
|
|
1816
|
-
vite.mergeConfig(baseConfig, serverConfig)
|
|
1817
|
-
);
|
|
1818
|
-
const server = {
|
|
1819
|
-
async listen() {
|
|
1820
|
-
await viteServer.listen(info.port);
|
|
1821
|
-
},
|
|
1822
|
-
async close() {
|
|
1823
|
-
await viteServer.close();
|
|
1824
|
-
},
|
|
1825
|
-
transformHtml(...args) {
|
|
1826
|
-
return viteServer.transformIndexHtml(...args);
|
|
1827
|
-
},
|
|
1828
|
-
ws: {
|
|
1829
|
-
send(message, payload) {
|
|
1830
|
-
return viteServer.ws.send(message, payload);
|
|
1831
|
-
},
|
|
1832
|
-
on(message, cb) {
|
|
1833
|
-
viteServer.ws.on(message, cb);
|
|
1834
|
-
}
|
|
1835
|
-
},
|
|
1836
|
-
watcher: viteServer.watcher
|
|
1837
|
-
};
|
|
1838
|
-
return server;
|
|
1842
|
+
async get(key) {
|
|
1843
|
+
const path10 = getPath(key);
|
|
1844
|
+
try {
|
|
1845
|
+
return await fs7.readFile(path10, "utf-8");
|
|
1846
|
+
} catch {
|
|
1847
|
+
return void 0;
|
|
1848
|
+
}
|
|
1839
1849
|
}
|
|
1840
1850
|
};
|
|
1841
1851
|
}
|
|
1842
|
-
function getBuildOutputChunks(result) {
|
|
1843
|
-
if ("on" in result)
|
|
1844
|
-
throw Error("wxt does not support vite watch mode.");
|
|
1845
|
-
if (Array.isArray(result))
|
|
1846
|
-
return result.flatMap(({ output }) => output);
|
|
1847
|
-
return result.output;
|
|
1848
|
-
}
|
|
1849
|
-
function getRollupEntry(entrypoint) {
|
|
1850
|
-
let virtualEntrypointType;
|
|
1851
|
-
switch (entrypoint.type) {
|
|
1852
|
-
case "background":
|
|
1853
|
-
case "unlisted-script":
|
|
1854
|
-
virtualEntrypointType = entrypoint.type;
|
|
1855
|
-
break;
|
|
1856
|
-
case "content-script":
|
|
1857
|
-
virtualEntrypointType = entrypoint.options.world === "MAIN" ? "content-script-main-world" : "content-script-isolated-world";
|
|
1858
|
-
break;
|
|
1859
|
-
}
|
|
1860
|
-
return virtualEntrypointType ? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}` : entrypoint.inputPath;
|
|
1861
|
-
}
|
|
1862
1852
|
|
|
1863
1853
|
// src/core/utils/building/resolve-config.ts
|
|
1854
|
+
import consola, { LogLevels } from "consola";
|
|
1864
1855
|
import defu from "defu";
|
|
1865
1856
|
|
|
1866
1857
|
// src/core/utils/package.ts
|
|
@@ -1883,7 +1874,7 @@ function isModuleInstalled(name) {
|
|
|
1883
1874
|
|
|
1884
1875
|
// src/core/utils/building/resolve-config.ts
|
|
1885
1876
|
import fs9 from "fs-extra";
|
|
1886
|
-
async function resolveConfig(inlineConfig, command
|
|
1877
|
+
async function resolveConfig(inlineConfig, command) {
|
|
1887
1878
|
let userConfig = {};
|
|
1888
1879
|
let userConfigMetadata;
|
|
1889
1880
|
if (inlineConfig.configFile !== false) {
|
|
@@ -1899,14 +1890,14 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1899
1890
|
userConfig = loadedConfig ?? {};
|
|
1900
1891
|
userConfigMetadata = metadata;
|
|
1901
1892
|
}
|
|
1902
|
-
const mergedConfig = mergeInlineConfig(inlineConfig, userConfig);
|
|
1893
|
+
const mergedConfig = await mergeInlineConfig(inlineConfig, userConfig);
|
|
1903
1894
|
const debug = mergedConfig.debug ?? false;
|
|
1904
1895
|
const logger = mergedConfig.logger ?? consola;
|
|
1905
1896
|
if (debug)
|
|
1906
1897
|
logger.level = LogLevels.debug;
|
|
1907
1898
|
const browser = mergedConfig.browser ?? "chrome";
|
|
1908
1899
|
const manifestVersion = mergedConfig.manifestVersion ?? (browser === "firefox" || browser === "safari" ? 2 : 3);
|
|
1909
|
-
const mode = mergedConfig.mode ??
|
|
1900
|
+
const mode = mergedConfig.mode ?? COMMAND_MODES[command];
|
|
1910
1901
|
const env = { browser, command, manifestVersion, mode };
|
|
1911
1902
|
const root = path5.resolve(
|
|
1912
1903
|
inlineConfig.root ?? userConfig.root ?? process.cwd()
|
|
@@ -1947,13 +1938,19 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1947
1938
|
"~~": root
|
|
1948
1939
|
}).map(([key, value]) => [key, path5.resolve(root, value)])
|
|
1949
1940
|
);
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
mergedConfig.
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1941
|
+
let devServerConfig;
|
|
1942
|
+
if (command === "serve") {
|
|
1943
|
+
let port = mergedConfig.dev?.server?.port;
|
|
1944
|
+
if (port == null || !isFinite(port)) {
|
|
1945
|
+
const { default: getPort, portNumbers } = await import("get-port");
|
|
1946
|
+
port = await getPort({ port: portNumbers(3e3, 3010) });
|
|
1947
|
+
}
|
|
1948
|
+
devServerConfig = {
|
|
1949
|
+
port,
|
|
1950
|
+
hostname: "localhost"
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
return {
|
|
1957
1954
|
browser,
|
|
1958
1955
|
command,
|
|
1959
1956
|
debug,
|
|
@@ -1975,109 +1972,47 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1975
1972
|
srcDir,
|
|
1976
1973
|
typesDir,
|
|
1977
1974
|
wxtDir,
|
|
1978
|
-
zip:
|
|
1979
|
-
transformManifest
|
|
1980
|
-
|
|
1981
|
-
inlineConfig.transformManifest?.(manifest);
|
|
1982
|
-
},
|
|
1983
|
-
analysis: {
|
|
1984
|
-
enabled: mergedConfig.analysis?.enabled ?? false,
|
|
1985
|
-
open: mergedConfig.analysis?.open ?? false,
|
|
1986
|
-
template: mergedConfig.analysis?.template ?? "treemap",
|
|
1987
|
-
outputFile: analysisOutputFile,
|
|
1988
|
-
outputDir: analysisOutputDir,
|
|
1989
|
-
outputName: analysisOutputName,
|
|
1990
|
-
keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false
|
|
1991
|
-
},
|
|
1975
|
+
zip: resolveZipConfig(root, mergedConfig),
|
|
1976
|
+
transformManifest: mergedConfig.transformManifest,
|
|
1977
|
+
analysis: resolveAnalysisConfig(root, mergedConfig),
|
|
1992
1978
|
userConfigMetadata: userConfigMetadata ?? {},
|
|
1993
1979
|
alias,
|
|
1994
|
-
experimental: {
|
|
1995
|
-
includeBrowserPolyfill:
|
|
1996
|
-
},
|
|
1997
|
-
server,
|
|
1980
|
+
experimental: defu(mergedConfig.experimental, {
|
|
1981
|
+
includeBrowserPolyfill: true
|
|
1982
|
+
}),
|
|
1998
1983
|
dev: {
|
|
1984
|
+
server: devServerConfig,
|
|
1999
1985
|
reloadCommand
|
|
2000
1986
|
},
|
|
2001
|
-
hooks: mergedConfig.hooks ?? {}
|
|
2002
|
-
|
|
2003
|
-
const builder = await createViteBuilder(
|
|
2004
|
-
inlineConfig,
|
|
2005
|
-
userConfig,
|
|
2006
|
-
finalConfig
|
|
2007
|
-
);
|
|
2008
|
-
return {
|
|
2009
|
-
...finalConfig,
|
|
2010
|
-
builder
|
|
1987
|
+
hooks: mergedConfig.hooks ?? {},
|
|
1988
|
+
vite: mergedConfig.vite ?? (() => ({}))
|
|
2011
1989
|
};
|
|
2012
1990
|
}
|
|
2013
1991
|
async function resolveManifestConfig(env, manifest) {
|
|
2014
1992
|
return await (typeof manifest === "function" ? manifest(env) : manifest ?? {});
|
|
2015
1993
|
}
|
|
2016
|
-
function mergeInlineConfig(inlineConfig, userConfig) {
|
|
2017
|
-
|
|
2018
|
-
if (inlineConfig.imports === false || userConfig.imports === false) {
|
|
2019
|
-
imports = false;
|
|
2020
|
-
} else if (userConfig.imports == null && inlineConfig.imports == null) {
|
|
2021
|
-
imports = void 0;
|
|
2022
|
-
} else {
|
|
2023
|
-
imports = defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
|
2024
|
-
}
|
|
1994
|
+
async function mergeInlineConfig(inlineConfig, userConfig) {
|
|
1995
|
+
const imports = inlineConfig.imports === false || userConfig.imports === false ? false : userConfig.imports == null && inlineConfig.imports == null ? void 0 : defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
|
2025
1996
|
const manifest = async (env) => {
|
|
2026
1997
|
const user = await resolveManifestConfig(env, userConfig.manifest);
|
|
2027
1998
|
const inline = await resolveManifestConfig(env, inlineConfig.manifest);
|
|
2028
1999
|
return defu(inline, user);
|
|
2029
2000
|
};
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
const
|
|
2035
|
-
inlineConfig.zip ?? {},
|
|
2036
|
-
userConfig.zip ?? {}
|
|
2037
|
-
);
|
|
2038
|
-
const hooks = defu(
|
|
2039
|
-
inlineConfig.hooks ?? {},
|
|
2040
|
-
userConfig.hooks ?? {}
|
|
2041
|
-
);
|
|
2001
|
+
const transformManifest = (manifest2) => {
|
|
2002
|
+
userConfig.transformManifest?.(manifest2);
|
|
2003
|
+
inlineConfig.transformManifest?.(manifest2);
|
|
2004
|
+
};
|
|
2005
|
+
const builderConfig = await mergeBuilderConfig(inlineConfig, userConfig);
|
|
2042
2006
|
return {
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
configFile: inlineConfig.configFile,
|
|
2047
|
-
debug: inlineConfig.debug ?? userConfig.debug,
|
|
2048
|
-
entrypointsDir: inlineConfig.entrypointsDir ?? userConfig.entrypointsDir,
|
|
2049
|
-
filterEntrypoints: inlineConfig.filterEntrypoints ?? userConfig.filterEntrypoints,
|
|
2007
|
+
...defu(inlineConfig, userConfig),
|
|
2008
|
+
// Custom merge values
|
|
2009
|
+
transformManifest,
|
|
2050
2010
|
imports,
|
|
2051
|
-
logger: inlineConfig.logger ?? userConfig.logger,
|
|
2052
2011
|
manifest,
|
|
2053
|
-
|
|
2054
|
-
publicDir: inlineConfig.publicDir ?? userConfig.publicDir,
|
|
2055
|
-
runner,
|
|
2056
|
-
srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
|
|
2057
|
-
outDir: inlineConfig.outDir ?? userConfig.outDir,
|
|
2058
|
-
zip: zip2,
|
|
2059
|
-
analysis: {
|
|
2060
|
-
...userConfig.analysis,
|
|
2061
|
-
...inlineConfig.analysis
|
|
2062
|
-
},
|
|
2063
|
-
alias: {
|
|
2064
|
-
...userConfig.alias,
|
|
2065
|
-
...inlineConfig.alias
|
|
2066
|
-
},
|
|
2067
|
-
experimental: {
|
|
2068
|
-
...userConfig.experimental,
|
|
2069
|
-
...inlineConfig.experimental
|
|
2070
|
-
},
|
|
2071
|
-
vite: void 0,
|
|
2072
|
-
transformManifest: void 0,
|
|
2073
|
-
dev: {
|
|
2074
|
-
...userConfig.dev,
|
|
2075
|
-
...inlineConfig.dev
|
|
2076
|
-
},
|
|
2077
|
-
hooks
|
|
2012
|
+
...builderConfig
|
|
2078
2013
|
};
|
|
2079
2014
|
}
|
|
2080
|
-
function
|
|
2015
|
+
function resolveZipConfig(root, mergedConfig) {
|
|
2081
2016
|
const downloadedPackagesDir = path5.resolve(root, ".wxt/local_modules");
|
|
2082
2017
|
return {
|
|
2083
2018
|
name: void 0,
|
|
@@ -2102,6 +2037,23 @@ function resolveInternalZipConfig(root, mergedConfig) {
|
|
|
2102
2037
|
downloadedPackagesDir
|
|
2103
2038
|
};
|
|
2104
2039
|
}
|
|
2040
|
+
function resolveAnalysisConfig(root, mergedConfig) {
|
|
2041
|
+
const analysisOutputFile = path5.resolve(
|
|
2042
|
+
root,
|
|
2043
|
+
mergedConfig.analysis?.outputFile ?? "stats.html"
|
|
2044
|
+
);
|
|
2045
|
+
const analysisOutputDir = path5.dirname(analysisOutputFile);
|
|
2046
|
+
const analysisOutputName = path5.parse(analysisOutputFile).name;
|
|
2047
|
+
return {
|
|
2048
|
+
enabled: mergedConfig.analysis?.enabled ?? false,
|
|
2049
|
+
open: mergedConfig.analysis?.open ?? false,
|
|
2050
|
+
template: mergedConfig.analysis?.template ?? "treemap",
|
|
2051
|
+
outputFile: analysisOutputFile,
|
|
2052
|
+
outputDir: analysisOutputDir,
|
|
2053
|
+
outputName: analysisOutputName,
|
|
2054
|
+
keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false
|
|
2055
|
+
};
|
|
2056
|
+
}
|
|
2105
2057
|
async function getUnimportOptions(wxtDir, logger, config) {
|
|
2106
2058
|
if (config.imports === false)
|
|
2107
2059
|
return false;
|
|
@@ -2154,6 +2106,23 @@ function logMissingDir(logger, name, expected) {
|
|
|
2154
2106
|
)}`
|
|
2155
2107
|
);
|
|
2156
2108
|
}
|
|
2109
|
+
var COMMAND_MODES = {
|
|
2110
|
+
build: "production",
|
|
2111
|
+
serve: "development"
|
|
2112
|
+
};
|
|
2113
|
+
async function mergeBuilderConfig(inlineConfig, userConfig) {
|
|
2114
|
+
const vite = await import("vite").catch(() => void 0);
|
|
2115
|
+
if (vite) {
|
|
2116
|
+
return {
|
|
2117
|
+
vite: async (env) => {
|
|
2118
|
+
const resolvedInlineConfig = await inlineConfig.vite?.(env) ?? {};
|
|
2119
|
+
const resolvedUserConfig = await userConfig.vite?.(env) ?? {};
|
|
2120
|
+
return vite.mergeConfig(resolvedUserConfig, resolvedInlineConfig);
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
throw Error("Builder not found. Make sure vite is installed.");
|
|
2125
|
+
}
|
|
2157
2126
|
|
|
2158
2127
|
// src/core/utils/building/group-entrypoints.ts
|
|
2159
2128
|
function groupEntrypoints(entrypoints) {
|
|
@@ -2417,7 +2386,7 @@ function getChunkSortWeight(filename) {
|
|
|
2417
2386
|
import pc4 from "picocolors";
|
|
2418
2387
|
|
|
2419
2388
|
// package.json
|
|
2420
|
-
var version = "0.17.
|
|
2389
|
+
var version = "0.17.10";
|
|
2421
2390
|
|
|
2422
2391
|
// src/core/utils/log/printHeader.ts
|
|
2423
2392
|
import { consola as consola2 } from "consola";
|
|
@@ -2595,7 +2564,7 @@ async function generateManifest(entrypoints, buildOutput) {
|
|
|
2595
2564
|
addDevModeCsp(manifest);
|
|
2596
2565
|
if (wxt.config.command === "serve")
|
|
2597
2566
|
addDevModePermissions(manifest);
|
|
2598
|
-
wxt.config.transformManifest(manifest);
|
|
2567
|
+
wxt.config.transformManifest?.(manifest);
|
|
2599
2568
|
await wxt.hooks.callHook("build:manifestGenerated", wxt, manifest);
|
|
2600
2569
|
if (wxt.config.manifestVersion === 2) {
|
|
2601
2570
|
convertWebAccessibleResourcesToMv2(manifest);
|
|
@@ -2876,8 +2845,8 @@ function discoverIcons(buildOutput) {
|
|
|
2876
2845
|
return icons.length > 0 ? Object.fromEntries(icons) : void 0;
|
|
2877
2846
|
}
|
|
2878
2847
|
function addDevModeCsp(manifest) {
|
|
2879
|
-
const permission = `http://${wxt.
|
|
2880
|
-
const allowedCsp = wxt.
|
|
2848
|
+
const permission = `http://${wxt.server?.hostname ?? ""}/*`;
|
|
2849
|
+
const allowedCsp = wxt.server?.origin ?? "http://localhost:*";
|
|
2881
2850
|
if (manifest.manifest_version === 3) {
|
|
2882
2851
|
addHostPermission(manifest, permission);
|
|
2883
2852
|
} else {
|
|
@@ -2890,7 +2859,7 @@ function addDevModeCsp(manifest) {
|
|
|
2890
2859
|
) : manifest.content_security_policy ?? "script-src 'self'; object-src 'self';"
|
|
2891
2860
|
// default CSP for MV2
|
|
2892
2861
|
);
|
|
2893
|
-
if (wxt.
|
|
2862
|
+
if (wxt.server)
|
|
2894
2863
|
csp.add("script-src", allowedCsp);
|
|
2895
2864
|
if (manifest.manifest_version === 3) {
|
|
2896
2865
|
manifest.content_security_policy ??= {};
|
|
@@ -3150,7 +3119,7 @@ async function internalBuild() {
|
|
|
3150
3119
|
const target = `${wxt.config.browser}-mv${wxt.config.manifestVersion}`;
|
|
3151
3120
|
wxt.logger.info(
|
|
3152
3121
|
`${verb} ${pc5.cyan(target)} for ${pc5.cyan(wxt.config.mode)} with ${pc5.green(
|
|
3153
|
-
`${wxt.
|
|
3122
|
+
`${wxt.builder.name} ${wxt.builder.version}`
|
|
3154
3123
|
)}`
|
|
3155
3124
|
);
|
|
3156
3125
|
const startTime = Date.now();
|
|
@@ -3431,14 +3400,59 @@ import { Mutex } from "async-mutex";
|
|
|
3431
3400
|
import pc7 from "picocolors";
|
|
3432
3401
|
import { relative as relative10 } from "node:path";
|
|
3433
3402
|
async function createServer(inlineConfig) {
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3403
|
+
await registerWxt("serve", inlineConfig, async (config) => {
|
|
3404
|
+
const { port, hostname } = config.dev.server;
|
|
3405
|
+
const serverInfo = {
|
|
3406
|
+
port,
|
|
3407
|
+
hostname,
|
|
3408
|
+
origin: `http://${hostname}:${port}`
|
|
3409
|
+
};
|
|
3410
|
+
const server2 = {
|
|
3411
|
+
...serverInfo,
|
|
3412
|
+
get watcher() {
|
|
3413
|
+
return builderServer.watcher;
|
|
3414
|
+
},
|
|
3415
|
+
get ws() {
|
|
3416
|
+
return builderServer.ws;
|
|
3417
|
+
},
|
|
3418
|
+
currentOutput: void 0,
|
|
3419
|
+
async start() {
|
|
3420
|
+
await builderServer.listen();
|
|
3421
|
+
wxt.logger.success(`Started dev server @ ${serverInfo.origin}`);
|
|
3422
|
+
await buildAndOpenBrowser();
|
|
3423
|
+
},
|
|
3424
|
+
async stop() {
|
|
3425
|
+
await runner.closeBrowser();
|
|
3426
|
+
await builderServer.close();
|
|
3427
|
+
},
|
|
3428
|
+
async restart() {
|
|
3429
|
+
await closeAndRecreateRunner();
|
|
3430
|
+
await buildAndOpenBrowser();
|
|
3431
|
+
},
|
|
3432
|
+
transformHtml(url, html, originalUrl) {
|
|
3433
|
+
return builderServer.transformHtml(url, html, originalUrl);
|
|
3434
|
+
},
|
|
3435
|
+
reloadContentScript(payload) {
|
|
3436
|
+
server2.ws.send("wxt:reload-content-script", payload);
|
|
3437
|
+
},
|
|
3438
|
+
reloadPage(path10) {
|
|
3439
|
+
server2.ws.send("wxt:reload-page", path10);
|
|
3440
|
+
},
|
|
3441
|
+
reloadExtension() {
|
|
3442
|
+
server2.ws.send("wxt:reload-extension");
|
|
3443
|
+
},
|
|
3444
|
+
async restartBrowser() {
|
|
3445
|
+
await closeAndRecreateRunner();
|
|
3446
|
+
await runner.openBrowser();
|
|
3447
|
+
}
|
|
3448
|
+
};
|
|
3449
|
+
return server2;
|
|
3450
|
+
});
|
|
3451
|
+
const server = wxt.server;
|
|
3452
|
+
let [runner, builderServer] = await Promise.all([
|
|
3453
|
+
createExtensionRunner(),
|
|
3454
|
+
wxt.builder.createServer(server)
|
|
3455
|
+
]);
|
|
3442
3456
|
const buildAndOpenBrowser = async () => {
|
|
3443
3457
|
server.currentOutput = await internalBuild();
|
|
3444
3458
|
try {
|
|
@@ -3453,50 +3467,6 @@ async function createServer(inlineConfig) {
|
|
|
3453
3467
|
await wxt.reloadConfig();
|
|
3454
3468
|
runner = await createExtensionRunner();
|
|
3455
3469
|
};
|
|
3456
|
-
const server = {
|
|
3457
|
-
...serverInfo,
|
|
3458
|
-
get watcher() {
|
|
3459
|
-
return builderServer.watcher;
|
|
3460
|
-
},
|
|
3461
|
-
get ws() {
|
|
3462
|
-
return builderServer.ws;
|
|
3463
|
-
},
|
|
3464
|
-
currentOutput: void 0,
|
|
3465
|
-
async start() {
|
|
3466
|
-
await builderServer.listen();
|
|
3467
|
-
wxt.logger.success(`Started dev server @ ${serverInfo.origin}`);
|
|
3468
|
-
await buildAndOpenBrowser();
|
|
3469
|
-
},
|
|
3470
|
-
async stop() {
|
|
3471
|
-
await runner.closeBrowser();
|
|
3472
|
-
await builderServer.close();
|
|
3473
|
-
},
|
|
3474
|
-
async restart() {
|
|
3475
|
-
await closeAndRecreateRunner();
|
|
3476
|
-
await buildAndOpenBrowser();
|
|
3477
|
-
},
|
|
3478
|
-
transformHtml(url, html, originalUrl) {
|
|
3479
|
-
return builderServer.transformHtml(url, html, originalUrl);
|
|
3480
|
-
},
|
|
3481
|
-
reloadContentScript(payload) {
|
|
3482
|
-
server.ws.send("wxt:reload-content-script", payload);
|
|
3483
|
-
},
|
|
3484
|
-
reloadPage(path10) {
|
|
3485
|
-
server.ws.send("wxt:reload-page", path10);
|
|
3486
|
-
},
|
|
3487
|
-
reloadExtension() {
|
|
3488
|
-
server.ws.send("wxt:reload-extension");
|
|
3489
|
-
},
|
|
3490
|
-
async restartBrowser() {
|
|
3491
|
-
await closeAndRecreateRunner();
|
|
3492
|
-
await runner.openBrowser();
|
|
3493
|
-
}
|
|
3494
|
-
};
|
|
3495
|
-
await registerWxt("serve", inlineConfig, server);
|
|
3496
|
-
let [runner, builderServer] = await Promise.all([
|
|
3497
|
-
createExtensionRunner(),
|
|
3498
|
-
wxt.config.builder.createServer(server)
|
|
3499
|
-
]);
|
|
3500
3470
|
server.ws.on("wxt:background-initialized", () => {
|
|
3501
3471
|
if (server.currentOutput == null)
|
|
3502
3472
|
return;
|
|
@@ -3506,10 +3476,6 @@ async function createServer(inlineConfig) {
|
|
|
3506
3476
|
server.watcher.on("all", reloadOnChange);
|
|
3507
3477
|
return server;
|
|
3508
3478
|
}
|
|
3509
|
-
async function getPort() {
|
|
3510
|
-
const { default: getPort2, portNumbers } = await import("get-port");
|
|
3511
|
-
return await getPort2({ port: portNumbers(3e3, 3010) });
|
|
3512
|
-
}
|
|
3513
3479
|
function createFileReloader(server) {
|
|
3514
3480
|
const fileChangedMutex = new Mutex();
|
|
3515
3481
|
const changeQueue = [];
|
|
@@ -3784,7 +3750,7 @@ async function zip(config) {
|
|
|
3784
3750
|
const applyTemplate = (template) => template.replaceAll("{{name}}", projectName).replaceAll("{{browser}}", wxt.config.browser).replaceAll(
|
|
3785
3751
|
"{{version}}",
|
|
3786
3752
|
output.manifest.version_name ?? output.manifest.version
|
|
3787
|
-
).replaceAll("{{manifestVersion}}", `mv${wxt.config.manifestVersion}`);
|
|
3753
|
+
).replaceAll("{{mode}}", wxt.config.mode).replaceAll("{{manifestVersion}}", `mv${wxt.config.manifestVersion}`);
|
|
3788
3754
|
await fs16.ensureDir(wxt.config.outBaseDir);
|
|
3789
3755
|
const outZipFilename = applyTemplate(wxt.config.zip.artifactTemplate);
|
|
3790
3756
|
const outZipPath = path9.resolve(wxt.config.outBaseDir, outZipFilename);
|
|
@@ -3952,7 +3918,7 @@ function isAliasedCommand(command) {
|
|
|
3952
3918
|
// src/cli/commands.ts
|
|
3953
3919
|
var cli = cac("wxt");
|
|
3954
3920
|
cli.option("--debug", "enable debug mode");
|
|
3955
|
-
cli.command("[root]", "start dev server").option("-c, --config <file>", "use specified config file").option("-m, --mode <mode>", "set env mode").option("-b, --browser <browser>", "specify a browser").option(
|
|
3921
|
+
cli.command("[root]", "start dev server").option("-c, --config <file>", "use specified config file").option("-m, --mode <mode>", "set env mode").option("-b, --browser <browser>", "specify a browser").option("-p, --port <port>", "specify a port for the dev server").option(
|
|
3956
3922
|
"-e, --filter-entrypoint <entrypoint>",
|
|
3957
3923
|
"only build specific entrypoints",
|
|
3958
3924
|
{
|
|
@@ -3967,7 +3933,12 @@ cli.command("[root]", "start dev server").option("-c, --config <file>", "use spe
|
|
|
3967
3933
|
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : void 0,
|
|
3968
3934
|
configFile: flags.config,
|
|
3969
3935
|
debug: flags.debug,
|
|
3970
|
-
filterEntrypoints: getArrayFromFlags(flags, "filterEntrypoint")
|
|
3936
|
+
filterEntrypoints: getArrayFromFlags(flags, "filterEntrypoint"),
|
|
3937
|
+
dev: flags.port == null ? void 0 : {
|
|
3938
|
+
server: {
|
|
3939
|
+
port: parseInt(flags.port)
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3971
3942
|
});
|
|
3972
3943
|
await server.start();
|
|
3973
3944
|
return { isOngoing: true };
|