wxt 0.17.9 → 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-ONUEB57P.js → chunk-2SH4GQGN.js} +1535 -1529
- package/dist/cli.js +1535 -1525
- package/dist/{index-mZodC81T.d.cts → index-w7ohFTEX.d.cts} +24 -4
- package/dist/{index-mZodC81T.d.ts → index-w7ohFTEX.d.ts} +24 -4
- package/dist/index.cjs +1526 -1521
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +54 -57
- package/dist/testing.cjs +37 -614
- 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
|
-
config.wxtModuleDir,
|
|
916
|
-
"dist/virtual/reload-html.js"
|
|
917
|
-
);
|
|
918
|
-
const virtualReactRefreshId = "@wxt/virtual-react-refresh";
|
|
919
|
-
const resolvedVirtualReactRefreshId = "\0" + virtualReactRefreshId;
|
|
920
|
-
return [
|
|
921
|
-
{
|
|
922
|
-
apply: "build",
|
|
923
|
-
name: "wxt:dev-html-prerender",
|
|
924
|
-
config() {
|
|
925
|
-
return {
|
|
926
|
-
resolve: {
|
|
927
|
-
alias: {
|
|
928
|
-
[htmlReloadId]: resolvedHtmlReloadId
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
};
|
|
932
|
-
},
|
|
933
|
-
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
|
934
|
-
// before the paths are replaced with their bundled path
|
|
935
|
-
transform(code, id) {
|
|
936
|
-
const server = config.server;
|
|
937
|
-
if (config.command !== "serve" || server == null || !id.endsWith(".html"))
|
|
938
|
-
return;
|
|
939
|
-
const { document } = parseHTML2(code);
|
|
940
|
-
const _pointToDevServer = (querySelector, attr) => pointToDevServer(config, server, id, document, querySelector, attr);
|
|
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
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
];
|
|
1007
|
-
}
|
|
1008
|
-
function pointToDevServer(config, server, id, document, querySelector, attr) {
|
|
1009
|
-
document.querySelectorAll(querySelector).forEach((element) => {
|
|
1010
|
-
const src = element.getAttribute(attr);
|
|
1011
|
-
if (!src || isUrl(src))
|
|
1012
|
-
return;
|
|
1013
|
-
let resolvedAbsolutePath;
|
|
1014
|
-
const matchingAlias = Object.entries(config.alias).find(
|
|
1015
|
-
([key]) => src.startsWith(key)
|
|
1016
|
-
);
|
|
1017
|
-
if (matchingAlias) {
|
|
1018
|
-
const [alias, replacement] = matchingAlias;
|
|
1019
|
-
resolvedAbsolutePath = resolve6(
|
|
1020
|
-
config.root,
|
|
1021
|
-
src.replace(alias, replacement)
|
|
1022
|
-
);
|
|
1023
|
-
} else {
|
|
1024
|
-
resolvedAbsolutePath = resolve6(dirname3(id), src);
|
|
1025
|
-
}
|
|
1026
|
-
if (resolvedAbsolutePath) {
|
|
1027
|
-
const relativePath = normalizePath(
|
|
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
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
});
|
|
1041
|
-
}
|
|
1042
|
-
function isUrl(str) {
|
|
1043
|
-
try {
|
|
1044
|
-
new URL(str);
|
|
1045
|
-
return true;
|
|
1046
|
-
} catch {
|
|
1047
|
-
return false;
|
|
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);
|
|
1048
642
|
}
|
|
1049
643
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
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
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
};
|
|
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);
|
|
1067
649
|
}
|
|
1068
650
|
|
|
1069
|
-
// src/core/utils/
|
|
1070
|
-
import
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
function
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
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 });
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
const publicAssets = await copyPublicDirectory();
|
|
671
|
+
return { publicAssets, steps };
|
|
1081
672
|
}
|
|
1082
|
-
function
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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;
|
|
1089
689
|
}
|
|
1090
690
|
|
|
1091
|
-
// src/core/utils/
|
|
1092
|
-
function
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
} else {
|
|
1098
|
-
res(true);
|
|
1099
|
-
}
|
|
1100
|
-
});
|
|
1101
|
-
});
|
|
1102
|
-
return withTimeout(isOffline2, 1e3).catch(() => true);
|
|
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;
|
|
1103
697
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
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;
|
|
1107
703
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
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);
|
|
1115
739
|
} else {
|
|
1116
|
-
|
|
1117
|
-
`Failed to download "${url}", falling back to cache...`
|
|
1118
|
-
);
|
|
740
|
+
unchangedOutput.steps.push(step);
|
|
1119
741
|
}
|
|
1120
742
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
);
|
|
1127
|
-
return content;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
// src/core/builders/vite/plugins/download.ts
|
|
1131
|
-
function download(config) {
|
|
1132
|
-
return {
|
|
1133
|
-
name: "wxt:download",
|
|
1134
|
-
resolveId(id) {
|
|
1135
|
-
if (id.startsWith("url:"))
|
|
1136
|
-
return "\0" + id;
|
|
1137
|
-
},
|
|
1138
|
-
async load(id) {
|
|
1139
|
-
if (!id.startsWith("\0url:"))
|
|
1140
|
-
return;
|
|
1141
|
-
const url = id.replace("\0url:", "");
|
|
1142
|
-
return await fetchCached(url, config);
|
|
1143
|
-
}
|
|
1144
|
-
};
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
// src/core/builders/vite/plugins/multipageMove.ts
|
|
1148
|
-
import { dirname as dirname4, extname, resolve as resolve7, join } from "node:path";
|
|
1149
|
-
import fs6, { ensureDir as ensureDir2 } from "fs-extra";
|
|
1150
|
-
function multipageMove(entrypoints, config) {
|
|
1151
|
-
return {
|
|
1152
|
-
name: "wxt:multipage-move",
|
|
1153
|
-
async writeBundle(_, bundle) {
|
|
1154
|
-
for (const oldBundlePath in bundle) {
|
|
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);
|
|
1188
|
-
}
|
|
1189
|
-
};
|
|
1190
|
-
}
|
|
1191
|
-
async function removeEmptyDirs(dir) {
|
|
1192
|
-
const files = await fs6.readdir(dir);
|
|
1193
|
-
for (const file of files) {
|
|
1194
|
-
const filePath = join(dir, file);
|
|
1195
|
-
const stats = await fs6.stat(filePath);
|
|
1196
|
-
if (stats.isDirectory()) {
|
|
1197
|
-
await removeEmptyDirs(filePath);
|
|
743
|
+
for (const asset of currentOutput.publicAssets) {
|
|
744
|
+
if (changedSteps.has(asset)) {
|
|
745
|
+
changedOutput.publicAssets.push(asset);
|
|
746
|
+
} else {
|
|
747
|
+
unchangedOutput.publicAssets.push(asset);
|
|
1198
748
|
}
|
|
1199
749
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
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
|
+
};
|
|
1203
769
|
}
|
|
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
|
-
return {
|
|
1223
|
-
name: "wxt:unimport",
|
|
1224
|
-
async config() {
|
|
1225
|
-
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
1226
|
-
},
|
|
1227
|
-
async transform(code, id) {
|
|
1228
|
-
if (id.includes("node_modules"))
|
|
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
|
-
}
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
// src/core/builders/vite/plugins/virtualEntrypoint.ts
|
|
1242
|
-
import fs7 from "fs-extra";
|
|
1243
|
-
import { resolve as resolve8 } from "path";
|
|
1244
|
-
function virtualEntrypoint(type, config) {
|
|
1245
|
-
const virtualId = `virtual:wxt-${type}?`;
|
|
1246
|
-
const resolvedVirtualId = `\0${virtualId}`;
|
|
1247
|
-
return {
|
|
1248
|
-
name: `wxt:virtual-entrypoint`,
|
|
1249
|
-
resolveId(id) {
|
|
1250
|
-
const index = id.indexOf(virtualId);
|
|
1251
|
-
if (index === -1)
|
|
1252
|
-
return;
|
|
1253
|
-
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
|
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
|
-
}
|
|
1266
|
-
};
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
// src/core/builders/vite/plugins/tsconfigPaths.ts
|
|
1270
|
-
function tsconfigPaths(config) {
|
|
1271
770
|
return {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
resolve: {
|
|
1276
|
-
alias: config.alias
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1279
|
-
}
|
|
771
|
+
type: "extension-reload",
|
|
772
|
+
cachedOutput: unchangedOutput,
|
|
773
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
1280
774
|
};
|
|
1281
775
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
const
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
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;
|
|
1300
797
|
}
|
|
1301
798
|
|
|
1302
|
-
// src/core/
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
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)
|
|
1321
826
|
});
|
|
1322
827
|
}
|
|
1323
|
-
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
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
|
+
};
|
|
1348
872
|
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
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
|
+
})
|
|
883
|
+
);
|
|
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.`
|
|
898
|
+
);
|
|
899
|
+
return false;
|
|
1352
900
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
// src/core/builders/vite/plugins/webextensionPolyfillMock.ts
|
|
1357
|
-
import path4 from "node:path";
|
|
1358
|
-
function webextensionPolyfillMock(config) {
|
|
1359
|
-
return {
|
|
1360
|
-
name: "wxt:testing-inline-deps",
|
|
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
|
-
};
|
|
901
|
+
if (exclude?.length && !include?.length) {
|
|
902
|
+
return !exclude.includes(wxt.config.browser);
|
|
1377
903
|
}
|
|
1378
|
-
|
|
904
|
+
if (include?.length && !exclude?.length) {
|
|
905
|
+
return include.includes(wxt.config.browser);
|
|
906
|
+
}
|
|
907
|
+
if (skippedEntrypointNames.includes(entry.name)) {
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
return true;
|
|
911
|
+
});
|
|
912
|
+
wxt.logger.debug(`${wxt.config.browser} entrypoints:`, targetEntrypoints);
|
|
913
|
+
await wxt.hooks.callHook("entrypoints:resolved", wxt, targetEntrypoints);
|
|
914
|
+
return targetEntrypoints;
|
|
1379
915
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
config() {
|
|
1387
|
-
if (config.experimental.includeBrowserPolyfill)
|
|
1388
|
-
return;
|
|
1389
|
-
return {
|
|
1390
|
-
resolve: {
|
|
1391
|
-
alias: {
|
|
1392
|
-
"webextension-polyfill": virtualId
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
};
|
|
916
|
+
function preventDuplicateEntrypointNames(files) {
|
|
917
|
+
const namesToPaths = files.reduce(
|
|
918
|
+
(map, { name, inputPath }) => {
|
|
919
|
+
map[name] ??= [];
|
|
920
|
+
map[name].push(inputPath);
|
|
921
|
+
return map;
|
|
1396
922
|
},
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
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
|
+
});
|
|
1400
932
|
}
|
|
933
|
+
return lines;
|
|
934
|
+
},
|
|
935
|
+
[]
|
|
936
|
+
);
|
|
937
|
+
if (errorLines.length > 0) {
|
|
938
|
+
const errorContent = errorLines.join("\n");
|
|
939
|
+
throw Error(
|
|
940
|
+
`Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.
|
|
941
|
+
|
|
942
|
+
${errorContent}`
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
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"
|
|
961
|
+
},
|
|
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"
|
|
1401
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
|
|
1402
977
|
};
|
|
1403
978
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
define[`import.meta.env.${global.name}`] = JSON.stringify(global.value);
|
|
1414
|
-
}
|
|
1415
|
-
return {
|
|
1416
|
-
define
|
|
1417
|
-
};
|
|
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"
|
|
1418
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
|
|
1419
997
|
};
|
|
1420
998
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
999
|
+
async function getUnlistedPageEntrypoint(info) {
|
|
1000
|
+
const options = await getHtmlEntrypointOptions(info, {
|
|
1001
|
+
exclude: "exclude",
|
|
1002
|
+
include: "include"
|
|
1003
|
+
});
|
|
1424
1004
|
return {
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
}
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1005
|
+
type: "unlisted-page",
|
|
1006
|
+
name: info.name,
|
|
1007
|
+
inputPath: info.inputPath,
|
|
1008
|
+
outputDir: wxt.config.outDir,
|
|
1009
|
+
options,
|
|
1010
|
+
skipped: info.skipped
|
|
1434
1011
|
};
|
|
1435
1012
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
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()
|
|
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(...)"?`
|
|
1475
1022
|
);
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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
|
|
1480
1032
|
};
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1033
|
+
}
|
|
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
|
+
);
|
|
1488
1046
|
}
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
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;
|
|
1047
|
+
const { main: _, ...moduleOptions } = defaultExport;
|
|
1048
|
+
options = moduleOptions;
|
|
1049
|
+
}
|
|
1050
|
+
if (wxt.config.manifestVersion !== 3) {
|
|
1051
|
+
delete options.type;
|
|
1052
|
+
}
|
|
1053
|
+
return {
|
|
1054
|
+
type: "background",
|
|
1055
|
+
name,
|
|
1056
|
+
inputPath,
|
|
1057
|
+
outputDir: wxt.config.outDir,
|
|
1058
|
+
options: resolvePerBrowserOptions(options, wxt.config.browser),
|
|
1059
|
+
skipped
|
|
1526
1060
|
};
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1061
|
+
}
|
|
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(...)"?`
|
|
1530
1071
|
);
|
|
1531
|
-
|
|
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
|
-
};
|
|
1072
|
+
}
|
|
1580
1073
|
return {
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
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
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
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"
|
|
1597
1092
|
},
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1093
|
+
{
|
|
1094
|
+
defaultTitle: (document) => document.querySelector("title")?.textContent || void 0
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
defaultTitle: (content) => content
|
|
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
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
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
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
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
|
+
}));
|
|
1212
|
+
}
|
|
1213
|
+
|
|
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);
|
|
1223
|
+
}
|
|
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);
|
|
1230
|
+
}
|
|
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;
|
|
1247
|
+
});
|
|
1248
|
+
await fs6.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
|
|
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";
|
|
1261
|
+
|
|
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
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
`;
|
|
1272
|
+
await writeFileIfDifferent(
|
|
1273
|
+
filePath,
|
|
1274
|
+
template.replace("{{ union }}", unions || " | never")
|
|
1275
|
+
);
|
|
1276
|
+
return filePath;
|
|
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";
|
|
1283
|
+
|
|
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
|
+
}
|
|
1294
|
+
|
|
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}
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1391
|
+
"include": [
|
|
1392
|
+
"${getTsconfigPath(wxt.config.root)}/**/*",
|
|
1393
|
+
"./${getTsconfigPath(mainReference)}"
|
|
1394
|
+
],
|
|
1395
|
+
"exclude": ["${getTsconfigPath(wxt.config.outBaseDir)}"]
|
|
1396
|
+
}`
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// src/core/utils/building/resolve-config.ts
|
|
1401
|
+
import { loadConfig } from "c12";
|
|
1402
|
+
import path5 from "node:path";
|
|
1403
|
+
|
|
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));
|
|
1409
|
+
return {
|
|
1410
|
+
async set(key, value) {
|
|
1411
|
+
const path8 = getPath(key);
|
|
1412
|
+
await ensureDir2(dirname4(path8));
|
|
1413
|
+
await writeFileIfDifferent(path8, value);
|
|
1414
|
+
},
|
|
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,7 +1463,7 @@ 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)
|
|
@@ -1740,7 +1511,19 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1740
1511
|
"~~": root
|
|
1741
1512
|
}).map(([key, value]) => [key, path5.resolve(root, value)])
|
|
1742
1513
|
);
|
|
1743
|
-
|
|
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 {
|
|
1744
1527
|
browser,
|
|
1745
1528
|
command,
|
|
1746
1529
|
debug,
|
|
@@ -1770,26 +1553,18 @@ async function resolveConfig(inlineConfig, command, server) {
|
|
|
1770
1553
|
experimental: defu(mergedConfig.experimental, {
|
|
1771
1554
|
includeBrowserPolyfill: true
|
|
1772
1555
|
}),
|
|
1773
|
-
server,
|
|
1774
1556
|
dev: {
|
|
1557
|
+
server: devServerConfig,
|
|
1775
1558
|
reloadCommand
|
|
1776
1559
|
},
|
|
1777
|
-
hooks: mergedConfig.hooks ?? {}
|
|
1778
|
-
|
|
1779
|
-
const builder = await createViteBuilder(
|
|
1780
|
-
inlineConfig,
|
|
1781
|
-
userConfig,
|
|
1782
|
-
finalConfig
|
|
1783
|
-
);
|
|
1784
|
-
return {
|
|
1785
|
-
...finalConfig,
|
|
1786
|
-
builder
|
|
1560
|
+
hooks: mergedConfig.hooks ?? {},
|
|
1561
|
+
vite: mergedConfig.vite ?? (() => ({}))
|
|
1787
1562
|
};
|
|
1788
1563
|
}
|
|
1789
1564
|
async function resolveManifestConfig(env, manifest) {
|
|
1790
1565
|
return await (typeof manifest === "function" ? manifest(env) : manifest ?? {});
|
|
1791
1566
|
}
|
|
1792
|
-
function mergeInlineConfig(inlineConfig, userConfig) {
|
|
1567
|
+
async function mergeInlineConfig(inlineConfig, userConfig) {
|
|
1793
1568
|
const imports = inlineConfig.imports === false || userConfig.imports === false ? false : userConfig.imports == null && inlineConfig.imports == null ? void 0 : defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
|
1794
1569
|
const manifest = async (env) => {
|
|
1795
1570
|
const user = await resolveManifestConfig(env, userConfig.manifest);
|
|
@@ -1800,14 +1575,14 @@ function mergeInlineConfig(inlineConfig, userConfig) {
|
|
|
1800
1575
|
userConfig.transformManifest?.(manifest2);
|
|
1801
1576
|
inlineConfig.transformManifest?.(manifest2);
|
|
1802
1577
|
};
|
|
1578
|
+
const builderConfig = await mergeBuilderConfig(inlineConfig, userConfig);
|
|
1803
1579
|
return {
|
|
1804
1580
|
...defu(inlineConfig, userConfig),
|
|
1805
1581
|
// Custom merge values
|
|
1806
1582
|
transformManifest,
|
|
1807
1583
|
imports,
|
|
1808
1584
|
manifest,
|
|
1809
|
-
|
|
1810
|
-
vite: void 0
|
|
1585
|
+
...builderConfig
|
|
1811
1586
|
};
|
|
1812
1587
|
}
|
|
1813
1588
|
function resolveZipConfig(root, mergedConfig) {
|
|
@@ -1908,6 +1683,19 @@ var COMMAND_MODES = {
|
|
|
1908
1683
|
build: "production",
|
|
1909
1684
|
serve: "development"
|
|
1910
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
|
+
}
|
|
1911
1699
|
|
|
1912
1700
|
// src/core/utils/building/group-entrypoints.ts
|
|
1913
1701
|
function groupEntrypoints(entrypoints) {
|
|
@@ -2621,8 +2409,8 @@ function discoverIcons(buildOutput) {
|
|
|
2621
2409
|
return icons.length > 0 ? Object.fromEntries(icons) : void 0;
|
|
2622
2410
|
}
|
|
2623
2411
|
function addDevModeCsp(manifest) {
|
|
2624
|
-
const permission = `http://${wxt.
|
|
2625
|
-
const allowedCsp = wxt.
|
|
2412
|
+
const permission = `http://${wxt.server?.hostname ?? ""}/*`;
|
|
2413
|
+
const allowedCsp = wxt.server?.origin ?? "http://localhost:*";
|
|
2626
2414
|
if (manifest.manifest_version === 3) {
|
|
2627
2415
|
addHostPermission(manifest, permission);
|
|
2628
2416
|
} else {
|
|
@@ -2635,7 +2423,7 @@ function addDevModeCsp(manifest) {
|
|
|
2635
2423
|
) : manifest.content_security_policy ?? "script-src 'self'; object-src 'self';"
|
|
2636
2424
|
// default CSP for MV2
|
|
2637
2425
|
);
|
|
2638
|
-
if (wxt.
|
|
2426
|
+
if (wxt.server)
|
|
2639
2427
|
csp.add("script-src", allowedCsp);
|
|
2640
2428
|
if (manifest.manifest_version === 3) {
|
|
2641
2429
|
manifest.content_security_policy ??= {};
|
|
@@ -2895,7 +2683,7 @@ async function internalBuild() {
|
|
|
2895
2683
|
const target = `${wxt.config.browser}-mv${wxt.config.manifestVersion}`;
|
|
2896
2684
|
wxt.logger.info(
|
|
2897
2685
|
`${verb} ${pc5.cyan(target)} for ${pc5.cyan(wxt.config.mode)} with ${pc5.green(
|
|
2898
|
-
`${wxt.
|
|
2686
|
+
`${wxt.builder.name} ${wxt.builder.version}`
|
|
2899
2687
|
)}`
|
|
2900
2688
|
);
|
|
2901
2689
|
const startTime = Date.now();
|
|
@@ -3193,11 +2981,227 @@ var packageManagers = {
|
|
|
3193
2981
|
yarn
|
|
3194
2982
|
};
|
|
3195
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
|
+
|
|
3196
3198
|
// src/core/wxt.ts
|
|
3197
3199
|
var wxt;
|
|
3198
|
-
async function registerWxt(command, inlineConfig = {},
|
|
3199
|
-
const config = await resolveConfig(inlineConfig, command, server);
|
|
3200
|
+
async function registerWxt(command, inlineConfig = {}, getServer) {
|
|
3200
3201
|
const hooks = createHooks();
|
|
3202
|
+
const config = await resolveConfig(inlineConfig, command);
|
|
3203
|
+
const server = await getServer?.(config);
|
|
3204
|
+
const builder = await createViteBuilder(config, server);
|
|
3201
3205
|
const pm = await createWxtPackageManager(config.root);
|
|
3202
3206
|
wxt = {
|
|
3203
3207
|
config,
|
|
@@ -3206,9 +3210,11 @@ async function registerWxt(command, inlineConfig = {}, server) {
|
|
|
3206
3210
|
return config.logger;
|
|
3207
3211
|
},
|
|
3208
3212
|
async reloadConfig() {
|
|
3209
|
-
wxt.config = await resolveConfig(inlineConfig, command
|
|
3213
|
+
wxt.config = await resolveConfig(inlineConfig, command);
|
|
3210
3214
|
},
|
|
3211
|
-
pm
|
|
3215
|
+
pm,
|
|
3216
|
+
builder,
|
|
3217
|
+
server
|
|
3212
3218
|
};
|
|
3213
3219
|
wxt.hooks.addHooks(config.hooks);
|
|
3214
3220
|
await wxt.hooks.callHook("ready", wxt);
|
|
@@ -3217,19 +3223,19 @@ async function registerWxt(command, inlineConfig = {}, server) {
|
|
|
3217
3223
|
export {
|
|
3218
3224
|
normalizePath,
|
|
3219
3225
|
unnormalizePath,
|
|
3220
|
-
wxt,
|
|
3221
|
-
registerWxt,
|
|
3222
|
-
detectDevChanges,
|
|
3223
3226
|
getEntrypointBundlePath,
|
|
3224
3227
|
isHtmlEntrypoint,
|
|
3225
|
-
findEntrypoints,
|
|
3226
|
-
generateTypesDir,
|
|
3227
3228
|
formatDuration,
|
|
3228
3229
|
download,
|
|
3229
3230
|
unimport,
|
|
3230
3231
|
tsconfigPaths,
|
|
3231
3232
|
globals,
|
|
3232
3233
|
webextensionPolyfillMock,
|
|
3234
|
+
wxt,
|
|
3235
|
+
registerWxt,
|
|
3236
|
+
detectDevChanges,
|
|
3237
|
+
findEntrypoints,
|
|
3238
|
+
generateTypesDir,
|
|
3233
3239
|
getPackageJson,
|
|
3234
3240
|
resolveConfig,
|
|
3235
3241
|
kebabCaseAlphanumeric,
|