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
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-VBXJIVYU.js";
|
|
4
4
|
|
|
5
5
|
// package.json
|
|
6
|
-
var version = "0.17.
|
|
6
|
+
var version = "0.17.10";
|
|
7
7
|
|
|
8
8
|
// src/core/utils/paths.ts
|
|
9
9
|
import systemPath from "node:path";
|
|
@@ -17,187 +17,15 @@ function unnormalizePath(path8) {
|
|
|
17
17
|
var CSS_EXTENSIONS = ["css", "scss", "sass", "less", "styl", "stylus"];
|
|
18
18
|
var CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
|
|
19
19
|
|
|
20
|
-
// src/core/utils/fs.ts
|
|
21
|
-
import fs from "fs-extra";
|
|
22
|
-
import glob from "fast-glob";
|
|
23
|
-
async function writeFileIfDifferent(file, newContents) {
|
|
24
|
-
const existingContents = await fs.readFile(file, "utf-8").catch(() => void 0);
|
|
25
|
-
if (existingContents !== newContents) {
|
|
26
|
-
await fs.writeFile(file, newContents);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async function getPublicFiles() {
|
|
30
|
-
if (!await fs.exists(wxt.config.publicDir))
|
|
31
|
-
return [];
|
|
32
|
-
const files = await glob("**/*", { cwd: wxt.config.publicDir });
|
|
33
|
-
return files.map(unnormalizePath);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/core/utils/building/build-entrypoints.ts
|
|
37
|
-
import fs2 from "fs-extra";
|
|
38
|
-
import { dirname, resolve } from "path";
|
|
39
|
-
import pc from "picocolors";
|
|
40
|
-
async function buildEntrypoints(groups, spinner) {
|
|
41
|
-
const steps = [];
|
|
42
|
-
for (let i = 0; i < groups.length; i++) {
|
|
43
|
-
const group = groups[i];
|
|
44
|
-
const groupNames = [group].flat().map((e) => e.name);
|
|
45
|
-
const groupNameColored = groupNames.join(pc.dim(", "));
|
|
46
|
-
spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
|
47
|
-
try {
|
|
48
|
-
steps.push(await wxt.config.builder.build(group));
|
|
49
|
-
} catch (err) {
|
|
50
|
-
spinner.stop().clear();
|
|
51
|
-
wxt.logger.error(err);
|
|
52
|
-
throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const publicAssets = await copyPublicDirectory();
|
|
56
|
-
return { publicAssets, steps };
|
|
57
|
-
}
|
|
58
|
-
async function copyPublicDirectory() {
|
|
59
|
-
const files = await getPublicFiles();
|
|
60
|
-
if (files.length === 0)
|
|
61
|
-
return [];
|
|
62
|
-
const publicAssets = [];
|
|
63
|
-
for (const file of files) {
|
|
64
|
-
const srcPath = resolve(wxt.config.publicDir, file);
|
|
65
|
-
const outPath = resolve(wxt.config.outDir, file);
|
|
66
|
-
await fs2.ensureDir(dirname(outPath));
|
|
67
|
-
await fs2.copyFile(srcPath, outPath);
|
|
68
|
-
publicAssets.push({
|
|
69
|
-
type: "asset",
|
|
70
|
-
fileName: file
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return publicAssets;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/core/utils/arrays.ts
|
|
77
|
-
function every(array, predicate) {
|
|
78
|
-
for (let i = 0; i < array.length; i++)
|
|
79
|
-
if (!predicate(array[i], i))
|
|
80
|
-
return false;
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
function some(array, predicate) {
|
|
84
|
-
for (let i = 0; i < array.length; i++)
|
|
85
|
-
if (predicate(array[i], i))
|
|
86
|
-
return true;
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// src/core/utils/building/detect-dev-changes.ts
|
|
91
|
-
function detectDevChanges(changedFiles, currentOutput) {
|
|
92
|
-
const isConfigChange = some(
|
|
93
|
-
changedFiles,
|
|
94
|
-
(file) => file === wxt.config.userConfigMetadata.configFile
|
|
95
|
-
);
|
|
96
|
-
if (isConfigChange)
|
|
97
|
-
return { type: "full-restart" };
|
|
98
|
-
const isRunnerChange = some(
|
|
99
|
-
changedFiles,
|
|
100
|
-
(file) => file === wxt.config.runnerConfig.configFile
|
|
101
|
-
);
|
|
102
|
-
if (isRunnerChange)
|
|
103
|
-
return { type: "browser-restart" };
|
|
104
|
-
const changedSteps = new Set(
|
|
105
|
-
changedFiles.flatMap(
|
|
106
|
-
(changedFile) => findEffectedSteps(changedFile, currentOutput)
|
|
107
|
-
)
|
|
108
|
-
);
|
|
109
|
-
if (changedSteps.size === 0)
|
|
110
|
-
return { type: "no-change" };
|
|
111
|
-
const unchangedOutput = {
|
|
112
|
-
manifest: currentOutput.manifest,
|
|
113
|
-
steps: [],
|
|
114
|
-
publicAssets: []
|
|
115
|
-
};
|
|
116
|
-
const changedOutput = {
|
|
117
|
-
manifest: currentOutput.manifest,
|
|
118
|
-
steps: [],
|
|
119
|
-
publicAssets: []
|
|
120
|
-
};
|
|
121
|
-
for (const step of currentOutput.steps) {
|
|
122
|
-
if (changedSteps.has(step)) {
|
|
123
|
-
changedOutput.steps.push(step);
|
|
124
|
-
} else {
|
|
125
|
-
unchangedOutput.steps.push(step);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
for (const asset of currentOutput.publicAssets) {
|
|
129
|
-
if (changedSteps.has(asset)) {
|
|
130
|
-
changedOutput.publicAssets.push(asset);
|
|
131
|
-
} else {
|
|
132
|
-
unchangedOutput.publicAssets.push(asset);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
|
|
136
|
-
if (isOnlyHtmlChanges) {
|
|
137
|
-
return {
|
|
138
|
-
type: "html-reload",
|
|
139
|
-
cachedOutput: unchangedOutput,
|
|
140
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
|
|
144
|
-
changedOutput.steps.flatMap((step) => step.entrypoints),
|
|
145
|
-
(entry) => entry.type === "content-script"
|
|
146
|
-
);
|
|
147
|
-
if (isOnlyContentScripts) {
|
|
148
|
-
return {
|
|
149
|
-
type: "content-script-reload",
|
|
150
|
-
cachedOutput: unchangedOutput,
|
|
151
|
-
changedSteps: changedOutput.steps,
|
|
152
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
type: "extension-reload",
|
|
157
|
-
cachedOutput: unchangedOutput,
|
|
158
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
function findEffectedSteps(changedFile, currentOutput) {
|
|
162
|
-
const changes = [];
|
|
163
|
-
const changedPath = normalizePath(changedFile);
|
|
164
|
-
const isChunkEffected = (chunk) => (
|
|
165
|
-
// If it's an HTML file with the same path, is is effected because HTML files need to be re-rendered
|
|
166
|
-
// - fileName is normalized, relative bundle path, "<entrypoint-name>.html"
|
|
167
|
-
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
|
|
168
|
-
// - moduleIds are absolute, normalized paths
|
|
169
|
-
chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
|
|
170
|
-
);
|
|
171
|
-
for (const step of currentOutput.steps) {
|
|
172
|
-
const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
|
|
173
|
-
if (effectedChunk)
|
|
174
|
-
changes.push(step);
|
|
175
|
-
}
|
|
176
|
-
const effectedAsset = currentOutput.publicAssets.find(
|
|
177
|
-
(chunk) => isChunkEffected(chunk)
|
|
178
|
-
);
|
|
179
|
-
if (effectedAsset)
|
|
180
|
-
changes.push(effectedAsset);
|
|
181
|
-
return changes;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// src/core/utils/building/find-entrypoints.ts
|
|
185
|
-
import { relative as relative2, resolve as resolve3 } from "path";
|
|
186
|
-
import fs3 from "fs-extra";
|
|
187
|
-
import { minimatch } from "minimatch";
|
|
188
|
-
import { parseHTML } from "linkedom";
|
|
189
|
-
import JSON5 from "json5";
|
|
190
|
-
import glob2 from "fast-glob";
|
|
191
|
-
|
|
192
20
|
// src/core/utils/entrypoints.ts
|
|
193
|
-
import path, { relative, resolve
|
|
21
|
+
import path, { relative, resolve } from "node:path";
|
|
194
22
|
function getEntrypointName(entrypointsDir, inputPath) {
|
|
195
23
|
const relativePath = path.relative(entrypointsDir, inputPath);
|
|
196
24
|
const name = relativePath.split(/[\.\/\\]/, 2)[0];
|
|
197
25
|
return name;
|
|
198
26
|
}
|
|
199
27
|
function getEntrypointOutputFile(entrypoint, ext) {
|
|
200
|
-
return
|
|
28
|
+
return resolve(entrypoint.outputDir, `${entrypoint.name}${ext}`);
|
|
201
29
|
}
|
|
202
30
|
function getEntrypointBundlePath(entrypoint, outDir, ext) {
|
|
203
31
|
return normalizePath(
|
|
@@ -221,1439 +49,1382 @@ function isHtmlEntrypoint(entrypoint) {
|
|
|
221
49
|
return entrypoint.inputPath.endsWith(".html");
|
|
222
50
|
}
|
|
223
51
|
|
|
224
|
-
// src/core/utils/
|
|
225
|
-
|
|
52
|
+
// src/core/utils/time.ts
|
|
53
|
+
function formatDuration(duration) {
|
|
54
|
+
if (duration < 1e3)
|
|
55
|
+
return `${duration} ms`;
|
|
56
|
+
if (duration < 1e4)
|
|
57
|
+
return `${(duration / 1e3).toFixed(3)} s`;
|
|
58
|
+
if (duration < 6e4)
|
|
59
|
+
return `${(duration / 1e3).toFixed(1)} s`;
|
|
60
|
+
return `${(duration / 1e3).toFixed(0)} s`;
|
|
61
|
+
}
|
|
62
|
+
function withTimeout(promise, duration) {
|
|
63
|
+
return new Promise((res, rej) => {
|
|
64
|
+
const timeout = setTimeout(() => {
|
|
65
|
+
rej(`Promise timed out after ${duration}ms`);
|
|
66
|
+
}, duration);
|
|
67
|
+
promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
226
70
|
|
|
227
|
-
// src/core/utils/
|
|
228
|
-
import
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
71
|
+
// src/core/utils/network.ts
|
|
72
|
+
import dns from "node:dns";
|
|
73
|
+
function isOffline() {
|
|
74
|
+
const isOffline2 = new Promise((res) => {
|
|
75
|
+
dns.resolve("google.com", (err) => {
|
|
76
|
+
if (err == null) {
|
|
77
|
+
res(false);
|
|
78
|
+
} else {
|
|
79
|
+
res(true);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
232
82
|
});
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
83
|
+
return withTimeout(isOffline2, 1e3).catch(() => true);
|
|
84
|
+
}
|
|
85
|
+
async function isOnline() {
|
|
86
|
+
const offline = await isOffline();
|
|
87
|
+
return !offline;
|
|
88
|
+
}
|
|
89
|
+
async function fetchCached(url, config) {
|
|
90
|
+
let content = "";
|
|
91
|
+
if (await isOnline()) {
|
|
92
|
+
const res = await fetch(url);
|
|
93
|
+
if (res.status < 300) {
|
|
94
|
+
content = await res.text();
|
|
95
|
+
await config.fsCache.set(url, content);
|
|
96
|
+
} else {
|
|
97
|
+
config.logger.debug(
|
|
98
|
+
`Failed to download "${url}", falling back to cache...`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!content)
|
|
103
|
+
content = await config.fsCache.get(url) ?? "";
|
|
104
|
+
if (!content)
|
|
105
|
+
throw Error(
|
|
106
|
+
`Offline and "${url}" has not been cached. Try again when online.`
|
|
240
107
|
);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
108
|
+
return content;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/core/builders/vite/plugins/download.ts
|
|
112
|
+
function download(config) {
|
|
113
|
+
return {
|
|
114
|
+
name: "wxt:download",
|
|
115
|
+
resolveId(id) {
|
|
116
|
+
if (id.startsWith("url:"))
|
|
117
|
+
return "\0" + id;
|
|
118
|
+
},
|
|
119
|
+
async load(id) {
|
|
120
|
+
if (!id.startsWith("\0url:"))
|
|
121
|
+
return;
|
|
122
|
+
const url = id.replace("\0url:", "");
|
|
123
|
+
return await fetchCached(url, config);
|
|
249
124
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
default:
|
|
285
|
-
return {
|
|
286
|
-
...info,
|
|
287
|
-
type,
|
|
288
|
-
outputDir: wxt.config.outDir,
|
|
289
|
-
options: {
|
|
290
|
-
include: void 0,
|
|
291
|
-
exclude: void 0
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
})
|
|
296
|
-
);
|
|
297
|
-
if (wxt.config.command === "serve" && !hasBackground) {
|
|
298
|
-
entrypoints.push(
|
|
299
|
-
await getBackgroundEntrypoint({
|
|
300
|
-
inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
|
|
301
|
-
name: "background",
|
|
302
|
-
type: "background",
|
|
303
|
-
skipped: false
|
|
304
|
-
})
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
wxt.logger.debug("All entrypoints:", entrypoints);
|
|
308
|
-
const skippedEntrypointNames = entrypointInfos.filter((item) => item.skipped).map((item) => item.name);
|
|
309
|
-
if (skippedEntrypointNames.length) {
|
|
310
|
-
wxt.logger.warn(
|
|
311
|
-
`Filter excluded the following entrypoints:
|
|
312
|
-
${skippedEntrypointNames.map((item) => `${pc2.dim("-")} ${pc2.cyan(item)}`).join("\n")}`
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
const targetEntrypoints = entrypoints.filter((entry) => {
|
|
316
|
-
const { include, exclude } = entry.options;
|
|
317
|
-
if (include?.length && exclude?.length) {
|
|
318
|
-
wxt.logger.warn(
|
|
319
|
-
`The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
|
|
320
|
-
);
|
|
321
|
-
return false;
|
|
322
|
-
}
|
|
323
|
-
if (exclude?.length && !include?.length) {
|
|
324
|
-
return !exclude.includes(wxt.config.browser);
|
|
325
|
-
}
|
|
326
|
-
if (include?.length && !exclude?.length) {
|
|
327
|
-
return include.includes(wxt.config.browser);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/core/builders/vite/plugins/unimport.ts
|
|
129
|
+
import { createUnimport } from "unimport";
|
|
130
|
+
import { extname } from "path";
|
|
131
|
+
var ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
132
|
+
".js",
|
|
133
|
+
".jsx",
|
|
134
|
+
".ts",
|
|
135
|
+
".tsx",
|
|
136
|
+
".vue",
|
|
137
|
+
".svelte"
|
|
138
|
+
]);
|
|
139
|
+
function unimport(config) {
|
|
140
|
+
const options = config.imports;
|
|
141
|
+
if (options === false)
|
|
142
|
+
return [];
|
|
143
|
+
const unimport2 = createUnimport(options);
|
|
144
|
+
return {
|
|
145
|
+
name: "wxt:unimport",
|
|
146
|
+
async config() {
|
|
147
|
+
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
148
|
+
},
|
|
149
|
+
async transform(code, id) {
|
|
150
|
+
if (id.includes("node_modules"))
|
|
151
|
+
return;
|
|
152
|
+
if (!ENABLED_EXTENSIONS.has(extname(id)))
|
|
153
|
+
return;
|
|
154
|
+
const injected = await unimport2.injectImports(code, id);
|
|
155
|
+
return {
|
|
156
|
+
code: injected.code,
|
|
157
|
+
map: injected.s.generateMap({ hires: "boundary", source: id })
|
|
158
|
+
};
|
|
328
159
|
}
|
|
329
|
-
|
|
330
|
-
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/core/builders/vite/plugins/tsconfigPaths.ts
|
|
164
|
+
function tsconfigPaths(config) {
|
|
165
|
+
return {
|
|
166
|
+
name: "wxt:aliases",
|
|
167
|
+
async config() {
|
|
168
|
+
return {
|
|
169
|
+
resolve: {
|
|
170
|
+
alias: config.alias
|
|
171
|
+
}
|
|
172
|
+
};
|
|
331
173
|
}
|
|
332
|
-
|
|
333
|
-
});
|
|
334
|
-
wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
|
|
335
|
-
await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
|
|
336
|
-
return targetEntrypoints;
|
|
174
|
+
};
|
|
337
175
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
176
|
+
|
|
177
|
+
// src/core/utils/globals.ts
|
|
178
|
+
function getGlobals(config) {
|
|
179
|
+
return [
|
|
180
|
+
{
|
|
181
|
+
name: "MANIFEST_VERSION",
|
|
182
|
+
value: config.manifestVersion,
|
|
183
|
+
type: `2 | 3`
|
|
344
184
|
},
|
|
345
|
-
{
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (absolutePaths.length > 1) {
|
|
350
|
-
lines.push(`- ${name}`);
|
|
351
|
-
absolutePaths.forEach((absolutePath) => {
|
|
352
|
-
lines.push(` - ${relative2(wxt.config.root, absolutePath)}`);
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
return lines;
|
|
185
|
+
{
|
|
186
|
+
name: "BROWSER",
|
|
187
|
+
value: config.browser,
|
|
188
|
+
type: `string`
|
|
356
189
|
},
|
|
357
|
-
[]
|
|
358
|
-
);
|
|
359
|
-
if (errorLines.length > 0) {
|
|
360
|
-
const errorContent = errorLines.join("\n");
|
|
361
|
-
throw Error(
|
|
362
|
-
`Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
|
|
363
|
-
|
|
364
|
-
${errorContent}`
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
function preventNoEntrypoints(files) {
|
|
369
|
-
if (files.length === 0) {
|
|
370
|
-
throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
async function getPopupEntrypoint(info) {
|
|
374
|
-
const options = await getHtmlEntrypointOptions(
|
|
375
|
-
info,
|
|
376
190
|
{
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
defaultIcon: "default_icon",
|
|
381
|
-
defaultTitle: "default_title",
|
|
382
|
-
mv2Key: "type"
|
|
191
|
+
name: "CHROME",
|
|
192
|
+
value: config.browser === "chrome",
|
|
193
|
+
type: `boolean`
|
|
383
194
|
},
|
|
384
195
|
{
|
|
385
|
-
|
|
196
|
+
name: "FIREFOX",
|
|
197
|
+
value: config.browser === "firefox",
|
|
198
|
+
type: `boolean`
|
|
386
199
|
},
|
|
387
200
|
{
|
|
388
|
-
|
|
389
|
-
|
|
201
|
+
name: "SAFARI",
|
|
202
|
+
value: config.browser === "safari",
|
|
203
|
+
type: `boolean`
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: "EDGE",
|
|
207
|
+
value: config.browser === "edge",
|
|
208
|
+
type: `boolean`
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: "OPERA",
|
|
212
|
+
value: config.browser === "opera",
|
|
213
|
+
type: `boolean`
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "COMMAND",
|
|
217
|
+
value: config.command,
|
|
218
|
+
type: `"build" | "serve"`
|
|
390
219
|
}
|
|
391
|
-
|
|
392
|
-
return {
|
|
393
|
-
type: "popup",
|
|
394
|
-
name: "popup",
|
|
395
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
396
|
-
inputPath: info.inputPath,
|
|
397
|
-
outputDir: wxt.config.outDir,
|
|
398
|
-
skipped: info.skipped
|
|
399
|
-
};
|
|
220
|
+
];
|
|
400
221
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
info,
|
|
222
|
+
function getEntrypointGlobals(entrypointName) {
|
|
223
|
+
return [
|
|
404
224
|
{
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
include: "include",
|
|
409
|
-
openInTab: "open_in_tab"
|
|
225
|
+
name: "ENTRYPOINT",
|
|
226
|
+
value: entrypointName,
|
|
227
|
+
type: `string`
|
|
410
228
|
}
|
|
411
|
-
|
|
229
|
+
];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/core/builders/vite/plugins/globals.ts
|
|
233
|
+
function globals(config) {
|
|
412
234
|
return {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
235
|
+
name: "wxt:globals",
|
|
236
|
+
config() {
|
|
237
|
+
const define = {};
|
|
238
|
+
for (const global of getGlobals(config)) {
|
|
239
|
+
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
define
|
|
243
|
+
};
|
|
244
|
+
}
|
|
419
245
|
};
|
|
420
246
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
});
|
|
426
|
-
return {
|
|
427
|
-
type: "unlisted-page",
|
|
428
|
-
name: info.name,
|
|
429
|
-
inputPath: info.inputPath,
|
|
430
|
-
outputDir: wxt.config.outDir,
|
|
431
|
-
options,
|
|
432
|
-
skipped: info.skipped
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
async function getUnlistedScriptEntrypoint({
|
|
436
|
-
inputPath,
|
|
437
|
-
name,
|
|
438
|
-
skipped
|
|
439
|
-
}) {
|
|
440
|
-
const defaultExport = await importEntrypointFile(inputPath);
|
|
441
|
-
if (defaultExport == null) {
|
|
442
|
-
throw Error(
|
|
443
|
-
`${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
const { main: _, ...options } = defaultExport;
|
|
247
|
+
|
|
248
|
+
// src/core/builders/vite/plugins/webextensionPolyfillMock.ts
|
|
249
|
+
import path2 from "node:path";
|
|
250
|
+
function webextensionPolyfillMock(config) {
|
|
447
251
|
return {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
throw Error(
|
|
466
|
-
`${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
|
|
467
|
-
);
|
|
252
|
+
name: "wxt:testing-inline-deps",
|
|
253
|
+
config() {
|
|
254
|
+
return {
|
|
255
|
+
resolve: {
|
|
256
|
+
alias: {
|
|
257
|
+
// Alias to use a mocked version of the polyfill
|
|
258
|
+
"webextension-polyfill": path2.resolve(
|
|
259
|
+
config.wxtModuleDir,
|
|
260
|
+
"dist/virtual/mock-browser"
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
ssr: {
|
|
265
|
+
// Inline all WXT modules
|
|
266
|
+
noExternal: ["wxt"]
|
|
267
|
+
}
|
|
268
|
+
};
|
|
468
269
|
}
|
|
469
|
-
const { main: _, ...moduleOptions } = defaultExport;
|
|
470
|
-
options = moduleOptions;
|
|
471
|
-
}
|
|
472
|
-
if (wxt.config.manifestVersion !== 3) {
|
|
473
|
-
delete options.type;
|
|
474
|
-
}
|
|
475
|
-
return {
|
|
476
|
-
type: "background",
|
|
477
|
-
name,
|
|
478
|
-
inputPath,
|
|
479
|
-
outputDir: wxt.config.outDir,
|
|
480
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
481
|
-
skipped
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
async function getContentScriptEntrypoint({
|
|
485
|
-
inputPath,
|
|
486
|
-
name,
|
|
487
|
-
skipped
|
|
488
|
-
}) {
|
|
489
|
-
const { main: _, ...options } = await importEntrypointFile(inputPath);
|
|
490
|
-
if (options == null) {
|
|
491
|
-
throw Error(
|
|
492
|
-
`${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
return {
|
|
496
|
-
type: "content-script",
|
|
497
|
-
name,
|
|
498
|
-
inputPath,
|
|
499
|
-
outputDir: resolve3(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
500
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
501
|
-
skipped
|
|
502
270
|
};
|
|
503
271
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
272
|
+
|
|
273
|
+
// src/core/builders/vite/plugins/devHtmlPrerender.ts
|
|
274
|
+
import { parseHTML } from "linkedom";
|
|
275
|
+
import { dirname, relative as relative2, resolve as resolve2 } from "node:path";
|
|
276
|
+
var reactRefreshPreamble = "";
|
|
277
|
+
function devHtmlPrerender(config, server) {
|
|
278
|
+
const htmlReloadId = "@wxt/reload-html";
|
|
279
|
+
const resolvedHtmlReloadId = resolve2(
|
|
280
|
+
config.wxtModuleDir,
|
|
281
|
+
"dist/virtual/reload-html.js"
|
|
282
|
+
);
|
|
283
|
+
const virtualReactRefreshId = "@wxt/virtual-react-refresh";
|
|
284
|
+
const resolvedVirtualReactRefreshId = "\0" + virtualReactRefreshId;
|
|
285
|
+
return [
|
|
515
286
|
{
|
|
516
|
-
|
|
287
|
+
apply: "build",
|
|
288
|
+
name: "wxt:dev-html-prerender",
|
|
289
|
+
config() {
|
|
290
|
+
return {
|
|
291
|
+
resolve: {
|
|
292
|
+
alias: {
|
|
293
|
+
[htmlReloadId]: resolvedHtmlReloadId
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
},
|
|
298
|
+
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
|
299
|
+
// before the paths are replaced with their bundled path
|
|
300
|
+
transform(code, id) {
|
|
301
|
+
if (config.command !== "serve" || server == null || !id.endsWith(".html"))
|
|
302
|
+
return;
|
|
303
|
+
const { document } = parseHTML(code);
|
|
304
|
+
const _pointToDevServer = (querySelector, attr) => pointToDevServer(config, server, id, document, querySelector, attr);
|
|
305
|
+
_pointToDevServer("script[type=module]", "src");
|
|
306
|
+
_pointToDevServer("link[rel=stylesheet]", "href");
|
|
307
|
+
const reloader = document.createElement("script");
|
|
308
|
+
reloader.src = htmlReloadId;
|
|
309
|
+
reloader.type = "module";
|
|
310
|
+
document.head.appendChild(reloader);
|
|
311
|
+
const newHtml = document.toString();
|
|
312
|
+
config.logger.debug("transform " + id);
|
|
313
|
+
config.logger.debug("Old HTML:\n" + code);
|
|
314
|
+
config.logger.debug("New HTML:\n" + newHtml);
|
|
315
|
+
return newHtml;
|
|
316
|
+
},
|
|
317
|
+
// Pass the HTML through the dev server to add dev-mode specific code
|
|
318
|
+
async transformIndexHtml(html, ctx) {
|
|
319
|
+
if (config.command !== "serve" || server == null)
|
|
320
|
+
return;
|
|
321
|
+
const originalUrl = `${server.origin}${ctx.path}`;
|
|
322
|
+
const name = getEntrypointName(config.entrypointsDir, ctx.filename);
|
|
323
|
+
const url = `${server.origin}/${name}.html`;
|
|
324
|
+
const serverHtml = await server.transformHtml(url, html, originalUrl);
|
|
325
|
+
const { document } = parseHTML(serverHtml);
|
|
326
|
+
const reactRefreshScript = Array.from(
|
|
327
|
+
document.querySelectorAll("script[type=module]")
|
|
328
|
+
).find((script) => script.innerHTML.includes("@react-refresh"));
|
|
329
|
+
if (reactRefreshScript) {
|
|
330
|
+
reactRefreshPreamble = reactRefreshScript.innerHTML;
|
|
331
|
+
const virtualScript = document.createElement("script");
|
|
332
|
+
virtualScript.type = "module";
|
|
333
|
+
virtualScript.src = `${server.origin}/${virtualReactRefreshId}`;
|
|
334
|
+
reactRefreshScript.replaceWith(virtualScript);
|
|
335
|
+
}
|
|
336
|
+
const viteClientScript = document.querySelector(
|
|
337
|
+
"script[src='/@vite/client']"
|
|
338
|
+
);
|
|
339
|
+
if (viteClientScript) {
|
|
340
|
+
viteClientScript.src = `${server.origin}${viteClientScript.src}`;
|
|
341
|
+
}
|
|
342
|
+
const newHtml = document.toString();
|
|
343
|
+
config.logger.debug("transformIndexHtml " + ctx.filename);
|
|
344
|
+
config.logger.debug("Old HTML:\n" + html);
|
|
345
|
+
config.logger.debug("New HTML:\n" + newHtml);
|
|
346
|
+
return newHtml;
|
|
347
|
+
}
|
|
517
348
|
},
|
|
518
349
|
{
|
|
519
|
-
|
|
350
|
+
name: "wxt:virtualize-react-refresh",
|
|
351
|
+
apply: "serve",
|
|
352
|
+
resolveId(id) {
|
|
353
|
+
if (id === `/${virtualReactRefreshId}`) {
|
|
354
|
+
return resolvedVirtualReactRefreshId;
|
|
355
|
+
}
|
|
356
|
+
if (id.startsWith("/chunks/")) {
|
|
357
|
+
return "\0noop";
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
load(id) {
|
|
361
|
+
if (id === resolvedVirtualReactRefreshId) {
|
|
362
|
+
return reactRefreshPreamble;
|
|
363
|
+
}
|
|
364
|
+
if (id === "\0noop") {
|
|
365
|
+
return "";
|
|
366
|
+
}
|
|
367
|
+
}
|
|
520
368
|
}
|
|
521
|
-
|
|
522
|
-
return {
|
|
523
|
-
type: "sidepanel",
|
|
524
|
-
name: info.name,
|
|
525
|
-
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
526
|
-
inputPath: info.inputPath,
|
|
527
|
-
outputDir: wxt.config.outDir,
|
|
528
|
-
skipped: info.skipped
|
|
529
|
-
};
|
|
369
|
+
];
|
|
530
370
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
371
|
+
function pointToDevServer(config, server, id, document, querySelector, attr) {
|
|
372
|
+
document.querySelectorAll(querySelector).forEach((element) => {
|
|
373
|
+
const src = element.getAttribute(attr);
|
|
374
|
+
if (!src || isUrl(src))
|
|
375
|
+
return;
|
|
376
|
+
let resolvedAbsolutePath;
|
|
377
|
+
const matchingAlias = Object.entries(config.alias).find(
|
|
378
|
+
([key]) => src.startsWith(key)
|
|
379
|
+
);
|
|
380
|
+
if (matchingAlias) {
|
|
381
|
+
const [alias, replacement] = matchingAlias;
|
|
382
|
+
resolvedAbsolutePath = resolve2(
|
|
383
|
+
config.root,
|
|
384
|
+
src.replace(alias, replacement)
|
|
385
|
+
);
|
|
386
|
+
} else {
|
|
387
|
+
resolvedAbsolutePath = resolve2(dirname(id), src);
|
|
388
|
+
}
|
|
389
|
+
if (resolvedAbsolutePath) {
|
|
390
|
+
const relativePath = normalizePath(
|
|
391
|
+
relative2(config.root, resolvedAbsolutePath)
|
|
392
|
+
);
|
|
393
|
+
if (relativePath.startsWith(".")) {
|
|
394
|
+
let path8 = normalizePath(resolvedAbsolutePath);
|
|
395
|
+
if (!path8.startsWith("/"))
|
|
396
|
+
path8 = "/" + path8;
|
|
397
|
+
element.setAttribute(attr, `${server.origin}/@fs${path8}`);
|
|
398
|
+
} else {
|
|
399
|
+
const url = new URL(relativePath, server.origin);
|
|
400
|
+
element.setAttribute(attr, url.href);
|
|
547
401
|
}
|
|
548
402
|
}
|
|
549
403
|
});
|
|
550
|
-
return options;
|
|
551
404
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
"history/index.html": "history",
|
|
561
|
-
"newtab.html": "newtab",
|
|
562
|
-
"newtab/index.html": "newtab",
|
|
563
|
-
"sidepanel.html": "sidepanel",
|
|
564
|
-
"sidepanel/index.html": "sidepanel",
|
|
565
|
-
"*.sidepanel.html": "sidepanel",
|
|
566
|
-
"*.sidepanel/index.html": "sidepanel",
|
|
567
|
-
"devtools.html": "devtools",
|
|
568
|
-
"devtools/index.html": "devtools",
|
|
569
|
-
"background.[jt]s": "background",
|
|
570
|
-
"background/index.[jt]s": "background",
|
|
571
|
-
[VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
|
|
572
|
-
"content.[jt]s?(x)": "content-script",
|
|
573
|
-
"content/index.[jt]s?(x)": "content-script",
|
|
574
|
-
"*.content.[jt]s?(x)": "content-script",
|
|
575
|
-
"*.content/index.[jt]s?(x)": "content-script",
|
|
576
|
-
[`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
577
|
-
[`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
578
|
-
[`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
579
|
-
[`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
580
|
-
"popup.html": "popup",
|
|
581
|
-
"popup/index.html": "popup",
|
|
582
|
-
"options.html": "options",
|
|
583
|
-
"options/index.html": "options",
|
|
584
|
-
"*.html": "unlisted-page",
|
|
585
|
-
"*/index.html": "unlisted-page",
|
|
586
|
-
"*.[jt]s?(x)": "unlisted-script",
|
|
587
|
-
"*/index.[jt]s?(x)": "unlisted-script",
|
|
588
|
-
[`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
|
|
589
|
-
[`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
|
|
590
|
-
};
|
|
591
|
-
var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
|
|
592
|
-
|
|
593
|
-
// src/core/utils/building/generate-wxt-dir.ts
|
|
594
|
-
import { createUnimport } from "unimport";
|
|
595
|
-
import fs4 from "fs-extra";
|
|
596
|
-
import { relative as relative3, resolve as resolve4 } from "path";
|
|
405
|
+
function isUrl(str) {
|
|
406
|
+
try {
|
|
407
|
+
new URL(str);
|
|
408
|
+
return true;
|
|
409
|
+
} catch {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
597
413
|
|
|
598
|
-
// src/core/
|
|
599
|
-
function
|
|
600
|
-
return
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
name: "CHROME",
|
|
613
|
-
value: config.browser === "chrome",
|
|
614
|
-
type: `boolean`
|
|
615
|
-
},
|
|
616
|
-
{
|
|
617
|
-
name: "FIREFOX",
|
|
618
|
-
value: config.browser === "firefox",
|
|
619
|
-
type: `boolean`
|
|
620
|
-
},
|
|
621
|
-
{
|
|
622
|
-
name: "SAFARI",
|
|
623
|
-
value: config.browser === "safari",
|
|
624
|
-
type: `boolean`
|
|
625
|
-
},
|
|
626
|
-
{
|
|
627
|
-
name: "EDGE",
|
|
628
|
-
value: config.browser === "edge",
|
|
629
|
-
type: `boolean`
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
name: "OPERA",
|
|
633
|
-
value: config.browser === "opera",
|
|
634
|
-
type: `boolean`
|
|
635
|
-
},
|
|
636
|
-
{
|
|
637
|
-
name: "COMMAND",
|
|
638
|
-
value: config.command,
|
|
639
|
-
type: `"build" | "serve"`
|
|
414
|
+
// src/core/builders/vite/plugins/devServerGlobals.ts
|
|
415
|
+
function devServerGlobals(config, server) {
|
|
416
|
+
return {
|
|
417
|
+
name: "wxt:dev-server-globals",
|
|
418
|
+
config() {
|
|
419
|
+
if (server == null || config.command == "build")
|
|
420
|
+
return;
|
|
421
|
+
return {
|
|
422
|
+
define: {
|
|
423
|
+
__DEV_SERVER_PROTOCOL__: JSON.stringify("ws:"),
|
|
424
|
+
__DEV_SERVER_HOSTNAME__: JSON.stringify(server.hostname),
|
|
425
|
+
__DEV_SERVER_PORT__: JSON.stringify(server.port)
|
|
426
|
+
}
|
|
427
|
+
};
|
|
640
428
|
}
|
|
641
|
-
|
|
429
|
+
};
|
|
642
430
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
431
|
+
|
|
432
|
+
// src/core/builders/vite/plugins/multipageMove.ts
|
|
433
|
+
import { dirname as dirname2, extname as extname2, resolve as resolve3, join } from "node:path";
|
|
434
|
+
import fs, { ensureDir } from "fs-extra";
|
|
435
|
+
function multipageMove(entrypoints, config) {
|
|
436
|
+
return {
|
|
437
|
+
name: "wxt:multipage-move",
|
|
438
|
+
async writeBundle(_, bundle) {
|
|
439
|
+
for (const oldBundlePath in bundle) {
|
|
440
|
+
const entrypoint = entrypoints.find(
|
|
441
|
+
(entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath)
|
|
442
|
+
);
|
|
443
|
+
if (entrypoint == null) {
|
|
444
|
+
config.logger.debug(
|
|
445
|
+
`No entrypoint found for ${oldBundlePath}, leaving in chunks directory`
|
|
446
|
+
);
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
const newBundlePath = getEntrypointBundlePath(
|
|
450
|
+
entrypoint,
|
|
451
|
+
config.outDir,
|
|
452
|
+
extname2(oldBundlePath)
|
|
453
|
+
);
|
|
454
|
+
if (newBundlePath === oldBundlePath) {
|
|
455
|
+
config.logger.debug(
|
|
456
|
+
"HTML file is already in the correct location",
|
|
457
|
+
oldBundlePath
|
|
458
|
+
);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
const oldAbsPath = resolve3(config.outDir, oldBundlePath);
|
|
462
|
+
const newAbsPath = resolve3(config.outDir, newBundlePath);
|
|
463
|
+
await ensureDir(dirname2(newAbsPath));
|
|
464
|
+
await fs.move(oldAbsPath, newAbsPath, { overwrite: true });
|
|
465
|
+
const renamedChunk = {
|
|
466
|
+
...bundle[oldBundlePath],
|
|
467
|
+
fileName: newBundlePath
|
|
468
|
+
};
|
|
469
|
+
delete bundle[oldBundlePath];
|
|
470
|
+
bundle[newBundlePath] = renamedChunk;
|
|
471
|
+
}
|
|
472
|
+
removeEmptyDirs(config.outDir);
|
|
649
473
|
}
|
|
650
|
-
|
|
474
|
+
};
|
|
651
475
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
description: ""
|
|
665
|
-
},
|
|
666
|
-
"@@bidi_dir": {
|
|
667
|
-
message: "<ltr|rtl>",
|
|
668
|
-
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.'
|
|
669
|
-
},
|
|
670
|
-
"@@bidi_reversed_dir": {
|
|
671
|
-
message: "<rtl|ltr>",
|
|
672
|
-
description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
|
|
673
|
-
},
|
|
674
|
-
"@@bidi_start_edge": {
|
|
675
|
-
message: "<left|right>",
|
|
676
|
-
description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
|
|
677
|
-
},
|
|
678
|
-
"@@bidi_end_edge": {
|
|
679
|
-
message: "<right|left>",
|
|
680
|
-
description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
|
|
476
|
+
async function removeEmptyDirs(dir) {
|
|
477
|
+
const files = await fs.readdir(dir);
|
|
478
|
+
for (const file of files) {
|
|
479
|
+
const filePath = join(dir, file);
|
|
480
|
+
const stats = await fs.stat(filePath);
|
|
481
|
+
if (stats.isDirectory()) {
|
|
482
|
+
await removeEmptyDirs(filePath);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
await fs.rmdir(dir);
|
|
487
|
+
} catch {
|
|
681
488
|
}
|
|
682
|
-
};
|
|
683
|
-
function parseI18nMessages(messagesJson) {
|
|
684
|
-
return Object.entries({
|
|
685
|
-
...predefinedMessages,
|
|
686
|
-
...messagesJson
|
|
687
|
-
}).map(([name, details]) => ({
|
|
688
|
-
name,
|
|
689
|
-
...details
|
|
690
|
-
}));
|
|
691
489
|
}
|
|
692
490
|
|
|
693
|
-
// src/core/
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
491
|
+
// src/core/builders/vite/plugins/virtualEntrypoint.ts
|
|
492
|
+
import fs2 from "fs-extra";
|
|
493
|
+
import { resolve as resolve4 } from "path";
|
|
494
|
+
function virtualEntrypoint(type, config) {
|
|
495
|
+
const virtualId = `virtual:wxt-${type}?`;
|
|
496
|
+
const resolvedVirtualId = `\0${virtualId}`;
|
|
497
|
+
return {
|
|
498
|
+
name: `wxt:virtual-entrypoint`,
|
|
499
|
+
resolveId(id) {
|
|
500
|
+
const index = id.indexOf(virtualId);
|
|
501
|
+
if (index === -1)
|
|
502
|
+
return;
|
|
503
|
+
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
|
504
|
+
return resolvedVirtualId + inputPath;
|
|
505
|
+
},
|
|
506
|
+
async load(id) {
|
|
507
|
+
if (!id.startsWith(resolvedVirtualId))
|
|
508
|
+
return;
|
|
509
|
+
const inputPath = id.replace(resolvedVirtualId, "");
|
|
510
|
+
const template = await fs2.readFile(
|
|
511
|
+
resolve4(config.wxtModuleDir, `dist/virtual/${type}-entrypoint.js`),
|
|
512
|
+
"utf-8"
|
|
513
|
+
);
|
|
514
|
+
return template.replace(`virtual:user-${type}`, inputPath);
|
|
702
515
|
}
|
|
703
|
-
}
|
|
704
|
-
references.push(await writePathsDeclarationFile(entrypoints));
|
|
705
|
-
references.push(await writeI18nDeclarationFile());
|
|
706
|
-
references.push(await writeGlobalsDeclarationFile());
|
|
707
|
-
const mainReference = await writeMainDeclarationFile(references);
|
|
708
|
-
await writeTsConfigFile(mainReference);
|
|
709
|
-
}
|
|
710
|
-
async function writeImportsDeclarationFile(unimport2) {
|
|
711
|
-
const filePath = resolve4(wxt.config.typesDir, "imports.d.ts");
|
|
712
|
-
await unimport2.scanImportsFromDir(void 0, { cwd: wxt.config.srcDir });
|
|
713
|
-
await writeFileIfDifferent(
|
|
714
|
-
filePath,
|
|
715
|
-
["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
|
|
716
|
-
"\n"
|
|
717
|
-
) + "\n"
|
|
718
|
-
);
|
|
719
|
-
return filePath;
|
|
720
|
-
}
|
|
721
|
-
async function writeImportsEslintFile(unimport2, options) {
|
|
722
|
-
const globals2 = {};
|
|
723
|
-
const eslintrc = { globals: globals2 };
|
|
724
|
-
(await unimport2.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().forEach((name) => {
|
|
725
|
-
eslintrc.globals[name] = options.eslintrc.globalsPropValue;
|
|
726
|
-
});
|
|
727
|
-
await fs4.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
|
|
516
|
+
};
|
|
728
517
|
}
|
|
729
|
-
async function writePathsDeclarationFile(entrypoints) {
|
|
730
|
-
const filePath = resolve4(wxt.config.typesDir, "paths.d.ts");
|
|
731
|
-
const unions = entrypoints.map(
|
|
732
|
-
(entry) => getEntrypointBundlePath(
|
|
733
|
-
entry,
|
|
734
|
-
wxt.config.outDir,
|
|
735
|
-
isHtmlEntrypoint(entry) ? ".html" : ".js"
|
|
736
|
-
)
|
|
737
|
-
).concat(await getPublicFiles()).map(normalizePath).map((path8) => ` | "/${path8}"`).sort().join("\n");
|
|
738
|
-
const template = `// Generated by wxt
|
|
739
|
-
import "wxt/browser";
|
|
740
518
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
{{ union }}
|
|
744
|
-
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
|
|
745
|
-
export interface WxtRuntime extends Runtime.Static {
|
|
746
|
-
getURL(path: PublicPath): string;
|
|
747
|
-
getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
`;
|
|
751
|
-
await writeFileIfDifferent(
|
|
752
|
-
filePath,
|
|
753
|
-
template.replace("{{ union }}", unions || " | never")
|
|
754
|
-
);
|
|
755
|
-
return filePath;
|
|
756
|
-
}
|
|
757
|
-
async function writeI18nDeclarationFile() {
|
|
758
|
-
const filePath = resolve4(wxt.config.typesDir, "i18n.d.ts");
|
|
759
|
-
const defaultLocale = wxt.config.manifest.default_locale;
|
|
760
|
-
const template = `// Generated by wxt
|
|
761
|
-
import "wxt/browser";
|
|
519
|
+
// src/core/utils/constants.ts
|
|
520
|
+
var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
|
|
762
521
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
522
|
+
// src/core/builders/vite/plugins/noopBackground.ts
|
|
523
|
+
function noopBackground() {
|
|
524
|
+
const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
|
|
525
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
526
|
+
return {
|
|
527
|
+
name: "wxt:noop-background",
|
|
528
|
+
resolveId(id) {
|
|
529
|
+
if (id === virtualModuleId)
|
|
530
|
+
return resolvedVirtualModuleId;
|
|
531
|
+
},
|
|
532
|
+
load(id) {
|
|
533
|
+
if (id === resolvedVirtualModuleId) {
|
|
534
|
+
return `import { defineBackground } from 'wxt/sandbox';
|
|
535
|
+
export default defineBackground(() => void 0)`;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
773
540
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
541
|
+
// src/core/builders/vite/plugins/cssEntrypoints.ts
|
|
542
|
+
function cssEntrypoints(entrypoint, config) {
|
|
543
|
+
return {
|
|
544
|
+
name: "wxt:css-entrypoint",
|
|
545
|
+
config() {
|
|
546
|
+
return {
|
|
547
|
+
build: {
|
|
548
|
+
rollupOptions: {
|
|
549
|
+
output: {
|
|
550
|
+
assetFileNames: () => getEntrypointBundlePath(entrypoint, config.outDir, ".css")
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
},
|
|
556
|
+
generateBundle(_, bundle) {
|
|
557
|
+
Object.keys(bundle).forEach((file) => {
|
|
558
|
+
if (file.endsWith(".js"))
|
|
559
|
+
delete bundle[file];
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
};
|
|
777
563
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
messages = parseI18nMessages({});
|
|
791
|
-
}
|
|
792
|
-
const overrides = messages.map((message) => {
|
|
793
|
-
return ` /**
|
|
794
|
-
* ${message.description || "No message description."}
|
|
795
|
-
*
|
|
796
|
-
* "${message.message}"
|
|
797
|
-
*/
|
|
798
|
-
getMessage(
|
|
799
|
-
messageName: "${message.name}",
|
|
800
|
-
substitutions?: string | string[],
|
|
801
|
-
options?: GetMessageOptions,
|
|
802
|
-
): string;`;
|
|
564
|
+
|
|
565
|
+
// src/core/builders/vite/plugins/bundleAnalysis.ts
|
|
566
|
+
import { visualizer } from "@aklinker1/rollup-plugin-visualizer";
|
|
567
|
+
import path3 from "node:path";
|
|
568
|
+
var increment = 0;
|
|
569
|
+
function bundleAnalysis(config) {
|
|
570
|
+
return visualizer({
|
|
571
|
+
template: "raw-data",
|
|
572
|
+
filename: path3.resolve(
|
|
573
|
+
config.analysis.outputDir,
|
|
574
|
+
`${config.analysis.outputName}-${increment++}.json`
|
|
575
|
+
)
|
|
803
576
|
});
|
|
804
|
-
await writeFileIfDifferent(
|
|
805
|
-
filePath,
|
|
806
|
-
template.replace("{{ overrides }}", overrides.join("\n"))
|
|
807
|
-
);
|
|
808
|
-
return filePath;
|
|
809
|
-
}
|
|
810
|
-
async function writeGlobalsDeclarationFile() {
|
|
811
|
-
const filePath = resolve4(wxt.config.typesDir, "globals.d.ts");
|
|
812
|
-
const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
|
|
813
|
-
await writeFileIfDifferent(
|
|
814
|
-
filePath,
|
|
815
|
-
[
|
|
816
|
-
"// Generated by wxt",
|
|
817
|
-
"export {}",
|
|
818
|
-
"interface ImportMetaEnv {",
|
|
819
|
-
...globals2.map((global) => ` readonly ${global.name}: ${global.type};`),
|
|
820
|
-
"}",
|
|
821
|
-
"interface ImportMeta {",
|
|
822
|
-
" readonly env: ImportMetaEnv",
|
|
823
|
-
"}"
|
|
824
|
-
].join("\n") + "\n"
|
|
825
|
-
);
|
|
826
|
-
return filePath;
|
|
827
|
-
}
|
|
828
|
-
async function writeMainDeclarationFile(references) {
|
|
829
|
-
const dir = wxt.config.wxtDir;
|
|
830
|
-
const filePath = resolve4(dir, "wxt.d.ts");
|
|
831
|
-
await writeFileIfDifferent(
|
|
832
|
-
filePath,
|
|
833
|
-
[
|
|
834
|
-
"// Generated by wxt",
|
|
835
|
-
`/// <reference types="wxt/vite-builder-env" />`,
|
|
836
|
-
...references.map(
|
|
837
|
-
(ref) => `/// <reference types="./${normalizePath(relative3(dir, ref))}" />`
|
|
838
|
-
)
|
|
839
|
-
].join("\n") + "\n"
|
|
840
|
-
);
|
|
841
|
-
return filePath;
|
|
842
577
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
"strict": true,
|
|
865
|
-
"skipLibCheck": true,
|
|
866
|
-
"paths": {
|
|
867
|
-
${paths}
|
|
578
|
+
|
|
579
|
+
// src/core/builders/vite/plugins/excludeBrowserPolyfill.ts
|
|
580
|
+
function excludeBrowserPolyfill(config) {
|
|
581
|
+
const virtualId = "virtual:wxt-webextension-polyfill-disabled";
|
|
582
|
+
return {
|
|
583
|
+
name: "wxt:exclude-browser-polyfill",
|
|
584
|
+
config() {
|
|
585
|
+
if (config.experimental.includeBrowserPolyfill)
|
|
586
|
+
return;
|
|
587
|
+
return {
|
|
588
|
+
resolve: {
|
|
589
|
+
alias: {
|
|
590
|
+
"webextension-polyfill": virtualId
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
},
|
|
595
|
+
load(id) {
|
|
596
|
+
if (id === virtualId) {
|
|
597
|
+
return "export default chrome";
|
|
598
|
+
}
|
|
868
599
|
}
|
|
869
|
-
}
|
|
870
|
-
"include": [
|
|
871
|
-
"${getTsconfigPath(wxt.config.root)}/**/*",
|
|
872
|
-
"./${getTsconfigPath(mainReference)}"
|
|
873
|
-
],
|
|
874
|
-
"exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
|
|
875
|
-
}`
|
|
876
|
-
);
|
|
600
|
+
};
|
|
877
601
|
}
|
|
878
602
|
|
|
879
|
-
// src/core/
|
|
880
|
-
|
|
881
|
-
import path5 from "node:path";
|
|
882
|
-
|
|
883
|
-
// src/core/utils/cache.ts
|
|
884
|
-
import fs5, { ensureDir } from "fs-extra";
|
|
885
|
-
import { dirname as dirname2, resolve as resolve5 } from "path";
|
|
886
|
-
function createFsCache(wxtDir) {
|
|
887
|
-
const getPath = (key) => resolve5(wxtDir, "cache", encodeURIComponent(key));
|
|
603
|
+
// src/core/builders/vite/plugins/entrypointGroupGlobals.ts
|
|
604
|
+
function entrypointGroupGlobals(entrypointGroup) {
|
|
888
605
|
return {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
const path8 = getPath(key);
|
|
896
|
-
try {
|
|
897
|
-
return await fs5.readFile(path8, "utf-8");
|
|
898
|
-
} catch {
|
|
899
|
-
return void 0;
|
|
606
|
+
name: "wxt:entrypoint-group-globals",
|
|
607
|
+
config() {
|
|
608
|
+
const define = {};
|
|
609
|
+
let name = Array.isArray(entrypointGroup) ? "html" : entrypointGroup.name;
|
|
610
|
+
for (const global of getEntrypointGlobals(name)) {
|
|
611
|
+
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
900
612
|
}
|
|
613
|
+
return {
|
|
614
|
+
define
|
|
615
|
+
};
|
|
901
616
|
}
|
|
902
617
|
};
|
|
903
618
|
}
|
|
904
619
|
|
|
905
|
-
// src/core/
|
|
906
|
-
|
|
620
|
+
// src/core/builders/vite/plugins/defineImportMeta.ts
|
|
621
|
+
function defineImportMeta() {
|
|
622
|
+
return {
|
|
623
|
+
name: "wxt:define",
|
|
624
|
+
config() {
|
|
625
|
+
return {
|
|
626
|
+
define: {
|
|
627
|
+
// This works for all extension contexts, including background service worker
|
|
628
|
+
"import.meta.url": "self.location.href"
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
}
|
|
907
634
|
|
|
908
|
-
// src/core/
|
|
909
|
-
import
|
|
910
|
-
import
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
_pointToDevServer("script[type=module]", "src");
|
|
942
|
-
_pointToDevServer("link[rel=stylesheet]", "href");
|
|
943
|
-
const reloader = document.createElement("script");
|
|
944
|
-
reloader.src = htmlReloadId;
|
|
945
|
-
reloader.type = "module";
|
|
946
|
-
document.head.appendChild(reloader);
|
|
947
|
-
const newHtml = document.toString();
|
|
948
|
-
config.logger.debug("transform " + id);
|
|
949
|
-
config.logger.debug("Old HTML:\n" + code);
|
|
950
|
-
config.logger.debug("New HTML:\n" + newHtml);
|
|
951
|
-
return newHtml;
|
|
952
|
-
},
|
|
953
|
-
// Pass the HTML through the dev server to add dev-mode specific code
|
|
954
|
-
async transformIndexHtml(html, ctx) {
|
|
955
|
-
const server = config.server;
|
|
956
|
-
if (config.command !== "serve" || server == null)
|
|
957
|
-
return;
|
|
958
|
-
const originalUrl = `${server.origin}${ctx.path}`;
|
|
959
|
-
const name = getEntrypointName(config.entrypointsDir, ctx.filename);
|
|
960
|
-
const url = `${server.origin}/${name}.html`;
|
|
961
|
-
const serverHtml = await server.transformHtml(url, html, originalUrl);
|
|
962
|
-
const { document } = parseHTML2(serverHtml);
|
|
963
|
-
const reactRefreshScript = Array.from(
|
|
964
|
-
document.querySelectorAll("script[type=module]")
|
|
965
|
-
).find((script) => script.innerHTML.includes("@react-refresh"));
|
|
966
|
-
if (reactRefreshScript) {
|
|
967
|
-
reactRefreshPreamble = reactRefreshScript.innerHTML;
|
|
968
|
-
const virtualScript = document.createElement("script");
|
|
969
|
-
virtualScript.type = "module";
|
|
970
|
-
virtualScript.src = `${server.origin}/${virtualReactRefreshId}`;
|
|
971
|
-
reactRefreshScript.replaceWith(virtualScript);
|
|
972
|
-
}
|
|
973
|
-
const viteClientScript = document.querySelector(
|
|
974
|
-
"script[src='/@vite/client']"
|
|
975
|
-
);
|
|
976
|
-
if (viteClientScript) {
|
|
977
|
-
viteClientScript.src = `${server.origin}${viteClientScript.src}`;
|
|
978
|
-
}
|
|
979
|
-
const newHtml = document.toString();
|
|
980
|
-
config.logger.debug("transformIndexHtml " + ctx.filename);
|
|
981
|
-
config.logger.debug("Old HTML:\n" + html);
|
|
982
|
-
config.logger.debug("New HTML:\n" + newHtml);
|
|
983
|
-
return newHtml;
|
|
984
|
-
}
|
|
985
|
-
},
|
|
986
|
-
{
|
|
987
|
-
name: "wxt:virtualize-react-refresh",
|
|
988
|
-
apply: "serve",
|
|
989
|
-
resolveId(id) {
|
|
990
|
-
if (id === `/${virtualReactRefreshId}`) {
|
|
991
|
-
return resolvedVirtualReactRefreshId;
|
|
992
|
-
}
|
|
993
|
-
if (id.startsWith("/chunks/")) {
|
|
994
|
-
return "\0noop";
|
|
995
|
-
}
|
|
996
|
-
},
|
|
997
|
-
load(id) {
|
|
998
|
-
if (id === resolvedVirtualReactRefreshId) {
|
|
999
|
-
return reactRefreshPreamble;
|
|
1000
|
-
}
|
|
1001
|
-
if (id === "\0noop") {
|
|
1002
|
-
return "";
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
635
|
+
// src/core/utils/fs.ts
|
|
636
|
+
import fs3 from "fs-extra";
|
|
637
|
+
import glob from "fast-glob";
|
|
638
|
+
async function writeFileIfDifferent(file, newContents) {
|
|
639
|
+
const existingContents = await fs3.readFile(file, "utf-8").catch(() => void 0);
|
|
640
|
+
if (existingContents !== newContents) {
|
|
641
|
+
await fs3.writeFile(file, newContents);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
async function getPublicFiles() {
|
|
645
|
+
if (!await fs3.exists(wxt.config.publicDir))
|
|
646
|
+
return [];
|
|
647
|
+
const files = await glob("**/*", { cwd: wxt.config.publicDir });
|
|
648
|
+
return files.map(unnormalizePath);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/core/utils/building/build-entrypoints.ts
|
|
652
|
+
import fs4 from "fs-extra";
|
|
653
|
+
import { dirname as dirname3, resolve as resolve5 } from "path";
|
|
654
|
+
import pc from "picocolors";
|
|
655
|
+
async function buildEntrypoints(groups, spinner) {
|
|
656
|
+
const steps = [];
|
|
657
|
+
for (let i = 0; i < groups.length; i++) {
|
|
658
|
+
const group = groups[i];
|
|
659
|
+
const groupNames = [group].flat().map((e) => e.name);
|
|
660
|
+
const groupNameColored = groupNames.join(pc.dim(", "));
|
|
661
|
+
spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
|
662
|
+
try {
|
|
663
|
+
steps.push(await wxt.builder.build(group));
|
|
664
|
+
} catch (err) {
|
|
665
|
+
spinner.stop().clear();
|
|
666
|
+
wxt.logger.error(err);
|
|
667
|
+
throw Error(`Failed to build ${groupNames.join(", ")}`, { cause: err });
|
|
1005
668
|
}
|
|
1006
|
-
|
|
669
|
+
}
|
|
670
|
+
const publicAssets = await copyPublicDirectory();
|
|
671
|
+
return { publicAssets, steps };
|
|
1007
672
|
}
|
|
1008
|
-
function
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
const
|
|
1015
|
-
|
|
673
|
+
async function copyPublicDirectory() {
|
|
674
|
+
const files = await getPublicFiles();
|
|
675
|
+
if (files.length === 0)
|
|
676
|
+
return [];
|
|
677
|
+
const publicAssets = [];
|
|
678
|
+
for (const file of files) {
|
|
679
|
+
const srcPath = resolve5(wxt.config.publicDir, file);
|
|
680
|
+
const outPath = resolve5(wxt.config.outDir, file);
|
|
681
|
+
await fs4.ensureDir(dirname3(outPath));
|
|
682
|
+
await fs4.copyFile(srcPath, outPath);
|
|
683
|
+
publicAssets.push({
|
|
684
|
+
type: "asset",
|
|
685
|
+
fileName: file
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
return publicAssets;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/core/utils/arrays.ts
|
|
692
|
+
function every(array, predicate) {
|
|
693
|
+
for (let i = 0; i < array.length; i++)
|
|
694
|
+
if (!predicate(array[i], i))
|
|
695
|
+
return false;
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
function some(array, predicate) {
|
|
699
|
+
for (let i = 0; i < array.length; i++)
|
|
700
|
+
if (predicate(array[i], i))
|
|
701
|
+
return true;
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/core/utils/building/detect-dev-changes.ts
|
|
706
|
+
function detectDevChanges(changedFiles, currentOutput) {
|
|
707
|
+
const isConfigChange = some(
|
|
708
|
+
changedFiles,
|
|
709
|
+
(file) => file === wxt.config.userConfigMetadata.configFile
|
|
710
|
+
);
|
|
711
|
+
if (isConfigChange)
|
|
712
|
+
return { type: "full-restart" };
|
|
713
|
+
const isRunnerChange = some(
|
|
714
|
+
changedFiles,
|
|
715
|
+
(file) => file === wxt.config.runnerConfig.configFile
|
|
716
|
+
);
|
|
717
|
+
if (isRunnerChange)
|
|
718
|
+
return { type: "browser-restart" };
|
|
719
|
+
const changedSteps = new Set(
|
|
720
|
+
changedFiles.flatMap(
|
|
721
|
+
(changedFile) => findEffectedSteps(changedFile, currentOutput)
|
|
722
|
+
)
|
|
723
|
+
);
|
|
724
|
+
if (changedSteps.size === 0)
|
|
725
|
+
return { type: "no-change" };
|
|
726
|
+
const unchangedOutput = {
|
|
727
|
+
manifest: currentOutput.manifest,
|
|
728
|
+
steps: [],
|
|
729
|
+
publicAssets: []
|
|
730
|
+
};
|
|
731
|
+
const changedOutput = {
|
|
732
|
+
manifest: currentOutput.manifest,
|
|
733
|
+
steps: [],
|
|
734
|
+
publicAssets: []
|
|
735
|
+
};
|
|
736
|
+
for (const step of currentOutput.steps) {
|
|
737
|
+
if (changedSteps.has(step)) {
|
|
738
|
+
changedOutput.steps.push(step);
|
|
739
|
+
} else {
|
|
740
|
+
unchangedOutput.steps.push(step);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
for (const asset of currentOutput.publicAssets) {
|
|
744
|
+
if (changedSteps.has(asset)) {
|
|
745
|
+
changedOutput.publicAssets.push(asset);
|
|
746
|
+
} else {
|
|
747
|
+
unchangedOutput.publicAssets.push(asset);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
|
|
751
|
+
if (isOnlyHtmlChanges) {
|
|
752
|
+
return {
|
|
753
|
+
type: "html-reload",
|
|
754
|
+
cachedOutput: unchangedOutput,
|
|
755
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
|
|
759
|
+
changedOutput.steps.flatMap((step) => step.entrypoints),
|
|
760
|
+
(entry) => entry.type === "content-script"
|
|
761
|
+
);
|
|
762
|
+
if (isOnlyContentScripts) {
|
|
763
|
+
return {
|
|
764
|
+
type: "content-script-reload",
|
|
765
|
+
cachedOutput: unchangedOutput,
|
|
766
|
+
changedSteps: changedOutput.steps,
|
|
767
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
return {
|
|
771
|
+
type: "extension-reload",
|
|
772
|
+
cachedOutput: unchangedOutput,
|
|
773
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function findEffectedSteps(changedFile, currentOutput) {
|
|
777
|
+
const changes = [];
|
|
778
|
+
const changedPath = normalizePath(changedFile);
|
|
779
|
+
const isChunkEffected = (chunk) => (
|
|
780
|
+
// If it's an HTML file with the same path, is is effected because HTML files need to be re-rendered
|
|
781
|
+
// - fileName is normalized, relative bundle path, "<entrypoint-name>.html"
|
|
782
|
+
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
|
|
783
|
+
// - moduleIds are absolute, normalized paths
|
|
784
|
+
chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
|
|
785
|
+
);
|
|
786
|
+
for (const step of currentOutput.steps) {
|
|
787
|
+
const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
|
|
788
|
+
if (effectedChunk)
|
|
789
|
+
changes.push(step);
|
|
790
|
+
}
|
|
791
|
+
const effectedAsset = currentOutput.publicAssets.find(
|
|
792
|
+
(chunk) => isChunkEffected(chunk)
|
|
793
|
+
);
|
|
794
|
+
if (effectedAsset)
|
|
795
|
+
changes.push(effectedAsset);
|
|
796
|
+
return changes;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// src/core/utils/building/find-entrypoints.ts
|
|
800
|
+
import { relative as relative3, resolve as resolve6 } from "path";
|
|
801
|
+
import fs5 from "fs-extra";
|
|
802
|
+
import { minimatch } from "minimatch";
|
|
803
|
+
import { parseHTML as parseHTML2 } from "linkedom";
|
|
804
|
+
import JSON5 from "json5";
|
|
805
|
+
import glob2 from "fast-glob";
|
|
806
|
+
import pc2 from "picocolors";
|
|
807
|
+
async function findEntrypoints() {
|
|
808
|
+
const relativePaths = await glob2(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
|
|
809
|
+
cwd: wxt.config.entrypointsDir
|
|
810
|
+
});
|
|
811
|
+
relativePaths.sort();
|
|
812
|
+
const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
|
|
813
|
+
const entrypointInfos = relativePaths.reduce((results, relativePath) => {
|
|
814
|
+
const inputPath = resolve6(wxt.config.entrypointsDir, relativePath);
|
|
815
|
+
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
|
|
816
|
+
const matchingGlob = pathGlobs.find(
|
|
817
|
+
(glob4) => minimatch(relativePath, glob4)
|
|
818
|
+
);
|
|
819
|
+
if (matchingGlob) {
|
|
820
|
+
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
|
|
821
|
+
results.push({
|
|
822
|
+
name,
|
|
823
|
+
inputPath,
|
|
824
|
+
type,
|
|
825
|
+
skipped: wxt.config.filterEntrypoints != null && !wxt.config.filterEntrypoints.has(name)
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
return results;
|
|
829
|
+
}, []);
|
|
830
|
+
preventNoEntrypoints(entrypointInfos);
|
|
831
|
+
preventDuplicateEntrypointNames(entrypointInfos);
|
|
832
|
+
let hasBackground = false;
|
|
833
|
+
const entrypoints = await Promise.all(
|
|
834
|
+
entrypointInfos.map(async (info) => {
|
|
835
|
+
const { type } = info;
|
|
836
|
+
switch (type) {
|
|
837
|
+
case "popup":
|
|
838
|
+
return await getPopupEntrypoint(info);
|
|
839
|
+
case "sidepanel":
|
|
840
|
+
return await getSidepanelEntrypoint(info);
|
|
841
|
+
case "options":
|
|
842
|
+
return await getOptionsEntrypoint(info);
|
|
843
|
+
case "background":
|
|
844
|
+
hasBackground = true;
|
|
845
|
+
return await getBackgroundEntrypoint(info);
|
|
846
|
+
case "content-script":
|
|
847
|
+
return await getContentScriptEntrypoint(info);
|
|
848
|
+
case "unlisted-page":
|
|
849
|
+
return await getUnlistedPageEntrypoint(info);
|
|
850
|
+
case "unlisted-script":
|
|
851
|
+
return await getUnlistedScriptEntrypoint(info);
|
|
852
|
+
case "content-script-style":
|
|
853
|
+
return {
|
|
854
|
+
...info,
|
|
855
|
+
type,
|
|
856
|
+
outputDir: resolve6(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
857
|
+
options: {
|
|
858
|
+
include: void 0,
|
|
859
|
+
exclude: void 0
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
default:
|
|
863
|
+
return {
|
|
864
|
+
...info,
|
|
865
|
+
type,
|
|
866
|
+
outputDir: wxt.config.outDir,
|
|
867
|
+
options: {
|
|
868
|
+
include: void 0,
|
|
869
|
+
exclude: void 0
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
})
|
|
874
|
+
);
|
|
875
|
+
if (wxt.config.command === "serve" && !hasBackground) {
|
|
876
|
+
entrypoints.push(
|
|
877
|
+
await getBackgroundEntrypoint({
|
|
878
|
+
inputPath: VIRTUAL_NOOP_BACKGROUND_MODULE_ID,
|
|
879
|
+
name: "background",
|
|
880
|
+
type: "background",
|
|
881
|
+
skipped: false
|
|
882
|
+
})
|
|
1016
883
|
);
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
884
|
+
}
|
|
885
|
+
wxt.logger.debug("All entrypoints:", entrypoints);
|
|
886
|
+
const skippedEntrypointNames = entrypointInfos.filter((item) => item.skipped).map((item) => item.name);
|
|
887
|
+
if (skippedEntrypointNames.length) {
|
|
888
|
+
wxt.logger.warn(
|
|
889
|
+
`Filter excluded the following entrypoints:
|
|
890
|
+
${skippedEntrypointNames.map((item) => `${pc2.dim("-")} ${pc2.cyan(item)}`).join("\n")}`
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
const targetEntrypoints = entrypoints.filter((entry) => {
|
|
894
|
+
const { include, exclude } = entry.options;
|
|
895
|
+
if (include?.length && exclude?.length) {
|
|
896
|
+
wxt.logger.warn(
|
|
897
|
+
`The ${entry.name} entrypoint lists both include and exclude, but only one can be used per entrypoint. Entrypoint ignored.`
|
|
1022
898
|
);
|
|
1023
|
-
|
|
1024
|
-
resolvedAbsolutePath = resolve6(dirname3(id), src);
|
|
899
|
+
return false;
|
|
1025
900
|
}
|
|
1026
|
-
if (
|
|
1027
|
-
|
|
1028
|
-
relative4(config.root, resolvedAbsolutePath)
|
|
1029
|
-
);
|
|
1030
|
-
if (relativePath.startsWith(".")) {
|
|
1031
|
-
let path8 = normalizePath(resolvedAbsolutePath);
|
|
1032
|
-
if (!path8.startsWith("/"))
|
|
1033
|
-
path8 = "/" + path8;
|
|
1034
|
-
element.setAttribute(attr, `${server.origin}/@fs${path8}`);
|
|
1035
|
-
} else {
|
|
1036
|
-
const url = new URL(relativePath, server.origin);
|
|
1037
|
-
element.setAttribute(attr, url.href);
|
|
1038
|
-
}
|
|
901
|
+
if (exclude?.length && !include?.length) {
|
|
902
|
+
return !exclude.includes(wxt.config.browser);
|
|
1039
903
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
function isUrl(str) {
|
|
1043
|
-
try {
|
|
1044
|
-
new URL(str);
|
|
1045
|
-
return true;
|
|
1046
|
-
} catch {
|
|
1047
|
-
return false;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
// src/core/builders/vite/plugins/devServerGlobals.ts
|
|
1052
|
-
function devServerGlobals(config) {
|
|
1053
|
-
return {
|
|
1054
|
-
name: "wxt:dev-server-globals",
|
|
1055
|
-
config() {
|
|
1056
|
-
if (config.server == null || config.command == "build")
|
|
1057
|
-
return;
|
|
1058
|
-
return {
|
|
1059
|
-
define: {
|
|
1060
|
-
__DEV_SERVER_PROTOCOL__: JSON.stringify("ws:"),
|
|
1061
|
-
__DEV_SERVER_HOSTNAME__: JSON.stringify(config.server.hostname),
|
|
1062
|
-
__DEV_SERVER_PORT__: JSON.stringify(config.server.port)
|
|
1063
|
-
}
|
|
1064
|
-
};
|
|
904
|
+
if (include?.length && !exclude?.length) {
|
|
905
|
+
return include.includes(wxt.config.browser);
|
|
1065
906
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
import dns from "node:dns";
|
|
1071
|
-
|
|
1072
|
-
// src/core/utils/time.ts
|
|
1073
|
-
function formatDuration(duration) {
|
|
1074
|
-
if (duration < 1e3)
|
|
1075
|
-
return `${duration} ms`;
|
|
1076
|
-
if (duration < 1e4)
|
|
1077
|
-
return `${(duration / 1e3).toFixed(3)} s`;
|
|
1078
|
-
if (duration < 6e4)
|
|
1079
|
-
return `${(duration / 1e3).toFixed(1)} s`;
|
|
1080
|
-
return `${(duration / 1e3).toFixed(0)} s`;
|
|
1081
|
-
}
|
|
1082
|
-
function withTimeout(promise, duration) {
|
|
1083
|
-
return new Promise((res, rej) => {
|
|
1084
|
-
const timeout = setTimeout(() => {
|
|
1085
|
-
rej(`Promise timed out after ${duration}ms`);
|
|
1086
|
-
}, duration);
|
|
1087
|
-
promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
|
|
907
|
+
if (skippedEntrypointNames.includes(entry.name)) {
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
return true;
|
|
1088
911
|
});
|
|
912
|
+
wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
|
|
913
|
+
await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
|
|
914
|
+
return targetEntrypoints;
|
|
1089
915
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
916
|
+
function preventDuplicateEntrypointNames(files) {
|
|
917
|
+
const namesToPaths = files.reduce(
|
|
918
|
+
(map, { name, inputPath }) => {
|
|
919
|
+
map[name] ??= [];
|
|
920
|
+
map[name].push(inputPath);
|
|
921
|
+
return map;
|
|
922
|
+
},
|
|
923
|
+
{}
|
|
924
|
+
);
|
|
925
|
+
const errorLines = Object.entries(namesToPaths).reduce(
|
|
926
|
+
(lines, [name, absolutePaths]) => {
|
|
927
|
+
if (absolutePaths.length > 1) {
|
|
928
|
+
lines.push(`- ${name}`);
|
|
929
|
+
absolutePaths.forEach((absolutePath) => {
|
|
930
|
+
lines.push(` - ${relative3(wxt.config.root, absolutePath)}`);
|
|
931
|
+
});
|
|
1099
932
|
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
return !offline;
|
|
1107
|
-
}
|
|
1108
|
-
async function fetchCached(url, config) {
|
|
1109
|
-
let content = "";
|
|
1110
|
-
if (await isOnline()) {
|
|
1111
|
-
const res = await fetch(url);
|
|
1112
|
-
if (res.status < 300) {
|
|
1113
|
-
content = await res.text();
|
|
1114
|
-
await config.fsCache.set(url, content);
|
|
1115
|
-
} else {
|
|
1116
|
-
config.logger.debug(
|
|
1117
|
-
`Failed to download "${url}", falling back to cache...`
|
|
1118
|
-
);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
if (!content)
|
|
1122
|
-
content = await config.fsCache.get(url) ?? "";
|
|
1123
|
-
if (!content)
|
|
933
|
+
return lines;
|
|
934
|
+
},
|
|
935
|
+
[]
|
|
936
|
+
);
|
|
937
|
+
if (errorLines.length > 0) {
|
|
938
|
+
const errorContent = errorLines.join("\n");
|
|
1124
939
|
throw Error(
|
|
1125
|
-
`
|
|
940
|
+
`Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
|
|
941
|
+
|
|
942
|
+
${errorContent}`
|
|
1126
943
|
);
|
|
1127
|
-
|
|
944
|
+
}
|
|
1128
945
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
946
|
+
function preventNoEntrypoints(files) {
|
|
947
|
+
if (files.length === 0) {
|
|
948
|
+
throw Error(`No entrypoints found in ${wxt.config.entrypointsDir}`);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
async function getPopupEntrypoint(info) {
|
|
952
|
+
const options = await getHtmlEntrypointOptions(
|
|
953
|
+
info,
|
|
954
|
+
{
|
|
955
|
+
browserStyle: "browse_style",
|
|
956
|
+
exclude: "exclude",
|
|
957
|
+
include: "include",
|
|
958
|
+
defaultIcon: "default_icon",
|
|
959
|
+
defaultTitle: "default_title",
|
|
960
|
+
mv2Key: "type"
|
|
1137
961
|
},
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
962
|
+
{
|
|
963
|
+
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
defaultTitle: (content) => content,
|
|
967
|
+
mv2Key: (content) => content === "page_action" ? "page_action" : "browser_action"
|
|
1143
968
|
}
|
|
969
|
+
);
|
|
970
|
+
return {
|
|
971
|
+
type: "popup",
|
|
972
|
+
name: "popup",
|
|
973
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
974
|
+
inputPath: info.inputPath,
|
|
975
|
+
outputDir: wxt.config.outDir,
|
|
976
|
+
skipped: info.skipped
|
|
1144
977
|
};
|
|
1145
978
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
const entrypoint = entrypoints.find(
|
|
1156
|
-
(entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath)
|
|
1157
|
-
);
|
|
1158
|
-
if (entrypoint == null) {
|
|
1159
|
-
config.logger.debug(
|
|
1160
|
-
`No entrypoint found for ${oldBundlePath}, leaving in chunks directory`
|
|
1161
|
-
);
|
|
1162
|
-
continue;
|
|
1163
|
-
}
|
|
1164
|
-
const newBundlePath = getEntrypointBundlePath(
|
|
1165
|
-
entrypoint,
|
|
1166
|
-
config.outDir,
|
|
1167
|
-
extname(oldBundlePath)
|
|
1168
|
-
);
|
|
1169
|
-
if (newBundlePath === oldBundlePath) {
|
|
1170
|
-
config.logger.debug(
|
|
1171
|
-
"HTML file is already in the correct location",
|
|
1172
|
-
oldBundlePath
|
|
1173
|
-
);
|
|
1174
|
-
continue;
|
|
1175
|
-
}
|
|
1176
|
-
const oldAbsPath = resolve7(config.outDir, oldBundlePath);
|
|
1177
|
-
const newAbsPath = resolve7(config.outDir, newBundlePath);
|
|
1178
|
-
await ensureDir2(dirname4(newAbsPath));
|
|
1179
|
-
await fs6.move(oldAbsPath, newAbsPath, { overwrite: true });
|
|
1180
|
-
const renamedChunk = {
|
|
1181
|
-
...bundle[oldBundlePath],
|
|
1182
|
-
fileName: newBundlePath
|
|
1183
|
-
};
|
|
1184
|
-
delete bundle[oldBundlePath];
|
|
1185
|
-
bundle[newBundlePath] = renamedChunk;
|
|
1186
|
-
}
|
|
1187
|
-
removeEmptyDirs(config.outDir);
|
|
979
|
+
async function getOptionsEntrypoint(info) {
|
|
980
|
+
const options = await getHtmlEntrypointOptions(
|
|
981
|
+
info,
|
|
982
|
+
{
|
|
983
|
+
browserStyle: "browse_style",
|
|
984
|
+
chromeStyle: "chrome_style",
|
|
985
|
+
exclude: "exclude",
|
|
986
|
+
include: "include",
|
|
987
|
+
openInTab: "open_in_tab"
|
|
1188
988
|
}
|
|
989
|
+
);
|
|
990
|
+
return {
|
|
991
|
+
type: "options",
|
|
992
|
+
name: "options",
|
|
993
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
994
|
+
inputPath: info.inputPath,
|
|
995
|
+
outputDir: wxt.config.outDir,
|
|
996
|
+
skipped: info.skipped
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
async function getUnlistedPageEntrypoint(info) {
|
|
1000
|
+
const options = await getHtmlEntrypointOptions(info, {
|
|
1001
|
+
exclude: "exclude",
|
|
1002
|
+
include: "include"
|
|
1003
|
+
});
|
|
1004
|
+
return {
|
|
1005
|
+
type: "unlisted-page",
|
|
1006
|
+
name: info.name,
|
|
1007
|
+
inputPath: info.inputPath,
|
|
1008
|
+
outputDir: wxt.config.outDir,
|
|
1009
|
+
options,
|
|
1010
|
+
skipped: info.skipped
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
async function getUnlistedScriptEntrypoint({
|
|
1014
|
+
inputPath,
|
|
1015
|
+
name,
|
|
1016
|
+
skipped
|
|
1017
|
+
}) {
|
|
1018
|
+
const defaultExport = await importEntrypointFile(inputPath);
|
|
1019
|
+
if (defaultExport == null) {
|
|
1020
|
+
throw Error(
|
|
1021
|
+
`${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
const { main: _, ...options } = defaultExport;
|
|
1025
|
+
return {
|
|
1026
|
+
type: "unlisted-script",
|
|
1027
|
+
name,
|
|
1028
|
+
inputPath,
|
|
1029
|
+
outputDir: wxt.config.outDir,
|
|
1030
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1031
|
+
skipped
|
|
1189
1032
|
};
|
|
1190
1033
|
}
|
|
1191
|
-
async function
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1034
|
+
async function getBackgroundEntrypoint({
|
|
1035
|
+
inputPath,
|
|
1036
|
+
name,
|
|
1037
|
+
skipped
|
|
1038
|
+
}) {
|
|
1039
|
+
let options = {};
|
|
1040
|
+
if (inputPath !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
|
|
1041
|
+
const defaultExport = await importEntrypointFile(inputPath);
|
|
1042
|
+
if (defaultExport == null) {
|
|
1043
|
+
throw Error(
|
|
1044
|
+
`${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
|
|
1045
|
+
);
|
|
1198
1046
|
}
|
|
1047
|
+
const { main: _, ...moduleOptions } = defaultExport;
|
|
1048
|
+
options = moduleOptions;
|
|
1199
1049
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
} catch {
|
|
1050
|
+
if (wxt.config.manifestVersion !== 3) {
|
|
1051
|
+
delete options.type;
|
|
1203
1052
|
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
// src/core/builders/vite/plugins/unimport.ts
|
|
1207
|
-
import { createUnimport as createUnimport2 } from "unimport";
|
|
1208
|
-
import { extname as extname2 } from "path";
|
|
1209
|
-
var ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1210
|
-
".js",
|
|
1211
|
-
".jsx",
|
|
1212
|
-
".ts",
|
|
1213
|
-
".tsx",
|
|
1214
|
-
".vue",
|
|
1215
|
-
".svelte"
|
|
1216
|
-
]);
|
|
1217
|
-
function unimport(config) {
|
|
1218
|
-
const options = config.imports;
|
|
1219
|
-
if (options === false)
|
|
1220
|
-
return [];
|
|
1221
|
-
const unimport2 = createUnimport2(options);
|
|
1222
1053
|
return {
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
return;
|
|
1230
|
-
if (!ENABLED_EXTENSIONS.has(extname2(id)))
|
|
1231
|
-
return;
|
|
1232
|
-
const injected = await unimport2.injectImports(code, id);
|
|
1233
|
-
return {
|
|
1234
|
-
code: injected.code,
|
|
1235
|
-
map: injected.s.generateMap({ hires: "boundary", source: id })
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1054
|
+
type: "background",
|
|
1055
|
+
name,
|
|
1056
|
+
inputPath,
|
|
1057
|
+
outputDir: wxt.config.outDir,
|
|
1058
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1059
|
+
skipped
|
|
1238
1060
|
};
|
|
1239
1061
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1062
|
+
async function getContentScriptEntrypoint({
|
|
1063
|
+
inputPath,
|
|
1064
|
+
name,
|
|
1065
|
+
skipped
|
|
1066
|
+
}) {
|
|
1067
|
+
const { main: _, ...options } = await importEntrypointFile(inputPath);
|
|
1068
|
+
if (options == null) {
|
|
1069
|
+
throw Error(
|
|
1070
|
+
`${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1247
1073
|
return {
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
return resolvedVirtualId + inputPath;
|
|
1255
|
-
},
|
|
1256
|
-
async load(id) {
|
|
1257
|
-
if (!id.startsWith(resolvedVirtualId))
|
|
1258
|
-
return;
|
|
1259
|
-
const inputPath = id.replace(resolvedVirtualId, "");
|
|
1260
|
-
const template = await fs7.readFile(
|
|
1261
|
-
resolve8(config.wxtModuleDir, `dist/virtual/${type}-entrypoint.js`),
|
|
1262
|
-
"utf-8"
|
|
1263
|
-
);
|
|
1264
|
-
return template.replace(`virtual:user-${type}`, inputPath);
|
|
1265
|
-
}
|
|
1074
|
+
type: "content-script",
|
|
1075
|
+
name,
|
|
1076
|
+
inputPath,
|
|
1077
|
+
outputDir: resolve6(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
1078
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1079
|
+
skipped
|
|
1266
1080
|
};
|
|
1267
1081
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1082
|
+
async function getSidepanelEntrypoint(info) {
|
|
1083
|
+
const options = await getHtmlEntrypointOptions(
|
|
1084
|
+
info,
|
|
1085
|
+
{
|
|
1086
|
+
browserStyle: "browse_style",
|
|
1087
|
+
exclude: "exclude",
|
|
1088
|
+
include: "include",
|
|
1089
|
+
defaultIcon: "default_icon",
|
|
1090
|
+
defaultTitle: "default_title",
|
|
1091
|
+
openAtInstall: "open_at_install"
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
defaultTitle: (content) => content
|
|
1279
1098
|
}
|
|
1099
|
+
);
|
|
1100
|
+
return {
|
|
1101
|
+
type: "sidepanel",
|
|
1102
|
+
name: info.name,
|
|
1103
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1104
|
+
inputPath: info.inputPath,
|
|
1105
|
+
outputDir: wxt.config.outDir,
|
|
1106
|
+
skipped: info.skipped
|
|
1280
1107
|
};
|
|
1281
1108
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
const
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1109
|
+
async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
|
|
1110
|
+
const content = await fs5.readFile(info.inputPath, "utf-8");
|
|
1111
|
+
const { document } = parseHTML2(content);
|
|
1112
|
+
const options = {};
|
|
1113
|
+
const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
|
|
1114
|
+
Object.entries(keyMap).forEach(([_key, manifestKey]) => {
|
|
1115
|
+
const key = _key;
|
|
1116
|
+
const content2 = queries?.[key] ? queries[key](document, manifestKey) : defaultQuery(manifestKey);
|
|
1117
|
+
if (content2) {
|
|
1118
|
+
try {
|
|
1119
|
+
options[key] = (parsers?.[key] ?? JSON5.parse)(content2);
|
|
1120
|
+
} catch (err) {
|
|
1121
|
+
wxt.logger.fatal(
|
|
1122
|
+
`Failed to parse meta tag content. Usually this means you have invalid JSON5 content (content=${content2})`,
|
|
1123
|
+
err
|
|
1124
|
+
);
|
|
1297
1125
|
}
|
|
1298
1126
|
}
|
|
1299
|
-
};
|
|
1127
|
+
});
|
|
1128
|
+
return options;
|
|
1129
|
+
}
|
|
1130
|
+
var PATH_GLOB_TO_TYPE_MAP = {
|
|
1131
|
+
"sandbox.html": "sandbox",
|
|
1132
|
+
"sandbox/index.html": "sandbox",
|
|
1133
|
+
"*.sandbox.html": "sandbox",
|
|
1134
|
+
"*.sandbox/index.html": "sandbox",
|
|
1135
|
+
"bookmarks.html": "bookmarks",
|
|
1136
|
+
"bookmarks/index.html": "bookmarks",
|
|
1137
|
+
"history.html": "history",
|
|
1138
|
+
"history/index.html": "history",
|
|
1139
|
+
"newtab.html": "newtab",
|
|
1140
|
+
"newtab/index.html": "newtab",
|
|
1141
|
+
"sidepanel.html": "sidepanel",
|
|
1142
|
+
"sidepanel/index.html": "sidepanel",
|
|
1143
|
+
"*.sidepanel.html": "sidepanel",
|
|
1144
|
+
"*.sidepanel/index.html": "sidepanel",
|
|
1145
|
+
"devtools.html": "devtools",
|
|
1146
|
+
"devtools/index.html": "devtools",
|
|
1147
|
+
"background.[jt]s": "background",
|
|
1148
|
+
"background/index.[jt]s": "background",
|
|
1149
|
+
[VIRTUAL_NOOP_BACKGROUND_MODULE_ID]: "background",
|
|
1150
|
+
"content.[jt]s?(x)": "content-script",
|
|
1151
|
+
"content/index.[jt]s?(x)": "content-script",
|
|
1152
|
+
"*.content.[jt]s?(x)": "content-script",
|
|
1153
|
+
"*.content/index.[jt]s?(x)": "content-script",
|
|
1154
|
+
[`content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1155
|
+
[`*.content.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1156
|
+
[`content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1157
|
+
[`*.content/index.${CSS_EXTENSIONS_PATTERN}`]: "content-script-style",
|
|
1158
|
+
"popup.html": "popup",
|
|
1159
|
+
"popup/index.html": "popup",
|
|
1160
|
+
"options.html": "options",
|
|
1161
|
+
"options/index.html": "options",
|
|
1162
|
+
"*.html": "unlisted-page",
|
|
1163
|
+
"*/index.html": "unlisted-page",
|
|
1164
|
+
"*.[jt]s?(x)": "unlisted-script",
|
|
1165
|
+
"*/index.[jt]s?(x)": "unlisted-script",
|
|
1166
|
+
[`*.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style",
|
|
1167
|
+
[`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
|
|
1168
|
+
};
|
|
1169
|
+
var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
|
|
1170
|
+
|
|
1171
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
1172
|
+
import { createUnimport as createUnimport2 } from "unimport";
|
|
1173
|
+
import fs6 from "fs-extra";
|
|
1174
|
+
import { relative as relative4, resolve as resolve7 } from "path";
|
|
1175
|
+
import path4 from "node:path";
|
|
1176
|
+
|
|
1177
|
+
// src/core/utils/i18n.ts
|
|
1178
|
+
var predefinedMessages = {
|
|
1179
|
+
"@@extension_id": {
|
|
1180
|
+
message: "<browser.runtime.id>",
|
|
1181
|
+
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."
|
|
1182
|
+
},
|
|
1183
|
+
"@@ui_locale": {
|
|
1184
|
+
message: "<browser.i18n.getUiLocale()>",
|
|
1185
|
+
description: ""
|
|
1186
|
+
},
|
|
1187
|
+
"@@bidi_dir": {
|
|
1188
|
+
message: "<ltr|rtl>",
|
|
1189
|
+
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.'
|
|
1190
|
+
},
|
|
1191
|
+
"@@bidi_reversed_dir": {
|
|
1192
|
+
message: "<rtl|ltr>",
|
|
1193
|
+
description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
|
|
1194
|
+
},
|
|
1195
|
+
"@@bidi_start_edge": {
|
|
1196
|
+
message: "<left|right>",
|
|
1197
|
+
description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
|
|
1198
|
+
},
|
|
1199
|
+
"@@bidi_end_edge": {
|
|
1200
|
+
message: "<right|left>",
|
|
1201
|
+
description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
function parseI18nMessages(messagesJson) {
|
|
1205
|
+
return Object.entries({
|
|
1206
|
+
...predefinedMessages,
|
|
1207
|
+
...messagesJson
|
|
1208
|
+
}).map(([name, details]) => ({
|
|
1209
|
+
name,
|
|
1210
|
+
...details
|
|
1211
|
+
}));
|
|
1300
1212
|
}
|
|
1301
1213
|
|
|
1302
|
-
// src/core/
|
|
1303
|
-
function
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
assetFileNames: () => getEntrypointBundlePath(entrypoint, config.outDir, ".css")
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
};
|
|
1316
|
-
},
|
|
1317
|
-
generateBundle(_, bundle) {
|
|
1318
|
-
Object.keys(bundle).forEach((file) => {
|
|
1319
|
-
if (file.endsWith(".js"))
|
|
1320
|
-
delete bundle[file];
|
|
1321
|
-
});
|
|
1214
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
1215
|
+
async function generateTypesDir(entrypoints) {
|
|
1216
|
+
await fs6.ensureDir(wxt.config.typesDir);
|
|
1217
|
+
const references = [];
|
|
1218
|
+
if (wxt.config.imports !== false) {
|
|
1219
|
+
const unimport2 = createUnimport2(wxt.config.imports);
|
|
1220
|
+
references.push(await writeImportsDeclarationFile(unimport2));
|
|
1221
|
+
if (wxt.config.imports.eslintrc.enabled) {
|
|
1222
|
+
await writeImportsEslintFile(unimport2, wxt.config.imports);
|
|
1322
1223
|
}
|
|
1323
|
-
}
|
|
1224
|
+
}
|
|
1225
|
+
references.push(await writePathsDeclarationFile(entrypoints));
|
|
1226
|
+
references.push(await writeI18nDeclarationFile());
|
|
1227
|
+
references.push(await writeGlobalsDeclarationFile());
|
|
1228
|
+
const mainReference = await writeMainDeclarationFile(references);
|
|
1229
|
+
await writeTsConfigFile(mainReference);
|
|
1324
1230
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1231
|
+
async function writeImportsDeclarationFile(unimport2) {
|
|
1232
|
+
const filePath = resolve7(wxt.config.typesDir, "imports.d.ts");
|
|
1233
|
+
await unimport2.scanImportsFromDir(void 0, { cwd: wxt.config.srcDir });
|
|
1234
|
+
await writeFileIfDifferent(
|
|
1235
|
+
filePath,
|
|
1236
|
+
["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
|
|
1237
|
+
"\n"
|
|
1238
|
+
) + "\n"
|
|
1239
|
+
);
|
|
1240
|
+
return filePath;
|
|
1241
|
+
}
|
|
1242
|
+
async function writeImportsEslintFile(unimport2, options) {
|
|
1243
|
+
const globals2 = {};
|
|
1244
|
+
const eslintrc = { globals: globals2 };
|
|
1245
|
+
(await unimport2.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().forEach((name) => {
|
|
1246
|
+
eslintrc.globals[name] = options.eslintrc.globalsPropValue;
|
|
1337
1247
|
});
|
|
1248
|
+
await fs6.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
|
|
1338
1249
|
}
|
|
1250
|
+
async function writePathsDeclarationFile(entrypoints) {
|
|
1251
|
+
const filePath = resolve7(wxt.config.typesDir, "paths.d.ts");
|
|
1252
|
+
const unions = entrypoints.map(
|
|
1253
|
+
(entry) => getEntrypointBundlePath(
|
|
1254
|
+
entry,
|
|
1255
|
+
wxt.config.outDir,
|
|
1256
|
+
isHtmlEntrypoint(entry) ? ".html" : ".js"
|
|
1257
|
+
)
|
|
1258
|
+
).concat(await getPublicFiles()).map(normalizePath).map((path8) => ` | "/${path8}"`).sort().join("\n");
|
|
1259
|
+
const template = `// Generated by wxt
|
|
1260
|
+
import "wxt/browser";
|
|
1339
1261
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
}
|
|
1349
|
-
return {
|
|
1350
|
-
define
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
};
|
|
1262
|
+
declare module "wxt/browser" {
|
|
1263
|
+
export type PublicPath =
|
|
1264
|
+
{{ union }}
|
|
1265
|
+
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
|
|
1266
|
+
export interface WxtRuntime extends Runtime.Static {
|
|
1267
|
+
getURL(path: PublicPath): string;
|
|
1268
|
+
getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
|
|
1269
|
+
}
|
|
1354
1270
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
config() {
|
|
1362
|
-
return {
|
|
1363
|
-
resolve: {
|
|
1364
|
-
alias: {
|
|
1365
|
-
// Alias to use a mocked version of the polyfill
|
|
1366
|
-
"webextension-polyfill": path4.resolve(
|
|
1367
|
-
config.wxtModuleDir,
|
|
1368
|
-
"dist/virtual/mock-browser"
|
|
1369
|
-
)
|
|
1370
|
-
}
|
|
1371
|
-
},
|
|
1372
|
-
ssr: {
|
|
1373
|
-
// Inline all WXT modules
|
|
1374
|
-
noExternal: ["wxt"]
|
|
1375
|
-
}
|
|
1376
|
-
};
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1271
|
+
`;
|
|
1272
|
+
await writeFileIfDifferent(
|
|
1273
|
+
filePath,
|
|
1274
|
+
template.replace("{{ union }}", unions || " | never")
|
|
1275
|
+
);
|
|
1276
|
+
return filePath;
|
|
1379
1277
|
}
|
|
1278
|
+
async function writeI18nDeclarationFile() {
|
|
1279
|
+
const filePath = resolve7(wxt.config.typesDir, "i18n.d.ts");
|
|
1280
|
+
const defaultLocale = wxt.config.manifest.default_locale;
|
|
1281
|
+
const template = `// Generated by wxt
|
|
1282
|
+
import "wxt/browser";
|
|
1380
1283
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
alias: {
|
|
1392
|
-
"webextension-polyfill": virtualId
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
};
|
|
1396
|
-
},
|
|
1397
|
-
load(id) {
|
|
1398
|
-
if (id === virtualId) {
|
|
1399
|
-
return "export default chrome";
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
};
|
|
1403
|
-
}
|
|
1284
|
+
declare module "wxt/browser" {
|
|
1285
|
+
/**
|
|
1286
|
+
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
1287
|
+
*/
|
|
1288
|
+
interface GetMessageOptions {
|
|
1289
|
+
/**
|
|
1290
|
+
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
1291
|
+
*/
|
|
1292
|
+
escapeLt?: boolean
|
|
1293
|
+
}
|
|
1404
1294
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1295
|
+
export interface WxtI18n extends I18n.Static {
|
|
1296
|
+
{{ overrides }}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
`;
|
|
1300
|
+
let messages;
|
|
1301
|
+
if (defaultLocale) {
|
|
1302
|
+
const defaultLocalePath = path4.resolve(
|
|
1303
|
+
wxt.config.publicDir,
|
|
1304
|
+
"_locales",
|
|
1305
|
+
defaultLocale,
|
|
1306
|
+
"messages.json"
|
|
1307
|
+
);
|
|
1308
|
+
const content = JSON.parse(await fs6.readFile(defaultLocalePath, "utf-8"));
|
|
1309
|
+
messages = parseI18nMessages(content);
|
|
1310
|
+
} else {
|
|
1311
|
+
messages = parseI18nMessages({});
|
|
1312
|
+
}
|
|
1313
|
+
const overrides = messages.map((message) => {
|
|
1314
|
+
return ` /**
|
|
1315
|
+
* ${message.description || "No message description."}
|
|
1316
|
+
*
|
|
1317
|
+
* "${message.message}"
|
|
1318
|
+
*/
|
|
1319
|
+
getMessage(
|
|
1320
|
+
messageName: "${message.name}",
|
|
1321
|
+
substitutions?: string | string[],
|
|
1322
|
+
options?: GetMessageOptions,
|
|
1323
|
+
): string;`;
|
|
1324
|
+
});
|
|
1325
|
+
await writeFileIfDifferent(
|
|
1326
|
+
filePath,
|
|
1327
|
+
template.replace("{{ overrides }}", overrides.join("\n"))
|
|
1328
|
+
);
|
|
1329
|
+
return filePath;
|
|
1330
|
+
}
|
|
1331
|
+
async function writeGlobalsDeclarationFile() {
|
|
1332
|
+
const filePath = resolve7(wxt.config.typesDir, "globals.d.ts");
|
|
1333
|
+
const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
|
|
1334
|
+
await writeFileIfDifferent(
|
|
1335
|
+
filePath,
|
|
1336
|
+
[
|
|
1337
|
+
"// Generated by wxt",
|
|
1338
|
+
"export {}",
|
|
1339
|
+
"interface ImportMetaEnv {",
|
|
1340
|
+
...globals2.map((global) => ` readonly ${global.name}: ${global.type};`),
|
|
1341
|
+
"}",
|
|
1342
|
+
"interface ImportMeta {",
|
|
1343
|
+
" readonly env: ImportMetaEnv",
|
|
1344
|
+
"}"
|
|
1345
|
+
].join("\n") + "\n"
|
|
1346
|
+
);
|
|
1347
|
+
return filePath;
|
|
1348
|
+
}
|
|
1349
|
+
async function writeMainDeclarationFile(references) {
|
|
1350
|
+
const dir = wxt.config.wxtDir;
|
|
1351
|
+
const filePath = resolve7(dir, "wxt.d.ts");
|
|
1352
|
+
await writeFileIfDifferent(
|
|
1353
|
+
filePath,
|
|
1354
|
+
[
|
|
1355
|
+
"// Generated by wxt",
|
|
1356
|
+
`/// <reference types="wxt/vite-builder-env" />`,
|
|
1357
|
+
...references.map(
|
|
1358
|
+
(ref) => `/// <reference types="./${normalizePath(relative4(dir, ref))}" />`
|
|
1359
|
+
)
|
|
1360
|
+
].join("\n") + "\n"
|
|
1361
|
+
);
|
|
1362
|
+
return filePath;
|
|
1363
|
+
}
|
|
1364
|
+
async function writeTsConfigFile(mainReference) {
|
|
1365
|
+
const dir = wxt.config.wxtDir;
|
|
1366
|
+
const getTsconfigPath = (path8) => normalizePath(relative4(dir, path8));
|
|
1367
|
+
const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
|
|
1368
|
+
const aliasPath = getTsconfigPath(absolutePath);
|
|
1369
|
+
return [
|
|
1370
|
+
` "${alias}": ["${aliasPath}"]`,
|
|
1371
|
+
` "${alias}/*": ["${aliasPath}/*"]`
|
|
1372
|
+
];
|
|
1373
|
+
}).join(",\n");
|
|
1374
|
+
await writeFileIfDifferent(
|
|
1375
|
+
resolve7(dir, "tsconfig.json"),
|
|
1376
|
+
`{
|
|
1377
|
+
"compilerOptions": {
|
|
1378
|
+
"target": "ESNext",
|
|
1379
|
+
"module": "ESNext",
|
|
1380
|
+
"moduleResolution": "Bundler",
|
|
1381
|
+
"noEmit": true,
|
|
1382
|
+
"esModuleInterop": true,
|
|
1383
|
+
"forceConsistentCasingInFileNames": true,
|
|
1384
|
+
"resolveJsonModule": true,
|
|
1385
|
+
"strict": true,
|
|
1386
|
+
"skipLibCheck": true,
|
|
1387
|
+
"paths": {
|
|
1388
|
+
${paths}
|
|
1418
1389
|
}
|
|
1419
|
-
}
|
|
1390
|
+
},
|
|
1391
|
+
"include": [
|
|
1392
|
+
"${getTsconfigPath(wxt.config.root)}/**/*",
|
|
1393
|
+
"./${getTsconfigPath(mainReference)}"
|
|
1394
|
+
],
|
|
1395
|
+
"exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
|
|
1396
|
+
}`
|
|
1397
|
+
);
|
|
1420
1398
|
}
|
|
1421
1399
|
|
|
1422
|
-
// src/core/
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
name: "wxt:define",
|
|
1426
|
-
config() {
|
|
1427
|
-
return {
|
|
1428
|
-
define: {
|
|
1429
|
-
// This works for all extension contexts, including background service worker
|
|
1430
|
-
"import.meta.url": "self.location.href"
|
|
1431
|
-
}
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
};
|
|
1435
|
-
}
|
|
1400
|
+
// src/core/utils/building/resolve-config.ts
|
|
1401
|
+
import { loadConfig } from "c12";
|
|
1402
|
+
import path5 from "node:path";
|
|
1436
1403
|
|
|
1437
|
-
// src/core/
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
const resolvedUserConfig = await userConfig.vite?.(wxtConfig.env) ?? {};
|
|
1443
|
-
const config = vite.mergeConfig(
|
|
1444
|
-
resolvedUserConfig,
|
|
1445
|
-
resolvedInlineConfig
|
|
1446
|
-
);
|
|
1447
|
-
config.root = wxtConfig.root;
|
|
1448
|
-
config.configFile = false;
|
|
1449
|
-
config.logLevel = "warn";
|
|
1450
|
-
config.mode = wxtConfig.mode;
|
|
1451
|
-
config.build ??= {};
|
|
1452
|
-
config.build.outDir = wxtConfig.outDir;
|
|
1453
|
-
config.build.emptyOutDir = false;
|
|
1454
|
-
if (config.build.minify == null && wxtConfig.command === "serve") {
|
|
1455
|
-
config.build.minify = false;
|
|
1456
|
-
}
|
|
1457
|
-
if (config.build.sourcemap == null && wxtConfig.command === "serve") {
|
|
1458
|
-
config.build.sourcemap = "inline";
|
|
1459
|
-
}
|
|
1460
|
-
config.plugins ??= [];
|
|
1461
|
-
config.plugins.push(
|
|
1462
|
-
download(wxtConfig),
|
|
1463
|
-
devHtmlPrerender(wxtConfig),
|
|
1464
|
-
unimport(wxtConfig),
|
|
1465
|
-
virtualEntrypoint("background", wxtConfig),
|
|
1466
|
-
virtualEntrypoint("content-script-isolated-world", wxtConfig),
|
|
1467
|
-
virtualEntrypoint("content-script-main-world", wxtConfig),
|
|
1468
|
-
virtualEntrypoint("unlisted-script", wxtConfig),
|
|
1469
|
-
devServerGlobals(wxtConfig),
|
|
1470
|
-
tsconfigPaths(wxtConfig),
|
|
1471
|
-
noopBackground(),
|
|
1472
|
-
globals(wxtConfig),
|
|
1473
|
-
excludeBrowserPolyfill(wxtConfig),
|
|
1474
|
-
defineImportMeta()
|
|
1475
|
-
);
|
|
1476
|
-
if (wxtConfig.analysis.enabled) {
|
|
1477
|
-
config.plugins.push(bundleAnalysis(wxtConfig));
|
|
1478
|
-
}
|
|
1479
|
-
return config;
|
|
1480
|
-
};
|
|
1481
|
-
const getLibModeConfig = (entrypoint) => {
|
|
1482
|
-
const entry = getRollupEntry(entrypoint);
|
|
1483
|
-
const plugins = [
|
|
1484
|
-
entrypointGroupGlobals(entrypoint)
|
|
1485
|
-
];
|
|
1486
|
-
if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
|
|
1487
|
-
plugins.push(cssEntrypoints(entrypoint, wxtConfig));
|
|
1488
|
-
}
|
|
1489
|
-
const libMode = {
|
|
1490
|
-
mode: wxtConfig.mode,
|
|
1491
|
-
plugins,
|
|
1492
|
-
build: {
|
|
1493
|
-
lib: {
|
|
1494
|
-
entry,
|
|
1495
|
-
formats: ["iife"],
|
|
1496
|
-
name: "_",
|
|
1497
|
-
fileName: entrypoint.name
|
|
1498
|
-
},
|
|
1499
|
-
rollupOptions: {
|
|
1500
|
-
output: {
|
|
1501
|
-
// There's only a single output for this build, so we use the desired bundle path for the
|
|
1502
|
-
// entry output (like "content-scripts/overlay.js")
|
|
1503
|
-
entryFileNames: getEntrypointBundlePath(
|
|
1504
|
-
entrypoint,
|
|
1505
|
-
wxtConfig.outDir,
|
|
1506
|
-
".js"
|
|
1507
|
-
),
|
|
1508
|
-
// Output content script CSS to `content-scripts/`, but all other scripts are written to
|
|
1509
|
-
// `assets/`.
|
|
1510
|
-
assetFileNames: ({ name }) => {
|
|
1511
|
-
if (entrypoint.type === "content-script" && name?.endsWith("css")) {
|
|
1512
|
-
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
1513
|
-
} else {
|
|
1514
|
-
return `assets/${entrypoint.name}.[ext]`;
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
},
|
|
1520
|
-
define: {
|
|
1521
|
-
// See https://github.com/aklinker1/vite-plugin-web-extension/issues/96
|
|
1522
|
-
"process.env.NODE_ENV": JSON.stringify(wxtConfig.mode)
|
|
1523
|
-
}
|
|
1524
|
-
};
|
|
1525
|
-
return libMode;
|
|
1526
|
-
};
|
|
1527
|
-
const getMultiPageConfig = (entrypoints) => {
|
|
1528
|
-
const htmlEntrypoints = new Set(
|
|
1529
|
-
entrypoints.filter(isHtmlEntrypoint).map((e) => e.name)
|
|
1530
|
-
);
|
|
1531
|
-
return {
|
|
1532
|
-
mode: wxtConfig.mode,
|
|
1533
|
-
plugins: [
|
|
1534
|
-
multipageMove(entrypoints, wxtConfig),
|
|
1535
|
-
entrypointGroupGlobals(entrypoints)
|
|
1536
|
-
],
|
|
1537
|
-
build: {
|
|
1538
|
-
rollupOptions: {
|
|
1539
|
-
input: entrypoints.reduce((input, entry) => {
|
|
1540
|
-
input[entry.name] = getRollupEntry(entry);
|
|
1541
|
-
return input;
|
|
1542
|
-
}, {}),
|
|
1543
|
-
output: {
|
|
1544
|
-
// Include a hash to prevent conflicts
|
|
1545
|
-
chunkFileNames: "chunks/[name]-[hash].js",
|
|
1546
|
-
entryFileNames: ({ name }) => {
|
|
1547
|
-
if (htmlEntrypoints.has(name))
|
|
1548
|
-
return "chunks/[name]-[hash].js";
|
|
1549
|
-
return "[name].js";
|
|
1550
|
-
},
|
|
1551
|
-
// We can't control the "name", so we need a hash to prevent conflicts
|
|
1552
|
-
assetFileNames: "assets/[name]-[hash].[ext]"
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
};
|
|
1558
|
-
const getCssConfig = (entrypoint) => {
|
|
1559
|
-
return {
|
|
1560
|
-
mode: wxtConfig.mode,
|
|
1561
|
-
plugins: [entrypointGroupGlobals(entrypoint)],
|
|
1562
|
-
build: {
|
|
1563
|
-
rollupOptions: {
|
|
1564
|
-
input: {
|
|
1565
|
-
[entrypoint.name]: entrypoint.inputPath
|
|
1566
|
-
},
|
|
1567
|
-
output: {
|
|
1568
|
-
assetFileNames: () => {
|
|
1569
|
-
if (entrypoint.type === "content-script-style") {
|
|
1570
|
-
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
1571
|
-
} else {
|
|
1572
|
-
return `assets/${entrypoint.name}.[ext]`;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
};
|
|
1579
|
-
};
|
|
1404
|
+
// src/core/utils/cache.ts
|
|
1405
|
+
import fs7, { ensureDir as ensureDir2 } from "fs-extra";
|
|
1406
|
+
import { dirname as dirname4, resolve as resolve8 } from "path";
|
|
1407
|
+
function createFsCache(wxtDir) {
|
|
1408
|
+
const getPath = (key) => resolve8(wxtDir, "cache", encodeURIComponent(key));
|
|
1580
1409
|
return {
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
if (Array.isArray(group))
|
|
1586
|
-
entryConfig = getMultiPageConfig(group);
|
|
1587
|
-
else if (group.inputPath.endsWith(".css"))
|
|
1588
|
-
entryConfig = getCssConfig(group);
|
|
1589
|
-
else
|
|
1590
|
-
entryConfig = getLibModeConfig(group);
|
|
1591
|
-
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
|
|
1592
|
-
const result = await vite.build(buildConfig);
|
|
1593
|
-
return {
|
|
1594
|
-
entrypoints: group,
|
|
1595
|
-
chunks: getBuildOutputChunks(result)
|
|
1596
|
-
};
|
|
1410
|
+
async set(key, value) {
|
|
1411
|
+
const path8 = getPath(key);
|
|
1412
|
+
await ensureDir2(dirname4(path8));
|
|
1413
|
+
await writeFileIfDifferent(path8, value);
|
|
1597
1414
|
},
|
|
1598
|
-
async
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
}
|
|
1606
|
-
};
|
|
1607
|
-
const baseConfig = await getBaseConfig();
|
|
1608
|
-
const viteServer = await vite.createServer(
|
|
1609
|
-
vite.mergeConfig(baseConfig, serverConfig)
|
|
1610
|
-
);
|
|
1611
|
-
const server = {
|
|
1612
|
-
async listen() {
|
|
1613
|
-
await viteServer.listen(info.port);
|
|
1614
|
-
},
|
|
1615
|
-
async close() {
|
|
1616
|
-
await viteServer.close();
|
|
1617
|
-
},
|
|
1618
|
-
transformHtml(...args) {
|
|
1619
|
-
return viteServer.transformIndexHtml(...args);
|
|
1620
|
-
},
|
|
1621
|
-
ws: {
|
|
1622
|
-
send(message, payload) {
|
|
1623
|
-
return viteServer.ws.send(message, payload);
|
|
1624
|
-
},
|
|
1625
|
-
on(message, cb) {
|
|
1626
|
-
viteServer.ws.on(message, cb);
|
|
1627
|
-
}
|
|
1628
|
-
},
|
|
1629
|
-
watcher: viteServer.watcher
|
|
1630
|
-
};
|
|
1631
|
-
return server;
|
|
1415
|
+
async get(key) {
|
|
1416
|
+
const path8 = getPath(key);
|
|
1417
|
+
try {
|
|
1418
|
+
return await fs7.readFile(path8, "utf-8");
|
|
1419
|
+
} catch {
|
|
1420
|
+
return void 0;
|
|
1421
|
+
}
|
|
1632
1422
|
}
|
|
1633
1423
|
};
|
|
1634
1424
|
}
|
|
1635
|
-
function getBuildOutputChunks(result) {
|
|
1636
|
-
if ("on" in result)
|
|
1637
|
-
throw Error("wxt does not support vite watch mode.");
|
|
1638
|
-
if (Array.isArray(result))
|
|
1639
|
-
return result.flatMap(({ output }) => output);
|
|
1640
|
-
return result.output;
|
|
1641
|
-
}
|
|
1642
|
-
function getRollupEntry(entrypoint) {
|
|
1643
|
-
let virtualEntrypointType;
|
|
1644
|
-
switch (entrypoint.type) {
|
|
1645
|
-
case "background":
|
|
1646
|
-
case "unlisted-script":
|
|
1647
|
-
virtualEntrypointType = entrypoint.type;
|
|
1648
|
-
break;
|
|
1649
|
-
case "content-script":
|
|
1650
|
-
virtualEntrypointType = entrypoint.options.world === "MAIN" ? "content-script-main-world" : "content-script-isolated-world";
|
|
1651
|
-
break;
|
|
1652
|
-
}
|
|
1653
|
-
return virtualEntrypointType ? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}` : entrypoint.inputPath;
|
|
1654
|
-
}
|
|
1655
1425
|
|
|
1656
1426
|
// src/core/utils/building/resolve-config.ts
|
|
1427
|
+
import consola, { LogLevels } from "consola";
|
|
1657
1428
|
import defu from "defu";
|
|
1658
1429
|
|
|
1659
1430
|
// src/core/utils/package.ts
|
|
@@ -1676,7 +1447,7 @@ function isModuleInstalled(name) {
|
|
|
1676
1447
|
|
|
1677
1448
|
// src/core/utils/building/resolve-config.ts
|
|
1678
1449
|
import fs9 from "fs-extra";
|
|
1679
|
-
async function resolveConfig(inlineConfig, command
|
|
1450
|
+
async function resolveConfig(inlineConfig, command) {
|
|
1680
1451
|
let userConfig = {};
|
|
1681
1452
|
let userConfigMetadata;
|
|
1682
1453
|
if (inlineConfig.configFile !== false) {
|
|
@@ -1692,14 +1463,14 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1692
1463
|
userConfig = loadedConfig ?? {};
|
|
1693
1464
|
userConfigMetadata = metadata;
|
|
1694
1465
|
}
|
|
1695
|
-
const mergedConfig = mergeInlineConfig(inlineConfig, userConfig);
|
|
1466
|
+
const mergedConfig = await mergeInlineConfig(inlineConfig, userConfig);
|
|
1696
1467
|
const debug = mergedConfig.debug ?? false;
|
|
1697
1468
|
const logger = mergedConfig.logger ?? consola;
|
|
1698
1469
|
if (debug)
|
|
1699
1470
|
logger.level = LogLevels.debug;
|
|
1700
1471
|
const browser = mergedConfig.browser ?? "chrome";
|
|
1701
1472
|
const manifestVersion = mergedConfig.manifestVersion ?? (browser === "firefox" || browser === "safari" ? 2 : 3);
|
|
1702
|
-
const mode = mergedConfig.mode ??
|
|
1473
|
+
const mode = mergedConfig.mode ?? COMMAND_MODES[command];
|
|
1703
1474
|
const env = { browser, command, manifestVersion, mode };
|
|
1704
1475
|
const root = path5.resolve(
|
|
1705
1476
|
inlineConfig.root ?? userConfig.root ?? process.cwd()
|
|
@@ -1738,15 +1509,21 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1738
1509
|
"~": srcDir,
|
|
1739
1510
|
"@@": root,
|
|
1740
1511
|
"~~": root
|
|
1741
|
-
}).map(([key, value]) => [key, path5.resolve(root, value)])
|
|
1742
|
-
);
|
|
1743
|
-
const analysisOutputFile = path5.resolve(
|
|
1744
|
-
root,
|
|
1745
|
-
mergedConfig.analysis?.outputFile ?? "stats.html"
|
|
1512
|
+
}).map(([key, value]) => [key, path5.resolve(root, value)])
|
|
1746
1513
|
);
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1514
|
+
let devServerConfig;
|
|
1515
|
+
if (command === "serve") {
|
|
1516
|
+
let port = mergedConfig.dev?.server?.port;
|
|
1517
|
+
if (port == null || !isFinite(port)) {
|
|
1518
|
+
const { default: getPort, portNumbers } = await import("get-port");
|
|
1519
|
+
port = await getPort({ port: portNumbers(3e3, 3010) });
|
|
1520
|
+
}
|
|
1521
|
+
devServerConfig = {
|
|
1522
|
+
port,
|
|
1523
|
+
hostname: "localhost"
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
return {
|
|
1750
1527
|
browser,
|
|
1751
1528
|
command,
|
|
1752
1529
|
debug,
|
|
@@ -1768,109 +1545,47 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1768
1545
|
srcDir,
|
|
1769
1546
|
typesDir,
|
|
1770
1547
|
wxtDir,
|
|
1771
|
-
zip:
|
|
1772
|
-
transformManifest
|
|
1773
|
-
|
|
1774
|
-
inlineConfig.transformManifest?.(manifest);
|
|
1775
|
-
},
|
|
1776
|
-
analysis: {
|
|
1777
|
-
enabled: mergedConfig.analysis?.enabled ?? false,
|
|
1778
|
-
open: mergedConfig.analysis?.open ?? false,
|
|
1779
|
-
template: mergedConfig.analysis?.template ?? "treemap",
|
|
1780
|
-
outputFile: analysisOutputFile,
|
|
1781
|
-
outputDir: analysisOutputDir,
|
|
1782
|
-
outputName: analysisOutputName,
|
|
1783
|
-
keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false
|
|
1784
|
-
},
|
|
1548
|
+
zip: resolveZipConfig(root, mergedConfig),
|
|
1549
|
+
transformManifest: mergedConfig.transformManifest,
|
|
1550
|
+
analysis: resolveAnalysisConfig(root, mergedConfig),
|
|
1785
1551
|
userConfigMetadata: userConfigMetadata ?? {},
|
|
1786
1552
|
alias,
|
|
1787
|
-
experimental: {
|
|
1788
|
-
includeBrowserPolyfill:
|
|
1789
|
-
},
|
|
1790
|
-
server,
|
|
1553
|
+
experimental: defu(mergedConfig.experimental, {
|
|
1554
|
+
includeBrowserPolyfill: true
|
|
1555
|
+
}),
|
|
1791
1556
|
dev: {
|
|
1557
|
+
server: devServerConfig,
|
|
1792
1558
|
reloadCommand
|
|
1793
1559
|
},
|
|
1794
|
-
hooks: mergedConfig.hooks ?? {}
|
|
1795
|
-
|
|
1796
|
-
const builder = await createViteBuilder(
|
|
1797
|
-
inlineConfig,
|
|
1798
|
-
userConfig,
|
|
1799
|
-
finalConfig
|
|
1800
|
-
);
|
|
1801
|
-
return {
|
|
1802
|
-
...finalConfig,
|
|
1803
|
-
builder
|
|
1560
|
+
hooks: mergedConfig.hooks ?? {},
|
|
1561
|
+
vite: mergedConfig.vite ?? (() => ({}))
|
|
1804
1562
|
};
|
|
1805
1563
|
}
|
|
1806
1564
|
async function resolveManifestConfig(env, manifest) {
|
|
1807
1565
|
return await (typeof manifest === "function" ? manifest(env) : manifest ?? {});
|
|
1808
1566
|
}
|
|
1809
|
-
function mergeInlineConfig(inlineConfig, userConfig) {
|
|
1810
|
-
|
|
1811
|
-
if (inlineConfig.imports === false || userConfig.imports === false) {
|
|
1812
|
-
imports = false;
|
|
1813
|
-
} else if (userConfig.imports == null && inlineConfig.imports == null) {
|
|
1814
|
-
imports = void 0;
|
|
1815
|
-
} else {
|
|
1816
|
-
imports = defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
|
1817
|
-
}
|
|
1567
|
+
async function mergeInlineConfig(inlineConfig, userConfig) {
|
|
1568
|
+
const imports = inlineConfig.imports === false || userConfig.imports === false ? false : userConfig.imports == null && inlineConfig.imports == null ? void 0 : defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
|
1818
1569
|
const manifest = async (env) => {
|
|
1819
1570
|
const user = await resolveManifestConfig(env, userConfig.manifest);
|
|
1820
1571
|
const inline = await resolveManifestConfig(env, inlineConfig.manifest);
|
|
1821
1572
|
return defu(inline, user);
|
|
1822
1573
|
};
|
|
1823
|
-
const
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
const
|
|
1828
|
-
inlineConfig.zip ?? {},
|
|
1829
|
-
userConfig.zip ?? {}
|
|
1830
|
-
);
|
|
1831
|
-
const hooks = defu(
|
|
1832
|
-
inlineConfig.hooks ?? {},
|
|
1833
|
-
userConfig.hooks ?? {}
|
|
1834
|
-
);
|
|
1574
|
+
const transformManifest = (manifest2) => {
|
|
1575
|
+
userConfig.transformManifest?.(manifest2);
|
|
1576
|
+
inlineConfig.transformManifest?.(manifest2);
|
|
1577
|
+
};
|
|
1578
|
+
const builderConfig = await mergeBuilderConfig(inlineConfig, userConfig);
|
|
1835
1579
|
return {
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
configFile: inlineConfig.configFile,
|
|
1840
|
-
debug: inlineConfig.debug ?? userConfig.debug,
|
|
1841
|
-
entrypointsDir: inlineConfig.entrypointsDir ?? userConfig.entrypointsDir,
|
|
1842
|
-
filterEntrypoints: inlineConfig.filterEntrypoints ?? userConfig.filterEntrypoints,
|
|
1580
|
+
...defu(inlineConfig, userConfig),
|
|
1581
|
+
// Custom merge values
|
|
1582
|
+
transformManifest,
|
|
1843
1583
|
imports,
|
|
1844
|
-
logger: inlineConfig.logger ?? userConfig.logger,
|
|
1845
1584
|
manifest,
|
|
1846
|
-
|
|
1847
|
-
publicDir: inlineConfig.publicDir ?? userConfig.publicDir,
|
|
1848
|
-
runner,
|
|
1849
|
-
srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
|
|
1850
|
-
outDir: inlineConfig.outDir ?? userConfig.outDir,
|
|
1851
|
-
zip,
|
|
1852
|
-
analysis: {
|
|
1853
|
-
...userConfig.analysis,
|
|
1854
|
-
...inlineConfig.analysis
|
|
1855
|
-
},
|
|
1856
|
-
alias: {
|
|
1857
|
-
...userConfig.alias,
|
|
1858
|
-
...inlineConfig.alias
|
|
1859
|
-
},
|
|
1860
|
-
experimental: {
|
|
1861
|
-
...userConfig.experimental,
|
|
1862
|
-
...inlineConfig.experimental
|
|
1863
|
-
},
|
|
1864
|
-
vite: void 0,
|
|
1865
|
-
transformManifest: void 0,
|
|
1866
|
-
dev: {
|
|
1867
|
-
...userConfig.dev,
|
|
1868
|
-
...inlineConfig.dev
|
|
1869
|
-
},
|
|
1870
|
-
hooks
|
|
1585
|
+
...builderConfig
|
|
1871
1586
|
};
|
|
1872
1587
|
}
|
|
1873
|
-
function
|
|
1588
|
+
function resolveZipConfig(root, mergedConfig) {
|
|
1874
1589
|
const downloadedPackagesDir = path5.resolve(root, ".wxt/local_modules");
|
|
1875
1590
|
return {
|
|
1876
1591
|
name: void 0,
|
|
@@ -1895,6 +1610,23 @@ function resolveInternalZipConfig(root, mergedConfig) {
|
|
|
1895
1610
|
downloadedPackagesDir
|
|
1896
1611
|
};
|
|
1897
1612
|
}
|
|
1613
|
+
function resolveAnalysisConfig(root, mergedConfig) {
|
|
1614
|
+
const analysisOutputFile = path5.resolve(
|
|
1615
|
+
root,
|
|
1616
|
+
mergedConfig.analysis?.outputFile ?? "stats.html"
|
|
1617
|
+
);
|
|
1618
|
+
const analysisOutputDir = path5.dirname(analysisOutputFile);
|
|
1619
|
+
const analysisOutputName = path5.parse(analysisOutputFile).name;
|
|
1620
|
+
return {
|
|
1621
|
+
enabled: mergedConfig.analysis?.enabled ?? false,
|
|
1622
|
+
open: mergedConfig.analysis?.open ?? false,
|
|
1623
|
+
template: mergedConfig.analysis?.template ?? "treemap",
|
|
1624
|
+
outputFile: analysisOutputFile,
|
|
1625
|
+
outputDir: analysisOutputDir,
|
|
1626
|
+
outputName: analysisOutputName,
|
|
1627
|
+
keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1898
1630
|
async function getUnimportOptions(wxtDir, logger, config) {
|
|
1899
1631
|
if (config.imports === false)
|
|
1900
1632
|
return false;
|
|
@@ -1947,6 +1679,23 @@ function logMissingDir(logger, name, expected) {
|
|
|
1947
1679
|
)}`
|
|
1948
1680
|
);
|
|
1949
1681
|
}
|
|
1682
|
+
var COMMAND_MODES = {
|
|
1683
|
+
build: "production",
|
|
1684
|
+
serve: "development"
|
|
1685
|
+
};
|
|
1686
|
+
async function mergeBuilderConfig(inlineConfig, userConfig) {
|
|
1687
|
+
const vite = await import("vite").catch(() => void 0);
|
|
1688
|
+
if (vite) {
|
|
1689
|
+
return {
|
|
1690
|
+
vite: async (env) => {
|
|
1691
|
+
const resolvedInlineConfig = await inlineConfig.vite?.(env) ?? {};
|
|
1692
|
+
const resolvedUserConfig = await userConfig.vite?.(env) ?? {};
|
|
1693
|
+
return vite.mergeConfig(resolvedUserConfig, resolvedInlineConfig);
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
throw Error("Builder not found. Make sure vite is installed.");
|
|
1698
|
+
}
|
|
1950
1699
|
|
|
1951
1700
|
// src/core/utils/building/group-entrypoints.ts
|
|
1952
1701
|
function groupEntrypoints(entrypoints) {
|
|
@@ -2379,7 +2128,7 @@ async function generateManifest(entrypoints, buildOutput) {
|
|
|
2379
2128
|
addDevModeCsp(manifest);
|
|
2380
2129
|
if (wxt.config.command === "serve")
|
|
2381
2130
|
addDevModePermissions(manifest);
|
|
2382
|
-
wxt.config.transformManifest(manifest);
|
|
2131
|
+
wxt.config.transformManifest?.(manifest);
|
|
2383
2132
|
await wxt.hooks.callHook("build:manifestGenerated", wxt, manifest);
|
|
2384
2133
|
if (wxt.config.manifestVersion === 2) {
|
|
2385
2134
|
convertWebAccessibleResourcesToMv2(manifest);
|
|
@@ -2660,8 +2409,8 @@ function discoverIcons(buildOutput) {
|
|
|
2660
2409
|
return icons.length > 0 ? Object.fromEntries(icons) : void 0;
|
|
2661
2410
|
}
|
|
2662
2411
|
function addDevModeCsp(manifest) {
|
|
2663
|
-
const permission = `http://${wxt.
|
|
2664
|
-
const allowedCsp = wxt.
|
|
2412
|
+
const permission = `http://${wxt.server?.hostname ?? ""}/*`;
|
|
2413
|
+
const allowedCsp = wxt.server?.origin ?? "http://localhost:*";
|
|
2665
2414
|
if (manifest.manifest_version === 3) {
|
|
2666
2415
|
addHostPermission(manifest, permission);
|
|
2667
2416
|
} else {
|
|
@@ -2674,7 +2423,7 @@ function addDevModeCsp(manifest) {
|
|
|
2674
2423
|
) : manifest.content_security_policy ?? "script-src 'self'; object-src 'self';"
|
|
2675
2424
|
// default CSP for MV2
|
|
2676
2425
|
);
|
|
2677
|
-
if (wxt.
|
|
2426
|
+
if (wxt.server)
|
|
2678
2427
|
csp.add("script-src", allowedCsp);
|
|
2679
2428
|
if (manifest.manifest_version === 3) {
|
|
2680
2429
|
manifest.content_security_policy ??= {};
|
|
@@ -2934,7 +2683,7 @@ async function internalBuild() {
|
|
|
2934
2683
|
const target = `${wxt.config.browser}-mv${wxt.config.manifestVersion}`;
|
|
2935
2684
|
wxt.logger.info(
|
|
2936
2685
|
`${verb} ${pc5.cyan(target)} for ${pc5.cyan(wxt.config.mode)} with ${pc5.green(
|
|
2937
|
-
`${wxt.
|
|
2686
|
+
`${wxt.builder.name} ${wxt.builder.version}`
|
|
2938
2687
|
)}`
|
|
2939
2688
|
);
|
|
2940
2689
|
const startTime = Date.now();
|
|
@@ -3232,11 +2981,227 @@ var packageManagers = {
|
|
|
3232
2981
|
yarn
|
|
3233
2982
|
};
|
|
3234
2983
|
|
|
2984
|
+
// src/core/builders/vite/index.ts
|
|
2985
|
+
async function createViteBuilder(wxtConfig, server) {
|
|
2986
|
+
const vite = await import("vite");
|
|
2987
|
+
const getBaseConfig = async () => {
|
|
2988
|
+
const config = await wxtConfig.vite(wxtConfig.env);
|
|
2989
|
+
config.root = wxtConfig.root;
|
|
2990
|
+
config.configFile = false;
|
|
2991
|
+
config.logLevel = "warn";
|
|
2992
|
+
config.mode = wxtConfig.mode;
|
|
2993
|
+
config.build ??= {};
|
|
2994
|
+
config.build.outDir = wxtConfig.outDir;
|
|
2995
|
+
config.build.emptyOutDir = false;
|
|
2996
|
+
if (config.build.minify == null && wxtConfig.command === "serve") {
|
|
2997
|
+
config.build.minify = false;
|
|
2998
|
+
}
|
|
2999
|
+
if (config.build.sourcemap == null && wxtConfig.command === "serve") {
|
|
3000
|
+
config.build.sourcemap = "inline";
|
|
3001
|
+
}
|
|
3002
|
+
config.plugins ??= [];
|
|
3003
|
+
config.plugins.push(
|
|
3004
|
+
download(wxtConfig),
|
|
3005
|
+
devHtmlPrerender(wxtConfig, server),
|
|
3006
|
+
unimport(wxtConfig),
|
|
3007
|
+
virtualEntrypoint("background", wxtConfig),
|
|
3008
|
+
virtualEntrypoint("content-script-isolated-world", wxtConfig),
|
|
3009
|
+
virtualEntrypoint("content-script-main-world", wxtConfig),
|
|
3010
|
+
virtualEntrypoint("unlisted-script", wxtConfig),
|
|
3011
|
+
devServerGlobals(wxtConfig, server),
|
|
3012
|
+
tsconfigPaths(wxtConfig),
|
|
3013
|
+
noopBackground(),
|
|
3014
|
+
globals(wxtConfig),
|
|
3015
|
+
excludeBrowserPolyfill(wxtConfig),
|
|
3016
|
+
defineImportMeta()
|
|
3017
|
+
);
|
|
3018
|
+
if (wxtConfig.analysis.enabled) {
|
|
3019
|
+
config.plugins.push(bundleAnalysis(wxtConfig));
|
|
3020
|
+
}
|
|
3021
|
+
return config;
|
|
3022
|
+
};
|
|
3023
|
+
const getLibModeConfig = (entrypoint) => {
|
|
3024
|
+
const entry = getRollupEntry(entrypoint);
|
|
3025
|
+
const plugins = [
|
|
3026
|
+
entrypointGroupGlobals(entrypoint)
|
|
3027
|
+
];
|
|
3028
|
+
if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
|
|
3029
|
+
plugins.push(cssEntrypoints(entrypoint, wxtConfig));
|
|
3030
|
+
}
|
|
3031
|
+
const libMode = {
|
|
3032
|
+
mode: wxtConfig.mode,
|
|
3033
|
+
plugins,
|
|
3034
|
+
build: {
|
|
3035
|
+
lib: {
|
|
3036
|
+
entry,
|
|
3037
|
+
formats: ["iife"],
|
|
3038
|
+
name: "_",
|
|
3039
|
+
fileName: entrypoint.name
|
|
3040
|
+
},
|
|
3041
|
+
rollupOptions: {
|
|
3042
|
+
output: {
|
|
3043
|
+
// There's only a single output for this build, so we use the desired bundle path for the
|
|
3044
|
+
// entry output (like "content-scripts/overlay.js")
|
|
3045
|
+
entryFileNames: getEntrypointBundlePath(
|
|
3046
|
+
entrypoint,
|
|
3047
|
+
wxtConfig.outDir,
|
|
3048
|
+
".js"
|
|
3049
|
+
),
|
|
3050
|
+
// Output content script CSS to `content-scripts/`, but all other scripts are written to
|
|
3051
|
+
// `assets/`.
|
|
3052
|
+
assetFileNames: ({ name }) => {
|
|
3053
|
+
if (entrypoint.type === "content-script" && name?.endsWith("css")) {
|
|
3054
|
+
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
3055
|
+
} else {
|
|
3056
|
+
return `assets/${entrypoint.name}.[ext]`;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
},
|
|
3062
|
+
define: {
|
|
3063
|
+
// See https://github.com/aklinker1/vite-plugin-web-extension/issues/96
|
|
3064
|
+
"process.env.NODE_ENV": JSON.stringify(wxtConfig.mode)
|
|
3065
|
+
}
|
|
3066
|
+
};
|
|
3067
|
+
return libMode;
|
|
3068
|
+
};
|
|
3069
|
+
const getMultiPageConfig = (entrypoints) => {
|
|
3070
|
+
const htmlEntrypoints = new Set(
|
|
3071
|
+
entrypoints.filter(isHtmlEntrypoint).map((e) => e.name)
|
|
3072
|
+
);
|
|
3073
|
+
return {
|
|
3074
|
+
mode: wxtConfig.mode,
|
|
3075
|
+
plugins: [
|
|
3076
|
+
multipageMove(entrypoints, wxtConfig),
|
|
3077
|
+
entrypointGroupGlobals(entrypoints)
|
|
3078
|
+
],
|
|
3079
|
+
build: {
|
|
3080
|
+
rollupOptions: {
|
|
3081
|
+
input: entrypoints.reduce((input, entry) => {
|
|
3082
|
+
input[entry.name] = getRollupEntry(entry);
|
|
3083
|
+
return input;
|
|
3084
|
+
}, {}),
|
|
3085
|
+
output: {
|
|
3086
|
+
// Include a hash to prevent conflicts
|
|
3087
|
+
chunkFileNames: "chunks/[name]-[hash].js",
|
|
3088
|
+
entryFileNames: ({ name }) => {
|
|
3089
|
+
if (htmlEntrypoints.has(name))
|
|
3090
|
+
return "chunks/[name]-[hash].js";
|
|
3091
|
+
return "[name].js";
|
|
3092
|
+
},
|
|
3093
|
+
// We can't control the "name", so we need a hash to prevent conflicts
|
|
3094
|
+
assetFileNames: "assets/[name]-[hash].[ext]"
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
};
|
|
3099
|
+
};
|
|
3100
|
+
const getCssConfig = (entrypoint) => {
|
|
3101
|
+
return {
|
|
3102
|
+
mode: wxtConfig.mode,
|
|
3103
|
+
plugins: [entrypointGroupGlobals(entrypoint)],
|
|
3104
|
+
build: {
|
|
3105
|
+
rollupOptions: {
|
|
3106
|
+
input: {
|
|
3107
|
+
[entrypoint.name]: entrypoint.inputPath
|
|
3108
|
+
},
|
|
3109
|
+
output: {
|
|
3110
|
+
assetFileNames: () => {
|
|
3111
|
+
if (entrypoint.type === "content-script-style") {
|
|
3112
|
+
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
3113
|
+
} else {
|
|
3114
|
+
return `assets/${entrypoint.name}.[ext]`;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
3121
|
+
};
|
|
3122
|
+
return {
|
|
3123
|
+
name: "Vite",
|
|
3124
|
+
version: vite.version,
|
|
3125
|
+
async build(group) {
|
|
3126
|
+
let entryConfig;
|
|
3127
|
+
if (Array.isArray(group))
|
|
3128
|
+
entryConfig = getMultiPageConfig(group);
|
|
3129
|
+
else if (group.inputPath.endsWith(".css"))
|
|
3130
|
+
entryConfig = getCssConfig(group);
|
|
3131
|
+
else
|
|
3132
|
+
entryConfig = getLibModeConfig(group);
|
|
3133
|
+
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
|
|
3134
|
+
const result = await vite.build(buildConfig);
|
|
3135
|
+
return {
|
|
3136
|
+
entrypoints: group,
|
|
3137
|
+
chunks: getBuildOutputChunks(result)
|
|
3138
|
+
};
|
|
3139
|
+
},
|
|
3140
|
+
async createServer(info) {
|
|
3141
|
+
const serverConfig = {
|
|
3142
|
+
server: {
|
|
3143
|
+
port: info.port,
|
|
3144
|
+
strictPort: true,
|
|
3145
|
+
host: info.hostname,
|
|
3146
|
+
origin: info.origin
|
|
3147
|
+
}
|
|
3148
|
+
};
|
|
3149
|
+
const baseConfig = await getBaseConfig();
|
|
3150
|
+
const viteServer = await vite.createServer(
|
|
3151
|
+
vite.mergeConfig(baseConfig, serverConfig)
|
|
3152
|
+
);
|
|
3153
|
+
const server2 = {
|
|
3154
|
+
async listen() {
|
|
3155
|
+
await viteServer.listen(info.port);
|
|
3156
|
+
},
|
|
3157
|
+
async close() {
|
|
3158
|
+
await viteServer.close();
|
|
3159
|
+
},
|
|
3160
|
+
transformHtml(...args) {
|
|
3161
|
+
return viteServer.transformIndexHtml(...args);
|
|
3162
|
+
},
|
|
3163
|
+
ws: {
|
|
3164
|
+
send(message, payload) {
|
|
3165
|
+
return viteServer.ws.send(message, payload);
|
|
3166
|
+
},
|
|
3167
|
+
on(message, cb) {
|
|
3168
|
+
viteServer.ws.on(message, cb);
|
|
3169
|
+
}
|
|
3170
|
+
},
|
|
3171
|
+
watcher: viteServer.watcher
|
|
3172
|
+
};
|
|
3173
|
+
return server2;
|
|
3174
|
+
}
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
function getBuildOutputChunks(result) {
|
|
3178
|
+
if ("on" in result)
|
|
3179
|
+
throw Error("wxt does not support vite watch mode.");
|
|
3180
|
+
if (Array.isArray(result))
|
|
3181
|
+
return result.flatMap(({ output }) => output);
|
|
3182
|
+
return result.output;
|
|
3183
|
+
}
|
|
3184
|
+
function getRollupEntry(entrypoint) {
|
|
3185
|
+
let virtualEntrypointType;
|
|
3186
|
+
switch (entrypoint.type) {
|
|
3187
|
+
case "background":
|
|
3188
|
+
case "unlisted-script":
|
|
3189
|
+
virtualEntrypointType = entrypoint.type;
|
|
3190
|
+
break;
|
|
3191
|
+
case "content-script":
|
|
3192
|
+
virtualEntrypointType = entrypoint.options.world === "MAIN" ? "content-script-main-world" : "content-script-isolated-world";
|
|
3193
|
+
break;
|
|
3194
|
+
}
|
|
3195
|
+
return virtualEntrypointType ? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}` : entrypoint.inputPath;
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3235
3198
|
// src/core/wxt.ts
|
|
3236
3199
|
var wxt;
|
|
3237
|
-
async function registerWxt(command, inlineConfig = {},
|
|
3238
|
-
const config = await resolveConfig(inlineConfig, command, server);
|
|
3200
|
+
async function registerWxt(command, inlineConfig = {}, getServer) {
|
|
3239
3201
|
const hooks = createHooks();
|
|
3202
|
+
const config = await resolveConfig(inlineConfig, command);
|
|
3203
|
+
const server = await getServer?.(config);
|
|
3204
|
+
const builder = await createViteBuilder(config, server);
|
|
3240
3205
|
const pm = await createWxtPackageManager(config.root);
|
|
3241
3206
|
wxt = {
|
|
3242
3207
|
config,
|
|
@@ -3245,9 +3210,11 @@ async function registerWxt(command, inlineConfig = {}, server) {
|
|
|
3245
3210
|
return config.logger;
|
|
3246
3211
|
},
|
|
3247
3212
|
async reloadConfig() {
|
|
3248
|
-
wxt.config = await resolveConfig(inlineConfig, command
|
|
3213
|
+
wxt.config = await resolveConfig(inlineConfig, command);
|
|
3249
3214
|
},
|
|
3250
|
-
pm
|
|
3215
|
+
pm,
|
|
3216
|
+
builder,
|
|
3217
|
+
server
|
|
3251
3218
|
};
|
|
3252
3219
|
wxt.hooks.addHooks(config.hooks);
|
|
3253
3220
|
await wxt.hooks.callHook("ready", wxt);
|
|
@@ -3256,19 +3223,19 @@ async function registerWxt(command, inlineConfig = {}, server) {
|
|
|
3256
3223
|
export {
|
|
3257
3224
|
normalizePath,
|
|
3258
3225
|
unnormalizePath,
|
|
3259
|
-
wxt,
|
|
3260
|
-
registerWxt,
|
|
3261
|
-
detectDevChanges,
|
|
3262
3226
|
getEntrypointBundlePath,
|
|
3263
3227
|
isHtmlEntrypoint,
|
|
3264
|
-
findEntrypoints,
|
|
3265
|
-
generateTypesDir,
|
|
3266
3228
|
formatDuration,
|
|
3267
3229
|
download,
|
|
3268
3230
|
unimport,
|
|
3269
3231
|
tsconfigPaths,
|
|
3270
3232
|
globals,
|
|
3271
3233
|
webextensionPolyfillMock,
|
|
3234
|
+
wxt,
|
|
3235
|
+
registerWxt,
|
|
3236
|
+
detectDevChanges,
|
|
3237
|
+
findEntrypoints,
|
|
3238
|
+
generateTypesDir,
|
|
3272
3239
|
getPackageJson,
|
|
3273
3240
|
resolveConfig,
|
|
3274
3241
|
kebabCaseAlphanumeric,
|