wxt 0.10.3 → 0.11.0
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/browser.d.ts +1 -1
- package/dist/{chunk-BHUP6PAP.js → chunk-6V4H2CZ4.js} +952 -891
- package/dist/cli.cjs +1446 -1399
- package/dist/client.d.ts +2 -2
- package/dist/{execa-Z7B33P3C.js → execa-4F7CCWCA.js} +3 -3
- package/dist/{external-9107db91.d.ts → external-6YqvLCcd.d.ts} +1 -1
- package/dist/{external-d75ae6fd.d.ts → external-n9SucYhJ.d.cts} +113 -32
- package/dist/external-n9SucYhJ.d.ts +694 -0
- package/dist/index.cjs +1446 -1399
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +75 -91
- package/dist/sandbox.d.ts +1 -1
- package/dist/storage.d.cts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +1 -1
- package/dist/testing.cjs +377 -112
- package/dist/testing.d.cts +2 -1
- package/dist/testing.d.ts +2 -1
- package/dist/testing.js +2 -2
- package/dist/virtual/mock-browser.js +9 -14
- package/package.json +18 -17
- /package/dist/{chunk-YUG22S6W.js → chunk-VBXJIVYU.js} +0 -0
|
@@ -1,22 +1,112 @@
|
|
|
1
1
|
// package.json
|
|
2
|
-
var version = "0.
|
|
2
|
+
var version = "0.11.0";
|
|
3
3
|
|
|
4
|
-
// src/core/utils/
|
|
5
|
-
|
|
4
|
+
// src/core/utils/arrays.ts
|
|
5
|
+
function every(array, predicate) {
|
|
6
|
+
for (let i = 0; i < array.length; i++)
|
|
7
|
+
if (!predicate(array[i], i))
|
|
8
|
+
return false;
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
6
11
|
|
|
7
12
|
// src/core/utils/paths.ts
|
|
8
13
|
import systemPath from "node:path";
|
|
9
14
|
import normalize from "normalize-path";
|
|
10
|
-
function normalizePath(
|
|
11
|
-
return normalize(
|
|
15
|
+
function normalizePath(path6) {
|
|
16
|
+
return normalize(path6);
|
|
12
17
|
}
|
|
13
|
-
function unnormalizePath(
|
|
14
|
-
return systemPath.normalize(
|
|
18
|
+
function unnormalizePath(path6) {
|
|
19
|
+
return systemPath.normalize(path6);
|
|
15
20
|
}
|
|
16
21
|
var CSS_EXTENSIONS = ["css", "scss", "sass", "less", "styl", "stylus"];
|
|
17
22
|
var CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join("|")})`;
|
|
18
23
|
|
|
24
|
+
// src/core/utils/building/detect-dev-changes.ts
|
|
25
|
+
function detectDevChanges(changedFiles, currentOutput) {
|
|
26
|
+
if (currentOutput == null)
|
|
27
|
+
return { type: "no-change" };
|
|
28
|
+
const changedSteps = new Set(
|
|
29
|
+
changedFiles.flatMap(
|
|
30
|
+
(changedFile) => findEffectedSteps(changedFile, currentOutput)
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
if (changedSteps.size === 0)
|
|
34
|
+
return { type: "no-change" };
|
|
35
|
+
const unchangedOutput = {
|
|
36
|
+
manifest: currentOutput.manifest,
|
|
37
|
+
steps: [],
|
|
38
|
+
publicAssets: []
|
|
39
|
+
};
|
|
40
|
+
const changedOutput = {
|
|
41
|
+
manifest: currentOutput.manifest,
|
|
42
|
+
steps: [],
|
|
43
|
+
publicAssets: []
|
|
44
|
+
};
|
|
45
|
+
for (const step of currentOutput.steps) {
|
|
46
|
+
if (changedSteps.has(step)) {
|
|
47
|
+
changedOutput.steps.push(step);
|
|
48
|
+
} else {
|
|
49
|
+
unchangedOutput.steps.push(step);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const asset of currentOutput.publicAssets) {
|
|
53
|
+
if (changedSteps.has(asset)) {
|
|
54
|
+
changedOutput.publicAssets.push(asset);
|
|
55
|
+
} else {
|
|
56
|
+
unchangedOutput.publicAssets.push(asset);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, ([_, file]) => file.endsWith(".html"));
|
|
60
|
+
if (isOnlyHtmlChanges) {
|
|
61
|
+
return {
|
|
62
|
+
type: "html-reload",
|
|
63
|
+
cachedOutput: unchangedOutput,
|
|
64
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
|
|
68
|
+
changedOutput.steps.flatMap((step) => step.entrypoints),
|
|
69
|
+
(entry) => entry.type === "content-script"
|
|
70
|
+
);
|
|
71
|
+
if (isOnlyContentScripts) {
|
|
72
|
+
return {
|
|
73
|
+
type: "content-script-reload",
|
|
74
|
+
cachedOutput: unchangedOutput,
|
|
75
|
+
changedSteps: changedOutput.steps,
|
|
76
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
type: "extension-reload",
|
|
81
|
+
cachedOutput: unchangedOutput,
|
|
82
|
+
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function findEffectedSteps(changedFile, currentOutput) {
|
|
86
|
+
const changes = [];
|
|
87
|
+
const changedPath = normalizePath(changedFile[1]);
|
|
88
|
+
const isChunkEffected = (chunk) => (
|
|
89
|
+
// If it's an HTML file with the same path, is is effected because HTML files need to be pre-rendered
|
|
90
|
+
// fileName is normalized, relative bundle path
|
|
91
|
+
chunk.type === "asset" && changedPath.endsWith(chunk.fileName) || // If it's a chunk that depends on the changed file, it is effected
|
|
92
|
+
// moduleIds are absolute, normalized paths
|
|
93
|
+
chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
|
|
94
|
+
);
|
|
95
|
+
for (const step of currentOutput.steps) {
|
|
96
|
+
const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
|
|
97
|
+
if (effectedChunk)
|
|
98
|
+
changes.push(step);
|
|
99
|
+
}
|
|
100
|
+
const effectedAsset = currentOutput.publicAssets.find(
|
|
101
|
+
(chunk) => isChunkEffected(chunk)
|
|
102
|
+
);
|
|
103
|
+
if (effectedAsset)
|
|
104
|
+
changes.push(effectedAsset);
|
|
105
|
+
return changes;
|
|
106
|
+
}
|
|
107
|
+
|
|
19
108
|
// src/core/utils/entrypoints.ts
|
|
109
|
+
import path, { relative, resolve } from "node:path";
|
|
20
110
|
function getEntrypointName(entrypointsDir, inputPath) {
|
|
21
111
|
const relativePath = path.relative(entrypointsDir, inputPath);
|
|
22
112
|
const name = relativePath.split(/[\.\/\\]/, 2)[0];
|
|
@@ -36,87 +126,69 @@ function resolvePerBrowserOption(option, browser) {
|
|
|
36
126
|
return option;
|
|
37
127
|
}
|
|
38
128
|
|
|
39
|
-
// src/core/utils/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (duration < 6e4)
|
|
46
|
-
return `${(duration / 1e3).toFixed(1)} s`;
|
|
47
|
-
return `${(duration / 1e3).toFixed(0)} s`;
|
|
48
|
-
}
|
|
49
|
-
function withTimeout(promise, duration) {
|
|
50
|
-
return new Promise((res, rej) => {
|
|
51
|
-
const timeout = setTimeout(() => {
|
|
52
|
-
rej(`Promise timed out after ${duration}ms`);
|
|
53
|
-
}, duration);
|
|
54
|
-
promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
|
|
55
|
-
});
|
|
56
|
-
}
|
|
129
|
+
// src/core/utils/building/find-entrypoints.ts
|
|
130
|
+
import { relative as relative4, resolve as resolve12 } from "path";
|
|
131
|
+
import fs12 from "fs-extra";
|
|
132
|
+
import { minimatch } from "minimatch";
|
|
133
|
+
import { parseHTML as parseHTML2 } from "linkedom";
|
|
134
|
+
import JSON5 from "json5";
|
|
57
135
|
|
|
58
|
-
// src/core/utils/
|
|
59
|
-
import
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
res(true);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
return withTimeout(isOffline2, 1e3).catch(() => true);
|
|
136
|
+
// src/core/utils/fs.ts
|
|
137
|
+
import fs from "fs-extra";
|
|
138
|
+
import glob from "fast-glob";
|
|
139
|
+
async function writeFileIfDifferent(file, newContents) {
|
|
140
|
+
const existingContents = await fs.readFile(file, "utf-8").catch(() => void 0);
|
|
141
|
+
if (existingContents !== newContents) {
|
|
142
|
+
await fs.writeFile(file, newContents);
|
|
143
|
+
}
|
|
71
144
|
}
|
|
72
|
-
async function
|
|
73
|
-
|
|
74
|
-
|
|
145
|
+
async function getPublicFiles(config) {
|
|
146
|
+
if (!await fs.exists(config.publicDir))
|
|
147
|
+
return [];
|
|
148
|
+
const files = await glob("**/*", { cwd: config.publicDir });
|
|
149
|
+
return files.map(unnormalizePath);
|
|
75
150
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
151
|
+
|
|
152
|
+
// src/core/utils/building/build-entrypoints.ts
|
|
153
|
+
import fs2 from "fs-extra";
|
|
154
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
155
|
+
import pc from "picocolors";
|
|
156
|
+
async function buildEntrypoints(groups, config, spinner) {
|
|
157
|
+
const steps = [];
|
|
158
|
+
for (let i = 0; i < groups.length; i++) {
|
|
159
|
+
const group = groups[i];
|
|
160
|
+
const groupNames = [group].flat().map((e) => e.name).join(pc.dim(", "));
|
|
161
|
+
spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNames}`;
|
|
162
|
+
steps.push(await config.builder.build(group));
|
|
88
163
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (!content)
|
|
92
|
-
throw Error(
|
|
93
|
-
`Offline and "${url}" has not been cached. Try again when online.`
|
|
94
|
-
);
|
|
95
|
-
return content;
|
|
164
|
+
const publicAssets = await copyPublicDirectory(config);
|
|
165
|
+
return { publicAssets, steps };
|
|
96
166
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
167
|
+
async function copyPublicDirectory(config) {
|
|
168
|
+
const files = await getPublicFiles(config);
|
|
169
|
+
if (files.length === 0)
|
|
170
|
+
return [];
|
|
171
|
+
const publicAssets = [];
|
|
172
|
+
for (const file of files) {
|
|
173
|
+
const srcPath = resolve2(config.publicDir, file);
|
|
174
|
+
const outPath = resolve2(config.outDir, file);
|
|
175
|
+
await fs2.ensureDir(dirname(outPath));
|
|
176
|
+
await fs2.copyFile(srcPath, outPath);
|
|
177
|
+
publicAssets.push({
|
|
178
|
+
type: "asset",
|
|
179
|
+
fileName: file
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return publicAssets;
|
|
113
183
|
}
|
|
114
184
|
|
|
115
|
-
// src/core/
|
|
185
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
116
186
|
import { createUnimport } from "unimport";
|
|
187
|
+
import fs3 from "fs-extra";
|
|
188
|
+
import { relative as relative2, resolve as resolve3 } from "path";
|
|
117
189
|
|
|
118
190
|
// src/core/utils/unimport.ts
|
|
119
|
-
import {
|
|
191
|
+
import { defu } from "defu";
|
|
120
192
|
function getUnimportOptions(config) {
|
|
121
193
|
if (config.imports === false)
|
|
122
194
|
return false;
|
|
@@ -135,54 +207,7 @@ function getUnimportOptions(config) {
|
|
|
135
207
|
warn: config.logger.warn,
|
|
136
208
|
dirs: ["components", "composables", "hooks", "utils"]
|
|
137
209
|
};
|
|
138
|
-
return
|
|
139
|
-
defaultOptions,
|
|
140
|
-
config.imports
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// src/core/vite-plugins/unimport.ts
|
|
145
|
-
import { extname } from "path";
|
|
146
|
-
var ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
147
|
-
".js",
|
|
148
|
-
".jsx",
|
|
149
|
-
".ts",
|
|
150
|
-
".tsx",
|
|
151
|
-
".vue",
|
|
152
|
-
".svelte"
|
|
153
|
-
]);
|
|
154
|
-
function unimport(config) {
|
|
155
|
-
const options = getUnimportOptions(config);
|
|
156
|
-
if (options === false)
|
|
157
|
-
return [];
|
|
158
|
-
const unimport2 = createUnimport(options);
|
|
159
|
-
return {
|
|
160
|
-
name: "wxt:unimport",
|
|
161
|
-
async config() {
|
|
162
|
-
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
163
|
-
},
|
|
164
|
-
async transform(code, id) {
|
|
165
|
-
if (id.includes("node_modules"))
|
|
166
|
-
return;
|
|
167
|
-
if (!ENABLED_EXTENSIONS.has(extname(id)))
|
|
168
|
-
return;
|
|
169
|
-
return unimport2.injectImports(code, id);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/core/vite-plugins/tsconfigPaths.ts
|
|
175
|
-
function tsconfigPaths(config) {
|
|
176
|
-
return {
|
|
177
|
-
name: "wxt:aliases",
|
|
178
|
-
async config() {
|
|
179
|
-
return {
|
|
180
|
-
resolve: {
|
|
181
|
-
alias: config.alias
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
};
|
|
210
|
+
return defu(config.imports, defaultOptions);
|
|
186
211
|
}
|
|
187
212
|
|
|
188
213
|
// src/core/utils/globals.ts
|
|
@@ -230,7 +255,7 @@ function getGlobals(config) {
|
|
|
230
255
|
}
|
|
231
256
|
];
|
|
232
257
|
}
|
|
233
|
-
function getEntrypointGlobals(
|
|
258
|
+
function getEntrypointGlobals(entrypointName) {
|
|
234
259
|
return [
|
|
235
260
|
{
|
|
236
261
|
name: surroundInUnderscore("ENTRYPOINT"),
|
|
@@ -243,68 +268,253 @@ function surroundInUnderscore(name) {
|
|
|
243
268
|
return `__${name}__`;
|
|
244
269
|
}
|
|
245
270
|
|
|
246
|
-
// src/core/
|
|
247
|
-
function globals(config) {
|
|
248
|
-
return {
|
|
249
|
-
name: "wxt:globals",
|
|
250
|
-
config() {
|
|
251
|
-
const define = {};
|
|
252
|
-
for (const global of getGlobals(config)) {
|
|
253
|
-
define[global.name] = JSON.stringify(global.value);
|
|
254
|
-
}
|
|
255
|
-
return {
|
|
256
|
-
define
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// src/core/vite-plugins/webextensionPolyfillAlias.ts
|
|
271
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
263
272
|
import path2 from "node:path";
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
273
|
+
|
|
274
|
+
// src/core/utils/i18n.ts
|
|
275
|
+
var predefinedMessages = {
|
|
276
|
+
"@@extension_id": {
|
|
277
|
+
message: "<browser.runtime.id>",
|
|
278
|
+
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."
|
|
279
|
+
},
|
|
280
|
+
"@@ui_locale": {
|
|
281
|
+
message: "<browser.i18n.getUiLocale()>",
|
|
282
|
+
description: ""
|
|
283
|
+
},
|
|
284
|
+
"@@bidi_dir": {
|
|
285
|
+
message: "<ltr|rtl>",
|
|
286
|
+
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.'
|
|
287
|
+
},
|
|
288
|
+
"@@bidi_reversed_dir": {
|
|
289
|
+
message: "<rtl|ltr>",
|
|
290
|
+
description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
|
|
291
|
+
},
|
|
292
|
+
"@@bidi_start_edge": {
|
|
293
|
+
message: "<left|right>",
|
|
294
|
+
description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
|
|
295
|
+
},
|
|
296
|
+
"@@bidi_end_edge": {
|
|
297
|
+
message: "<right|left>",
|
|
298
|
+
description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
function parseI18nMessages(messagesJson) {
|
|
302
|
+
return Object.entries({
|
|
303
|
+
...predefinedMessages,
|
|
304
|
+
...messagesJson
|
|
305
|
+
}).map(([name, details]) => ({
|
|
306
|
+
name,
|
|
307
|
+
...details
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/core/utils/building/generate-wxt-dir.ts
|
|
312
|
+
async function generateTypesDir(entrypoints, config) {
|
|
313
|
+
await fs3.ensureDir(config.typesDir);
|
|
314
|
+
const references = [];
|
|
315
|
+
const imports = getUnimportOptions(config);
|
|
316
|
+
if (imports !== false) {
|
|
317
|
+
references.push(await writeImportsDeclarationFile(config, imports));
|
|
318
|
+
}
|
|
319
|
+
references.push(await writePathsDeclarationFile(entrypoints, config));
|
|
320
|
+
references.push(await writeI18nDeclarationFile(config));
|
|
321
|
+
references.push(await writeGlobalsDeclarationFile(config));
|
|
322
|
+
const mainReference = await writeMainDeclarationFile(references, config);
|
|
323
|
+
await writeTsConfigFile(mainReference, config);
|
|
324
|
+
}
|
|
325
|
+
async function writeImportsDeclarationFile(config, unimportOptions) {
|
|
326
|
+
const filePath = resolve3(config.typesDir, "imports.d.ts");
|
|
327
|
+
const unimport2 = createUnimport(unimportOptions);
|
|
328
|
+
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
329
|
+
await writeFileIfDifferent(
|
|
330
|
+
filePath,
|
|
331
|
+
["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
|
|
332
|
+
"\n"
|
|
333
|
+
) + "\n"
|
|
334
|
+
);
|
|
335
|
+
return filePath;
|
|
336
|
+
}
|
|
337
|
+
async function writePathsDeclarationFile(entrypoints, config) {
|
|
338
|
+
const filePath = resolve3(config.typesDir, "paths.d.ts");
|
|
339
|
+
const unions = entrypoints.map(
|
|
340
|
+
(entry) => getEntrypointBundlePath(
|
|
341
|
+
entry,
|
|
342
|
+
config.outDir,
|
|
343
|
+
entry.inputPath.endsWith(".html") ? ".html" : ".js"
|
|
344
|
+
)
|
|
345
|
+
).concat(await getPublicFiles(config)).map(normalizePath).map((path6) => ` | "/${path6}"`).sort().join("\n");
|
|
346
|
+
const template = `// Generated by wxt
|
|
347
|
+
import "wxt/browser";
|
|
348
|
+
|
|
349
|
+
declare module "wxt/browser" {
|
|
350
|
+
export type PublicPath =
|
|
351
|
+
{{ union }}
|
|
352
|
+
export interface WxtRuntime extends Runtime.Static {
|
|
353
|
+
getURL(path: PublicPath): string;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
`;
|
|
357
|
+
await writeFileIfDifferent(
|
|
358
|
+
filePath,
|
|
359
|
+
template.replace("{{ union }}", unions || " | never")
|
|
360
|
+
);
|
|
361
|
+
return filePath;
|
|
362
|
+
}
|
|
363
|
+
async function writeI18nDeclarationFile(config) {
|
|
364
|
+
const filePath = resolve3(config.typesDir, "i18n.d.ts");
|
|
365
|
+
const defaultLocale = config.manifest.default_locale;
|
|
366
|
+
const template = `// Generated by wxt
|
|
367
|
+
import "wxt/browser";
|
|
368
|
+
|
|
369
|
+
declare module "wxt/browser" {
|
|
370
|
+
/**
|
|
371
|
+
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
372
|
+
*/
|
|
373
|
+
interface GetMessageOptions {
|
|
374
|
+
/**
|
|
375
|
+
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
376
|
+
*/
|
|
377
|
+
escapeLt?: boolean
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export interface WxtI18n extends I18n.Static {
|
|
381
|
+
{{ overrides }}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
`;
|
|
385
|
+
let messages;
|
|
386
|
+
if (defaultLocale) {
|
|
387
|
+
const defaultLocalePath = path2.resolve(
|
|
388
|
+
config.publicDir,
|
|
389
|
+
"_locales",
|
|
390
|
+
defaultLocale,
|
|
391
|
+
"messages.json"
|
|
392
|
+
);
|
|
393
|
+
const content = JSON.parse(await fs3.readFile(defaultLocalePath, "utf-8"));
|
|
394
|
+
messages = parseI18nMessages(content);
|
|
395
|
+
} else {
|
|
396
|
+
messages = parseI18nMessages({});
|
|
397
|
+
}
|
|
398
|
+
const overrides = messages.map((message) => {
|
|
399
|
+
return ` /**
|
|
400
|
+
* ${message.description ?? "No message description."}
|
|
401
|
+
*
|
|
402
|
+
* "${message.message}"
|
|
403
|
+
*/
|
|
404
|
+
getMessage(
|
|
405
|
+
messageName: "${message.name}",
|
|
406
|
+
substitutions?: string | string[],
|
|
407
|
+
options?: GetMessageOptions,
|
|
408
|
+
): string;`;
|
|
409
|
+
});
|
|
410
|
+
await writeFileIfDifferent(
|
|
411
|
+
filePath,
|
|
412
|
+
template.replace("{{ overrides }}", overrides.join("\n"))
|
|
413
|
+
);
|
|
414
|
+
return filePath;
|
|
415
|
+
}
|
|
416
|
+
async function writeGlobalsDeclarationFile(config) {
|
|
417
|
+
const filePath = resolve3(config.typesDir, "globals.d.ts");
|
|
418
|
+
const globals2 = [...getGlobals(config), ...getEntrypointGlobals("")];
|
|
419
|
+
await writeFileIfDifferent(
|
|
420
|
+
filePath,
|
|
421
|
+
[
|
|
422
|
+
"// Generated by wxt",
|
|
423
|
+
"export {}",
|
|
424
|
+
"declare global {",
|
|
425
|
+
...globals2.map((global) => ` const ${global.name}: ${global.type};`),
|
|
426
|
+
"}"
|
|
427
|
+
].join("\n") + "\n"
|
|
428
|
+
);
|
|
429
|
+
return filePath;
|
|
430
|
+
}
|
|
431
|
+
async function writeMainDeclarationFile(references, config) {
|
|
432
|
+
const dir = config.wxtDir;
|
|
433
|
+
const filePath = resolve3(dir, "wxt.d.ts");
|
|
434
|
+
await writeFileIfDifferent(
|
|
435
|
+
filePath,
|
|
436
|
+
[
|
|
437
|
+
"// Generated by wxt",
|
|
438
|
+
`/// <reference types="vite/client" />`,
|
|
439
|
+
...references.map(
|
|
440
|
+
(ref) => `/// <reference types="./${normalizePath(relative2(dir, ref))}" />`
|
|
441
|
+
)
|
|
442
|
+
].join("\n") + "\n"
|
|
443
|
+
);
|
|
444
|
+
return filePath;
|
|
445
|
+
}
|
|
446
|
+
async function writeTsConfigFile(mainReference, config) {
|
|
447
|
+
const dir = config.wxtDir;
|
|
448
|
+
const getTsconfigPath = (path6) => normalizePath(relative2(dir, path6));
|
|
449
|
+
const paths = Object.entries(config.alias).flatMap(([alias, absolutePath]) => {
|
|
450
|
+
const aliasPath = getTsconfigPath(absolutePath);
|
|
451
|
+
return [
|
|
452
|
+
` "${alias}": ["${aliasPath}"]`,
|
|
453
|
+
` "${alias}/*": ["${aliasPath}/*"]`
|
|
454
|
+
];
|
|
455
|
+
}).join(",\n");
|
|
456
|
+
await writeFileIfDifferent(
|
|
457
|
+
resolve3(dir, "tsconfig.json"),
|
|
458
|
+
`{
|
|
459
|
+
"compilerOptions": {
|
|
460
|
+
"target": "ESNext",
|
|
461
|
+
"module": "ESNext",
|
|
462
|
+
"moduleResolution": "Bundler",
|
|
463
|
+
"noEmit": true,
|
|
464
|
+
"esModuleInterop": true,
|
|
465
|
+
"forceConsistentCasingInFileNames": true,
|
|
466
|
+
"resolveJsonModule": true,
|
|
467
|
+
"strict": true,
|
|
468
|
+
"skipLibCheck": true,
|
|
469
|
+
"paths": {
|
|
470
|
+
${paths}
|
|
278
471
|
}
|
|
279
|
-
}
|
|
472
|
+
},
|
|
473
|
+
"include": [
|
|
474
|
+
"${getTsconfigPath(config.root)}/**/*",
|
|
475
|
+
"./${getTsconfigPath(mainReference)}"
|
|
476
|
+
],
|
|
477
|
+
"exclude": ["${getTsconfigPath(config.outBaseDir)}"]
|
|
478
|
+
}`
|
|
479
|
+
);
|
|
280
480
|
}
|
|
281
481
|
|
|
282
|
-
// src/core/
|
|
283
|
-
|
|
482
|
+
// src/core/utils/building/get-internal-config.ts
|
|
483
|
+
import { loadConfig } from "c12";
|
|
484
|
+
import path4 from "node:path";
|
|
485
|
+
|
|
486
|
+
// src/core/utils/cache.ts
|
|
487
|
+
import fs4, { ensureDir } from "fs-extra";
|
|
488
|
+
import { dirname as dirname2, resolve as resolve4 } from "path";
|
|
489
|
+
function createFsCache(wxtDir) {
|
|
490
|
+
const getPath = (key) => resolve4(wxtDir, "cache", encodeURIComponent(key));
|
|
284
491
|
return {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
492
|
+
async set(key, value) {
|
|
493
|
+
const path6 = getPath(key);
|
|
494
|
+
await ensureDir(dirname2(path6));
|
|
495
|
+
await writeFileIfDifferent(path6, value);
|
|
496
|
+
},
|
|
497
|
+
async get(key) {
|
|
498
|
+
const path6 = getPath(key);
|
|
499
|
+
try {
|
|
500
|
+
return await fs4.readFile(path6, "utf-8");
|
|
501
|
+
} catch {
|
|
502
|
+
return void 0;
|
|
503
|
+
}
|
|
297
504
|
}
|
|
298
505
|
};
|
|
299
506
|
}
|
|
300
507
|
|
|
301
|
-
// src/core/
|
|
508
|
+
// src/core/utils/building/get-internal-config.ts
|
|
509
|
+
import consola, { LogLevels } from "consola";
|
|
510
|
+
|
|
511
|
+
// src/core/builders/vite/plugins/devHtmlPrerender.ts
|
|
302
512
|
import { parseHTML } from "linkedom";
|
|
303
|
-
import { dirname, isAbsolute, relative as
|
|
513
|
+
import { dirname as dirname3, isAbsolute, relative as relative3, resolve as resolve5 } from "node:path";
|
|
304
514
|
var reactRefreshPreamble = "";
|
|
305
515
|
function devHtmlPrerender(config) {
|
|
306
516
|
const htmlReloadId = "@wxt/reload-html";
|
|
307
|
-
const resolvedHtmlReloadId =
|
|
517
|
+
const resolvedHtmlReloadId = resolve5(
|
|
308
518
|
config.root,
|
|
309
519
|
"node_modules/wxt/dist/virtual/reload-html.js"
|
|
310
520
|
);
|
|
@@ -338,8 +548,8 @@ function devHtmlPrerender(config) {
|
|
|
338
548
|
if (isAbsolute(src)) {
|
|
339
549
|
element.setAttribute(attr, server.origin + src);
|
|
340
550
|
} else if (src.startsWith(".")) {
|
|
341
|
-
const abs =
|
|
342
|
-
const pathname =
|
|
551
|
+
const abs = resolve5(dirname3(id), src);
|
|
552
|
+
const pathname = relative3(config.root, abs);
|
|
343
553
|
element.setAttribute(attr, `${server.origin}/${pathname}`);
|
|
344
554
|
}
|
|
345
555
|
});
|
|
@@ -364,11 +574,7 @@ function devHtmlPrerender(config) {
|
|
|
364
574
|
const originalUrl = `${server.origin}${ctx.path}`;
|
|
365
575
|
const name = getEntrypointName(config.entrypointsDir, ctx.filename);
|
|
366
576
|
const url = `${server.origin}/${name}.html`;
|
|
367
|
-
const serverHtml = await server.
|
|
368
|
-
url,
|
|
369
|
-
html,
|
|
370
|
-
originalUrl
|
|
371
|
-
);
|
|
577
|
+
const serverHtml = await server.transformHtml(url, html, originalUrl);
|
|
372
578
|
const { document } = parseHTML(serverHtml);
|
|
373
579
|
const reactRefreshScript = Array.from(
|
|
374
580
|
document.querySelectorAll("script[type=module]")
|
|
@@ -416,59 +622,135 @@ function devHtmlPrerender(config) {
|
|
|
416
622
|
];
|
|
417
623
|
}
|
|
418
624
|
|
|
419
|
-
// src/core/vite
|
|
420
|
-
function devServerGlobals(
|
|
625
|
+
// src/core/builders/vite/plugins/devServerGlobals.ts
|
|
626
|
+
function devServerGlobals(config) {
|
|
421
627
|
return {
|
|
422
628
|
name: "wxt:dev-server-globals",
|
|
423
629
|
config() {
|
|
424
|
-
if (
|
|
630
|
+
if (config.server == null || config.command == "build")
|
|
425
631
|
return;
|
|
426
632
|
return {
|
|
427
633
|
define: {
|
|
428
634
|
__DEV_SERVER_PROTOCOL__: JSON.stringify("ws:"),
|
|
429
|
-
__DEV_SERVER_HOSTNAME__: JSON.stringify(
|
|
430
|
-
|
|
431
|
-
),
|
|
432
|
-
__DEV_SERVER_PORT__: JSON.stringify(internalConfig.server.port)
|
|
635
|
+
__DEV_SERVER_HOSTNAME__: JSON.stringify(config.server.hostname),
|
|
636
|
+
__DEV_SERVER_PORT__: JSON.stringify(config.server.port)
|
|
433
637
|
}
|
|
434
638
|
};
|
|
435
639
|
}
|
|
436
640
|
};
|
|
437
641
|
}
|
|
438
642
|
|
|
439
|
-
// src/core/
|
|
440
|
-
import
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
643
|
+
// src/core/utils/network.ts
|
|
644
|
+
import dns from "node:dns";
|
|
645
|
+
|
|
646
|
+
// src/core/utils/time.ts
|
|
647
|
+
function formatDuration(duration) {
|
|
648
|
+
if (duration < 1e3)
|
|
649
|
+
return `${duration} ms`;
|
|
650
|
+
if (duration < 1e4)
|
|
651
|
+
return `${(duration / 1e3).toFixed(3)} s`;
|
|
652
|
+
if (duration < 6e4)
|
|
653
|
+
return `${(duration / 1e3).toFixed(1)} s`;
|
|
654
|
+
return `${(duration / 1e3).toFixed(0)} s`;
|
|
655
|
+
}
|
|
656
|
+
function withTimeout(promise, duration) {
|
|
657
|
+
return new Promise((res, rej) => {
|
|
658
|
+
const timeout = setTimeout(() => {
|
|
659
|
+
rej(`Promise timed out after ${duration}ms`);
|
|
660
|
+
}, duration);
|
|
661
|
+
promise.then(res).catch(rej).finally(() => clearTimeout(timeout));
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/core/utils/network.ts
|
|
666
|
+
function isOffline() {
|
|
667
|
+
const isOffline2 = new Promise((res) => {
|
|
668
|
+
dns.resolve("google.com", (err) => {
|
|
669
|
+
if (err == null) {
|
|
670
|
+
res(false);
|
|
671
|
+
} else {
|
|
672
|
+
res(true);
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
return withTimeout(isOffline2, 1e3).catch(() => true);
|
|
677
|
+
}
|
|
678
|
+
async function isOnline() {
|
|
679
|
+
const offline = await isOffline();
|
|
680
|
+
return !offline;
|
|
681
|
+
}
|
|
682
|
+
async function fetchCached(url, config) {
|
|
683
|
+
let content = "";
|
|
684
|
+
if (await isOnline()) {
|
|
685
|
+
const res = await fetch(url);
|
|
686
|
+
if (res.status < 300) {
|
|
687
|
+
content = await res.text();
|
|
688
|
+
await config.fsCache.set(url, content);
|
|
689
|
+
} else {
|
|
690
|
+
config.logger.debug(
|
|
691
|
+
`Failed to download "${url}", falling back to cache...`
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if (!content)
|
|
696
|
+
content = await config.fsCache.get(url) ?? "";
|
|
697
|
+
if (!content)
|
|
698
|
+
throw Error(
|
|
699
|
+
`Offline and "${url}" has not been cached. Try again when online.`
|
|
700
|
+
);
|
|
701
|
+
return content;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// src/core/builders/vite/plugins/download.ts
|
|
705
|
+
function download(config) {
|
|
706
|
+
return {
|
|
707
|
+
name: "wxt:download",
|
|
708
|
+
resolveId(id) {
|
|
709
|
+
if (id.startsWith("url:"))
|
|
710
|
+
return "\0" + id;
|
|
711
|
+
},
|
|
712
|
+
async load(id) {
|
|
713
|
+
if (!id.startsWith("\0url:"))
|
|
714
|
+
return;
|
|
715
|
+
const url = id.replace("\0url:", "");
|
|
716
|
+
return await fetchCached(url, config);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/core/builders/vite/plugins/multipageMove.ts
|
|
722
|
+
import { dirname as dirname4, extname, resolve as resolve6, join } from "node:path";
|
|
723
|
+
import fs5, { ensureDir as ensureDir2 } from "fs-extra";
|
|
724
|
+
function multipageMove(entrypoints, config) {
|
|
725
|
+
return {
|
|
726
|
+
name: "wxt:multipage-move",
|
|
727
|
+
async writeBundle(_, bundle) {
|
|
728
|
+
for (const oldBundlePath in bundle) {
|
|
729
|
+
const entrypoint = entrypoints.find(
|
|
730
|
+
(entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath)
|
|
731
|
+
);
|
|
732
|
+
if (entrypoint == null) {
|
|
733
|
+
config.logger.debug(
|
|
734
|
+
`No entrypoint found for ${oldBundlePath}, leaving in chunks directory`
|
|
735
|
+
);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
const newBundlePath = getEntrypointBundlePath(
|
|
739
|
+
entrypoint,
|
|
740
|
+
config.outDir,
|
|
741
|
+
extname(oldBundlePath)
|
|
742
|
+
);
|
|
743
|
+
if (newBundlePath === oldBundlePath) {
|
|
744
|
+
config.logger.debug(
|
|
463
745
|
"HTML file is already in the correct location",
|
|
464
746
|
oldBundlePath
|
|
465
747
|
);
|
|
466
748
|
continue;
|
|
467
749
|
}
|
|
468
|
-
const oldAbsPath =
|
|
469
|
-
const newAbsPath =
|
|
470
|
-
await
|
|
471
|
-
await
|
|
750
|
+
const oldAbsPath = resolve6(config.outDir, oldBundlePath);
|
|
751
|
+
const newAbsPath = resolve6(config.outDir, newBundlePath);
|
|
752
|
+
await ensureDir2(dirname4(newAbsPath));
|
|
753
|
+
await fs5.move(oldAbsPath, newAbsPath, { overwrite: true });
|
|
472
754
|
const renamedChunk = {
|
|
473
755
|
...bundle[oldBundlePath],
|
|
474
756
|
fileName: newBundlePath
|
|
@@ -476,13 +758,59 @@ function multipageMove(entrypoints, config) {
|
|
|
476
758
|
delete bundle[oldBundlePath];
|
|
477
759
|
bundle[newBundlePath] = renamedChunk;
|
|
478
760
|
}
|
|
761
|
+
removeEmptyDirs(config.outDir);
|
|
479
762
|
}
|
|
480
763
|
};
|
|
481
764
|
}
|
|
765
|
+
async function removeEmptyDirs(dir) {
|
|
766
|
+
const files = await fs5.readdir(dir);
|
|
767
|
+
for (const file of files) {
|
|
768
|
+
const filePath = join(dir, file);
|
|
769
|
+
const stats = await fs5.stat(filePath);
|
|
770
|
+
if (stats.isDirectory()) {
|
|
771
|
+
await removeEmptyDirs(filePath);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
try {
|
|
775
|
+
await fs5.rmdir(dir);
|
|
776
|
+
} catch {
|
|
777
|
+
}
|
|
778
|
+
}
|
|
482
779
|
|
|
483
|
-
// src/core/vite
|
|
484
|
-
import
|
|
485
|
-
import {
|
|
780
|
+
// src/core/builders/vite/plugins/unimport.ts
|
|
781
|
+
import { createUnimport as createUnimport2 } from "unimport";
|
|
782
|
+
import { extname as extname2 } from "path";
|
|
783
|
+
var ENABLED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
784
|
+
".js",
|
|
785
|
+
".jsx",
|
|
786
|
+
".ts",
|
|
787
|
+
".tsx",
|
|
788
|
+
".vue",
|
|
789
|
+
".svelte"
|
|
790
|
+
]);
|
|
791
|
+
function unimport(config) {
|
|
792
|
+
const options = getUnimportOptions(config);
|
|
793
|
+
if (options === false)
|
|
794
|
+
return [];
|
|
795
|
+
const unimport2 = createUnimport2(options);
|
|
796
|
+
return {
|
|
797
|
+
name: "wxt:unimport",
|
|
798
|
+
async config() {
|
|
799
|
+
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
800
|
+
},
|
|
801
|
+
async transform(code, id) {
|
|
802
|
+
if (id.includes("node_modules"))
|
|
803
|
+
return;
|
|
804
|
+
if (!ENABLED_EXTENSIONS.has(extname2(id)))
|
|
805
|
+
return;
|
|
806
|
+
return unimport2.injectImports(code, id);
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/core/builders/vite/plugins/virtualEntrypoint.ts
|
|
812
|
+
import fs6 from "fs-extra";
|
|
813
|
+
import { resolve as resolve7 } from "path";
|
|
486
814
|
function virtualEntrypoint(type, config) {
|
|
487
815
|
const virtualId = `virtual:wxt-${type}?`;
|
|
488
816
|
const resolvedVirtualId = `\0${virtualId}`;
|
|
@@ -499,8 +827,8 @@ function virtualEntrypoint(type, config) {
|
|
|
499
827
|
if (!id.startsWith(resolvedVirtualId))
|
|
500
828
|
return;
|
|
501
829
|
const inputPath = id.replace(resolvedVirtualId, "");
|
|
502
|
-
const template = await
|
|
503
|
-
|
|
830
|
+
const template = await fs6.readFile(
|
|
831
|
+
resolve7(
|
|
504
832
|
config.root,
|
|
505
833
|
`node_modules/wxt/dist/virtual/${type}-entrypoint.js`
|
|
506
834
|
),
|
|
@@ -511,7 +839,24 @@ function virtualEntrypoint(type, config) {
|
|
|
511
839
|
};
|
|
512
840
|
}
|
|
513
841
|
|
|
514
|
-
// src/core/vite
|
|
842
|
+
// src/core/builders/vite/plugins/tsconfigPaths.ts
|
|
843
|
+
function tsconfigPaths(config) {
|
|
844
|
+
return {
|
|
845
|
+
name: "wxt:aliases",
|
|
846
|
+
async config() {
|
|
847
|
+
return {
|
|
848
|
+
resolve: {
|
|
849
|
+
alias: config.alias
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/core/utils/constants.ts
|
|
857
|
+
var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
|
|
858
|
+
|
|
859
|
+
// src/core/builders/vite/plugins/noopBackground.ts
|
|
515
860
|
function noopBackground() {
|
|
516
861
|
const virtualModuleId = VIRTUAL_NOOP_BACKGROUND_MODULE_ID;
|
|
517
862
|
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
@@ -529,9 +874,8 @@ export default defineBackground(() => void 0)`;
|
|
|
529
874
|
}
|
|
530
875
|
};
|
|
531
876
|
}
|
|
532
|
-
var VIRTUAL_NOOP_BACKGROUND_MODULE_ID = "virtual:user-background";
|
|
533
877
|
|
|
534
|
-
// src/core/vite
|
|
878
|
+
// src/core/builders/vite/plugins/cssEntrypoints.ts
|
|
535
879
|
function cssEntrypoints(entrypoint, config) {
|
|
536
880
|
return {
|
|
537
881
|
name: "wxt:css-entrypoint",
|
|
@@ -545,568 +889,320 @@ function cssEntrypoints(entrypoint, config) {
|
|
|
545
889
|
}
|
|
546
890
|
}
|
|
547
891
|
};
|
|
548
|
-
},
|
|
549
|
-
generateBundle(_, bundle) {
|
|
550
|
-
Object.keys(bundle).forEach((file) => {
|
|
551
|
-
if (file.endsWith(".js"))
|
|
552
|
-
delete bundle[file];
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// src/core/vite-plugins/bundleAnalysis.ts
|
|
559
|
-
import { visualizer } from "rollup-plugin-visualizer";
|
|
560
|
-
var increment = 0;
|
|
561
|
-
function bundleAnalysis() {
|
|
562
|
-
return visualizer({
|
|
563
|
-
emitFile: true,
|
|
564
|
-
template: "raw-data",
|
|
565
|
-
filename: `stats-${increment++}.json`
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// src/core/vite-plugins/excludeBrowserPolyfill.ts
|
|
570
|
-
function excludeBrowserPolyfill(config) {
|
|
571
|
-
const virtualId = "virtual:wxt-webextension-polyfill-disabled";
|
|
572
|
-
return {
|
|
573
|
-
name: "wxt:exclude-browser-polyfill",
|
|
574
|
-
config() {
|
|
575
|
-
if (config.experimental.includeBrowserPolyfill)
|
|
576
|
-
return;
|
|
577
|
-
return {
|
|
578
|
-
resolve: {
|
|
579
|
-
alias: {
|
|
580
|
-
"webextension-polyfill": virtualId
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
},
|
|
585
|
-
load(id) {
|
|
586
|
-
if (id === virtualId) {
|
|
587
|
-
return "export default chrome";
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// src/core/utils/arrays.ts
|
|
594
|
-
function every(array, predicate) {
|
|
595
|
-
for (let i = 0; i < array.length; i++)
|
|
596
|
-
if (!predicate(array[i], i))
|
|
597
|
-
return false;
|
|
598
|
-
return true;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// src/core/utils/building/detect-dev-changes.ts
|
|
602
|
-
function detectDevChanges(changedFiles, currentOutput) {
|
|
603
|
-
if (currentOutput == null)
|
|
604
|
-
return { type: "no-change" };
|
|
605
|
-
const changedSteps = new Set(
|
|
606
|
-
changedFiles.flatMap(
|
|
607
|
-
(changedFile) => findEffectedSteps(changedFile, currentOutput)
|
|
608
|
-
)
|
|
609
|
-
);
|
|
610
|
-
if (changedSteps.size === 0)
|
|
611
|
-
return { type: "no-change" };
|
|
612
|
-
const unchangedOutput = {
|
|
613
|
-
manifest: currentOutput.manifest,
|
|
614
|
-
steps: [],
|
|
615
|
-
publicAssets: []
|
|
616
|
-
};
|
|
617
|
-
const changedOutput = {
|
|
618
|
-
manifest: currentOutput.manifest,
|
|
619
|
-
steps: [],
|
|
620
|
-
publicAssets: []
|
|
621
|
-
};
|
|
622
|
-
for (const step of currentOutput.steps) {
|
|
623
|
-
if (changedSteps.has(step)) {
|
|
624
|
-
changedOutput.steps.push(step);
|
|
625
|
-
} else {
|
|
626
|
-
unchangedOutput.steps.push(step);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
for (const asset of currentOutput.publicAssets) {
|
|
630
|
-
if (changedSteps.has(asset)) {
|
|
631
|
-
changedOutput.publicAssets.push(asset);
|
|
632
|
-
} else {
|
|
633
|
-
unchangedOutput.publicAssets.push(asset);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, ([_, file]) => file.endsWith(".html"));
|
|
637
|
-
if (isOnlyHtmlChanges) {
|
|
638
|
-
return {
|
|
639
|
-
type: "html-reload",
|
|
640
|
-
cachedOutput: unchangedOutput,
|
|
641
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
const isOnlyContentScripts = changedOutput.steps.length > 0 && every(
|
|
645
|
-
changedOutput.steps.flatMap((step) => step.entrypoints),
|
|
646
|
-
(entry) => entry.type === "content-script"
|
|
647
|
-
);
|
|
648
|
-
if (isOnlyContentScripts) {
|
|
649
|
-
return {
|
|
650
|
-
type: "content-script-reload",
|
|
651
|
-
cachedOutput: unchangedOutput,
|
|
652
|
-
changedSteps: changedOutput.steps,
|
|
653
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
return {
|
|
657
|
-
type: "extension-reload",
|
|
658
|
-
cachedOutput: unchangedOutput,
|
|
659
|
-
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints)
|
|
660
|
-
};
|
|
661
|
-
}
|
|
662
|
-
function findEffectedSteps(changedFile, currentOutput) {
|
|
663
|
-
const changes = [];
|
|
664
|
-
const changedPath = normalizePath(changedFile[1]);
|
|
665
|
-
const isChunkEffected = (chunk) => (
|
|
666
|
-
// If it's an HTML file with the same path, is is effected because HTML files need to be pre-rendered
|
|
667
|
-
// fileName is normalized, relative bundle path
|
|
668
|
-
chunk.type === "asset" && changedPath.endsWith(chunk.fileName) || // If it's a chunk that depends on the changed file, it is effected
|
|
669
|
-
// moduleIds are absolute, normalized paths
|
|
670
|
-
chunk.type === "chunk" && chunk.moduleIds.includes(changedPath)
|
|
671
|
-
);
|
|
672
|
-
for (const step of currentOutput.steps) {
|
|
673
|
-
const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
|
|
674
|
-
if (effectedChunk)
|
|
675
|
-
changes.push(step);
|
|
676
|
-
}
|
|
677
|
-
const effectedAsset = currentOutput.publicAssets.find(
|
|
678
|
-
(chunk) => isChunkEffected(chunk)
|
|
679
|
-
);
|
|
680
|
-
if (effectedAsset)
|
|
681
|
-
changes.push(effectedAsset);
|
|
682
|
-
return changes;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// src/core/utils/building/find-entrypoints.ts
|
|
686
|
-
import { relative as relative4, resolve as resolve12 } from "path";
|
|
687
|
-
import fs12 from "fs-extra";
|
|
688
|
-
import { minimatch } from "minimatch";
|
|
689
|
-
import { parseHTML as parseHTML2 } from "linkedom";
|
|
690
|
-
import JSON5 from "json5";
|
|
691
|
-
|
|
692
|
-
// src/core/utils/building/build-entrypoints.ts
|
|
693
|
-
import * as vite from "vite";
|
|
694
|
-
|
|
695
|
-
// src/core/utils/fs.ts
|
|
696
|
-
import fs3 from "fs-extra";
|
|
697
|
-
import glob from "fast-glob";
|
|
698
|
-
import path3 from "node:path";
|
|
699
|
-
async function writeFileIfDifferent(file, newContents) {
|
|
700
|
-
const existingContents = await fs3.readFile(file, "utf-8").catch(() => void 0);
|
|
701
|
-
if (existingContents !== newContents) {
|
|
702
|
-
await fs3.writeFile(file, newContents);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
async function getPublicFiles(config) {
|
|
706
|
-
if (!await fs3.exists(config.publicDir))
|
|
707
|
-
return [];
|
|
708
|
-
const files = await glob("**/*", { cwd: config.publicDir });
|
|
709
|
-
return files.map(unnormalizePath);
|
|
710
|
-
}
|
|
711
|
-
async function removeEmptyDirs(dir) {
|
|
712
|
-
const files = await fs3.readdir(dir);
|
|
713
|
-
for (const file of files) {
|
|
714
|
-
const filePath = path3.join(dir, file);
|
|
715
|
-
const stats = await fs3.stat(filePath);
|
|
716
|
-
if (stats.isDirectory()) {
|
|
717
|
-
await removeEmptyDirs(filePath);
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
try {
|
|
721
|
-
await fs3.rmdir(dir);
|
|
722
|
-
} catch {
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// src/core/utils/building/build-entrypoints.ts
|
|
727
|
-
import fs4 from "fs-extra";
|
|
728
|
-
import { dirname as dirname3, resolve as resolve5 } from "path";
|
|
729
|
-
import pc from "picocolors";
|
|
730
|
-
async function buildEntrypoints(groups, config, spinner) {
|
|
731
|
-
const steps = [];
|
|
732
|
-
for (let i = 0; i < groups.length; i++) {
|
|
733
|
-
const group = groups[i];
|
|
734
|
-
spinner.text = pc.dim(`[${i + 1}/${groups.length}]`) + ` ${[group].flat().map((e) => e.name).join(pc.dim(", "))}`;
|
|
735
|
-
const step = Array.isArray(group) ? await buildMultipleEntrypoints(group, config) : await buildSingleEntrypoint(group, config);
|
|
736
|
-
steps.push(step);
|
|
737
|
-
}
|
|
738
|
-
const publicAssets = await copyPublicDirectory(config);
|
|
739
|
-
await removeEmptyDirs(config.outDir);
|
|
740
|
-
return { publicAssets, steps };
|
|
741
|
-
}
|
|
742
|
-
async function buildSingleEntrypoint(entrypoint, config) {
|
|
743
|
-
const isVirtual = [
|
|
744
|
-
"background",
|
|
745
|
-
"content-script",
|
|
746
|
-
"unlisted-script"
|
|
747
|
-
].includes(entrypoint.type);
|
|
748
|
-
const entry = isVirtual ? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}` : entrypoint.inputPath;
|
|
749
|
-
const plugins = [];
|
|
750
|
-
if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
|
|
751
|
-
plugins.push(cssEntrypoints(entrypoint, config));
|
|
752
|
-
}
|
|
753
|
-
const libMode = {
|
|
754
|
-
mode: config.mode,
|
|
755
|
-
plugins,
|
|
756
|
-
build: {
|
|
757
|
-
lib: {
|
|
758
|
-
entry,
|
|
759
|
-
formats: ["iife"],
|
|
760
|
-
name: "_",
|
|
761
|
-
fileName: entrypoint.name
|
|
762
|
-
},
|
|
763
|
-
rollupOptions: {
|
|
764
|
-
output: {
|
|
765
|
-
// There's only a single output for this build, so we use the desired bundle path for the
|
|
766
|
-
// entry output (like "content-scripts/overlay.js")
|
|
767
|
-
entryFileNames: getEntrypointBundlePath(
|
|
768
|
-
entrypoint,
|
|
769
|
-
config.outDir,
|
|
770
|
-
".js"
|
|
771
|
-
),
|
|
772
|
-
// Output content script CSS to `content-scripts/`, but all other scripts are written to
|
|
773
|
-
// `assets/`.
|
|
774
|
-
assetFileNames: ({ name }) => {
|
|
775
|
-
if (entrypoint.type === "content-script" && name?.endsWith("css")) {
|
|
776
|
-
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
777
|
-
} else {
|
|
778
|
-
return `assets/${entrypoint.name}.[ext]`;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
},
|
|
784
|
-
define: {
|
|
785
|
-
// See https://github.com/aklinker1/vite-plugin-web-extension/issues/96
|
|
786
|
-
"process.env.NODE_ENV": JSON.stringify(config.mode)
|
|
787
|
-
}
|
|
788
|
-
};
|
|
789
|
-
for (const global of getEntrypointGlobals(config, entrypoint.name)) {
|
|
790
|
-
libMode.define[global.name] = JSON.stringify(global.value);
|
|
791
|
-
}
|
|
792
|
-
const entryConfig = vite.mergeConfig(
|
|
793
|
-
libMode,
|
|
794
|
-
await config.vite(config.env)
|
|
795
|
-
);
|
|
796
|
-
const result = await vite.build(entryConfig);
|
|
797
|
-
return {
|
|
798
|
-
entrypoints: entrypoint,
|
|
799
|
-
chunks: getBuildOutputChunks(result)
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
async function buildMultipleEntrypoints(entrypoints, config) {
|
|
803
|
-
const multiPage = {
|
|
804
|
-
mode: config.mode,
|
|
805
|
-
plugins: [multipageMove(entrypoints, config)],
|
|
806
|
-
build: {
|
|
807
|
-
rollupOptions: {
|
|
808
|
-
input: entrypoints.reduce((input, entry) => {
|
|
809
|
-
input[entry.name] = entry.inputPath;
|
|
810
|
-
return input;
|
|
811
|
-
}, {}),
|
|
812
|
-
output: {
|
|
813
|
-
// Include a hash to prevent conflicts
|
|
814
|
-
chunkFileNames: "chunks/[name]-[hash].js",
|
|
815
|
-
// Include a hash to prevent conflicts
|
|
816
|
-
entryFileNames: "chunks/[name]-[hash].js",
|
|
817
|
-
// We can't control the "name", so we need a hash to prevent conflicts
|
|
818
|
-
assetFileNames: "assets/[name]-[hash].[ext]"
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
},
|
|
822
|
-
define: {}
|
|
823
|
-
};
|
|
824
|
-
for (const global of getEntrypointGlobals(config, "html")) {
|
|
825
|
-
multiPage.define[global.name] = JSON.stringify(global.value);
|
|
826
|
-
}
|
|
827
|
-
const entryConfig = vite.mergeConfig(
|
|
828
|
-
multiPage,
|
|
829
|
-
await config.vite(config.env)
|
|
830
|
-
);
|
|
831
|
-
const result = await vite.build(entryConfig);
|
|
832
|
-
return {
|
|
833
|
-
entrypoints,
|
|
834
|
-
chunks: getBuildOutputChunks(result)
|
|
835
|
-
};
|
|
836
|
-
}
|
|
837
|
-
function getBuildOutputChunks(result) {
|
|
838
|
-
if ("on" in result)
|
|
839
|
-
throw Error("wxt does not support vite watch mode.");
|
|
840
|
-
if (Array.isArray(result))
|
|
841
|
-
return result.flatMap(({ output }) => output);
|
|
842
|
-
return result.output;
|
|
843
|
-
}
|
|
844
|
-
async function copyPublicDirectory(config) {
|
|
845
|
-
const files = await getPublicFiles(config);
|
|
846
|
-
if (files.length === 0)
|
|
847
|
-
return [];
|
|
848
|
-
const publicAssets = [];
|
|
849
|
-
for (const file of files) {
|
|
850
|
-
const srcPath = resolve5(config.publicDir, file);
|
|
851
|
-
const outPath = resolve5(config.outDir, file);
|
|
852
|
-
await fs4.ensureDir(dirname3(outPath));
|
|
853
|
-
await fs4.copyFile(srcPath, outPath);
|
|
854
|
-
publicAssets.push({
|
|
855
|
-
type: "asset",
|
|
856
|
-
fileName: file,
|
|
857
|
-
name: file,
|
|
858
|
-
needsCodeReference: false,
|
|
859
|
-
source: await fs4.readFile(srcPath)
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
return publicAssets;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// src/core/utils/building/generate-wxt-dir.ts
|
|
866
|
-
import { createUnimport as createUnimport2 } from "unimport";
|
|
867
|
-
import fs5 from "fs-extra";
|
|
868
|
-
import { relative as relative3, resolve as resolve6 } from "path";
|
|
869
|
-
import path4 from "node:path";
|
|
870
|
-
|
|
871
|
-
// src/core/utils/i18n.ts
|
|
872
|
-
var predefinedMessages = {
|
|
873
|
-
"@@extension_id": {
|
|
874
|
-
message: "<browser.runtime.id>",
|
|
875
|
-
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."
|
|
876
|
-
},
|
|
877
|
-
"@@ui_locale": {
|
|
878
|
-
message: "<browser.i18n.getUiLocale()>",
|
|
879
|
-
description: ""
|
|
880
|
-
},
|
|
881
|
-
"@@bidi_dir": {
|
|
882
|
-
message: "<ltr|rtl>",
|
|
883
|
-
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.'
|
|
884
|
-
},
|
|
885
|
-
"@@bidi_reversed_dir": {
|
|
886
|
-
message: "<rtl|ltr>",
|
|
887
|
-
description: `If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr".`
|
|
888
|
-
},
|
|
889
|
-
"@@bidi_start_edge": {
|
|
890
|
-
message: "<left|right>",
|
|
891
|
-
description: `If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right".`
|
|
892
|
-
},
|
|
893
|
-
"@@bidi_end_edge": {
|
|
894
|
-
message: "<right|left>",
|
|
895
|
-
description: `If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left".`
|
|
896
|
-
}
|
|
897
|
-
};
|
|
898
|
-
function parseI18nMessages(messagesJson) {
|
|
899
|
-
return Object.entries({
|
|
900
|
-
...predefinedMessages,
|
|
901
|
-
...messagesJson
|
|
902
|
-
}).map(([name, details]) => ({
|
|
903
|
-
name,
|
|
904
|
-
...details
|
|
905
|
-
}));
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// src/core/utils/building/generate-wxt-dir.ts
|
|
909
|
-
async function generateTypesDir(entrypoints, config) {
|
|
910
|
-
await fs5.ensureDir(config.typesDir);
|
|
911
|
-
const references = [];
|
|
912
|
-
const imports = getUnimportOptions(config);
|
|
913
|
-
if (imports !== false) {
|
|
914
|
-
references.push(await writeImportsDeclarationFile(config, imports));
|
|
915
|
-
}
|
|
916
|
-
references.push(await writePathsDeclarationFile(entrypoints, config));
|
|
917
|
-
references.push(await writeI18nDeclarationFile(config));
|
|
918
|
-
references.push(await writeGlobalsDeclarationFile(config));
|
|
919
|
-
const mainReference = await writeMainDeclarationFile(references, config);
|
|
920
|
-
await writeTsConfigFile(mainReference, config);
|
|
921
|
-
}
|
|
922
|
-
async function writeImportsDeclarationFile(config, unimportOptions) {
|
|
923
|
-
const filePath = resolve6(config.typesDir, "imports.d.ts");
|
|
924
|
-
const unimport2 = createUnimport2(unimportOptions);
|
|
925
|
-
await unimport2.scanImportsFromDir(void 0, { cwd: config.srcDir });
|
|
926
|
-
await writeFileIfDifferent(
|
|
927
|
-
filePath,
|
|
928
|
-
["// Generated by wxt", await unimport2.generateTypeDeclarations()].join(
|
|
929
|
-
"\n"
|
|
930
|
-
) + "\n"
|
|
931
|
-
);
|
|
932
|
-
return filePath;
|
|
933
|
-
}
|
|
934
|
-
async function writePathsDeclarationFile(entrypoints, config) {
|
|
935
|
-
const filePath = resolve6(config.typesDir, "paths.d.ts");
|
|
936
|
-
const unions = entrypoints.map(
|
|
937
|
-
(entry) => getEntrypointBundlePath(
|
|
938
|
-
entry,
|
|
939
|
-
config.outDir,
|
|
940
|
-
entry.inputPath.endsWith(".html") ? ".html" : ".js"
|
|
941
|
-
)
|
|
942
|
-
).concat(await getPublicFiles(config)).map(normalizePath).map((path7) => ` | "/${path7}"`).sort().join("\n");
|
|
943
|
-
const template = `// Generated by wxt
|
|
944
|
-
import "wxt/browser";
|
|
945
|
-
|
|
946
|
-
declare module "wxt/browser" {
|
|
947
|
-
export type PublicPath =
|
|
948
|
-
{{ union }}
|
|
949
|
-
export interface WxtRuntime extends Runtime.Static {
|
|
950
|
-
getURL(path: PublicPath): string;
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
`;
|
|
954
|
-
await writeFileIfDifferent(
|
|
955
|
-
filePath,
|
|
956
|
-
template.replace("{{ union }}", unions || " | never")
|
|
957
|
-
);
|
|
958
|
-
return filePath;
|
|
959
|
-
}
|
|
960
|
-
async function writeI18nDeclarationFile(config) {
|
|
961
|
-
const filePath = resolve6(config.typesDir, "i18n.d.ts");
|
|
962
|
-
const defaultLocale = config.manifest.default_locale;
|
|
963
|
-
const template = `// Generated by wxt
|
|
964
|
-
import "wxt/browser";
|
|
965
|
-
|
|
966
|
-
declare module "wxt/browser" {
|
|
967
|
-
/**
|
|
968
|
-
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
969
|
-
*/
|
|
970
|
-
interface GetMessageOptions {
|
|
971
|
-
/**
|
|
972
|
-
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
|
973
|
-
*/
|
|
974
|
-
escapeLt?: boolean
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
export interface WxtI18n extends I18n.Static {
|
|
978
|
-
{{ overrides }}
|
|
979
|
-
}
|
|
892
|
+
},
|
|
893
|
+
generateBundle(_, bundle) {
|
|
894
|
+
Object.keys(bundle).forEach((file) => {
|
|
895
|
+
if (file.endsWith(".js"))
|
|
896
|
+
delete bundle[file];
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
};
|
|
980
900
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
const content = JSON.parse(await fs5.readFile(defaultLocalePath, "utf-8"));
|
|
991
|
-
messages = parseI18nMessages(content);
|
|
992
|
-
} else {
|
|
993
|
-
messages = parseI18nMessages({});
|
|
994
|
-
}
|
|
995
|
-
const overrides = messages.map((message) => {
|
|
996
|
-
return ` /**
|
|
997
|
-
* ${message.description ?? "No message description."}
|
|
998
|
-
*
|
|
999
|
-
* "${message.message}"
|
|
1000
|
-
*/
|
|
1001
|
-
getMessage(
|
|
1002
|
-
messageName: "${message.name}",
|
|
1003
|
-
substitutions?: string | string[],
|
|
1004
|
-
options?: GetMessageOptions,
|
|
1005
|
-
): string;`;
|
|
901
|
+
|
|
902
|
+
// src/core/builders/vite/plugins/bundleAnalysis.ts
|
|
903
|
+
import { visualizer } from "rollup-plugin-visualizer";
|
|
904
|
+
var increment = 0;
|
|
905
|
+
function bundleAnalysis() {
|
|
906
|
+
return visualizer({
|
|
907
|
+
emitFile: true,
|
|
908
|
+
template: "raw-data",
|
|
909
|
+
filename: `stats-${increment++}.json`
|
|
1006
910
|
});
|
|
1007
|
-
await writeFileIfDifferent(
|
|
1008
|
-
filePath,
|
|
1009
|
-
template.replace("{{ overrides }}", overrides.join("\n"))
|
|
1010
|
-
);
|
|
1011
|
-
return filePath;
|
|
1012
|
-
}
|
|
1013
|
-
async function writeGlobalsDeclarationFile(config) {
|
|
1014
|
-
const filePath = resolve6(config.typesDir, "globals.d.ts");
|
|
1015
|
-
const globals2 = [...getGlobals(config), ...getEntrypointGlobals(config, "")];
|
|
1016
|
-
await writeFileIfDifferent(
|
|
1017
|
-
filePath,
|
|
1018
|
-
[
|
|
1019
|
-
"// Generated by wxt",
|
|
1020
|
-
"export {}",
|
|
1021
|
-
"declare global {",
|
|
1022
|
-
...globals2.map((global) => ` const ${global.name}: ${global.type};`),
|
|
1023
|
-
"}"
|
|
1024
|
-
].join("\n") + "\n"
|
|
1025
|
-
);
|
|
1026
|
-
return filePath;
|
|
1027
911
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
912
|
+
|
|
913
|
+
// src/core/builders/vite/plugins/globals.ts
|
|
914
|
+
function globals(config) {
|
|
915
|
+
return {
|
|
916
|
+
name: "wxt:globals",
|
|
917
|
+
config() {
|
|
918
|
+
const define = {};
|
|
919
|
+
for (const global of getGlobals(config)) {
|
|
920
|
+
define[global.name] = JSON.stringify(global.value);
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
define
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
};
|
|
1042
927
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
"noEmit": true,
|
|
1061
|
-
"esModuleInterop": true,
|
|
1062
|
-
"forceConsistentCasingInFileNames": true,
|
|
1063
|
-
"resolveJsonModule": true,
|
|
1064
|
-
"strict": true,
|
|
1065
|
-
"skipLibCheck": true,
|
|
1066
|
-
"paths": {
|
|
1067
|
-
${paths}
|
|
928
|
+
|
|
929
|
+
// src/core/builders/vite/plugins/webextensionPolyfillAlias.ts
|
|
930
|
+
import path3 from "node:path";
|
|
931
|
+
function webextensionPolyfillAlias(config) {
|
|
932
|
+
return {
|
|
933
|
+
name: "wxt:webextension-polyfill-test-alias",
|
|
934
|
+
config() {
|
|
935
|
+
return {
|
|
936
|
+
resolve: {
|
|
937
|
+
alias: {
|
|
938
|
+
"webextension-polyfill": path3.resolve(
|
|
939
|
+
config.root,
|
|
940
|
+
"node_modules/wxt/dist/virtual/mock-browser"
|
|
941
|
+
)
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
};
|
|
1068
945
|
}
|
|
1069
|
-
}
|
|
1070
|
-
"include": [
|
|
1071
|
-
"${getTsconfigPath(config.root)}/**/*",
|
|
1072
|
-
"./${getTsconfigPath(mainReference)}"
|
|
1073
|
-
],
|
|
1074
|
-
"exclude": ["${getTsconfigPath(config.outBaseDir)}"]
|
|
1075
|
-
}`
|
|
1076
|
-
);
|
|
946
|
+
};
|
|
1077
947
|
}
|
|
1078
948
|
|
|
1079
|
-
// src/core/
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
949
|
+
// src/core/builders/vite/plugins/webextensionPolyfillInlineDeps.ts
|
|
950
|
+
function webextensionPolyfillInlineDeps() {
|
|
951
|
+
return {
|
|
952
|
+
name: "wxt:testing-inline-deps",
|
|
953
|
+
config() {
|
|
954
|
+
const wxtModules = ["wxt/browser", "wxt/client"];
|
|
955
|
+
return {
|
|
956
|
+
test: {
|
|
957
|
+
server: {
|
|
958
|
+
deps: {
|
|
959
|
+
inline: [...wxtModules]
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
}
|
|
1083
967
|
|
|
1084
|
-
// src/core/
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
function createFsCache(wxtDir) {
|
|
1088
|
-
const getPath = (key) => resolve7(wxtDir, "cache", encodeURIComponent(key));
|
|
968
|
+
// src/core/builders/vite/plugins/excludeBrowserPolyfill.ts
|
|
969
|
+
function excludeBrowserPolyfill(config) {
|
|
970
|
+
const virtualId = "virtual:wxt-webextension-polyfill-disabled";
|
|
1089
971
|
return {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
972
|
+
name: "wxt:exclude-browser-polyfill",
|
|
973
|
+
config() {
|
|
974
|
+
if (config.experimental.includeBrowserPolyfill)
|
|
975
|
+
return;
|
|
976
|
+
return {
|
|
977
|
+
resolve: {
|
|
978
|
+
alias: {
|
|
979
|
+
"webextension-polyfill": virtualId
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
};
|
|
1094
983
|
},
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
984
|
+
load(id) {
|
|
985
|
+
if (id === virtualId) {
|
|
986
|
+
return "export default chrome";
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// src/core/builders/vite/plugins/entrypointGroupGlobals.ts
|
|
993
|
+
function entrypointGroupGlobals(entrypointGroup) {
|
|
994
|
+
return {
|
|
995
|
+
name: "wxt:entrypoint-group-globals",
|
|
996
|
+
config() {
|
|
997
|
+
const define = {};
|
|
998
|
+
let name = Array.isArray(entrypointGroup) ? "html" : entrypointGroup.name;
|
|
999
|
+
for (const global of getEntrypointGlobals(name)) {
|
|
1000
|
+
define[global.name] = JSON.stringify(global.value);
|
|
1001
|
+
}
|
|
1002
|
+
return {
|
|
1003
|
+
define
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/core/builders/vite/index.ts
|
|
1010
|
+
async function craeteViteBuilder(inlineConfig, userConfig, wxtConfig) {
|
|
1011
|
+
const vite = await import("vite");
|
|
1012
|
+
const getBaseConfig = async () => {
|
|
1013
|
+
const resolvedInlineConfig = await inlineConfig.vite?.(wxtConfig.env) ?? {};
|
|
1014
|
+
const resolvedUserConfig = await userConfig.vite?.(wxtConfig.env) ?? {};
|
|
1015
|
+
const config = vite.mergeConfig(
|
|
1016
|
+
resolvedUserConfig,
|
|
1017
|
+
resolvedInlineConfig
|
|
1018
|
+
);
|
|
1019
|
+
config.root = wxtConfig.root;
|
|
1020
|
+
config.configFile = false;
|
|
1021
|
+
config.logLevel = "warn";
|
|
1022
|
+
config.mode = wxtConfig.mode;
|
|
1023
|
+
config.build ??= {};
|
|
1024
|
+
config.build.outDir = wxtConfig.outDir;
|
|
1025
|
+
config.build.emptyOutDir = false;
|
|
1026
|
+
config.plugins ??= [];
|
|
1027
|
+
config.plugins.push(
|
|
1028
|
+
download(wxtConfig),
|
|
1029
|
+
devHtmlPrerender(wxtConfig),
|
|
1030
|
+
unimport(wxtConfig),
|
|
1031
|
+
virtualEntrypoint("background", wxtConfig),
|
|
1032
|
+
virtualEntrypoint("content-script", wxtConfig),
|
|
1033
|
+
virtualEntrypoint("unlisted-script", wxtConfig),
|
|
1034
|
+
devServerGlobals(wxtConfig),
|
|
1035
|
+
tsconfigPaths(wxtConfig),
|
|
1036
|
+
noopBackground(),
|
|
1037
|
+
globals(wxtConfig),
|
|
1038
|
+
excludeBrowserPolyfill(wxtConfig)
|
|
1039
|
+
);
|
|
1040
|
+
if (wxtConfig.analysis.enabled) {
|
|
1041
|
+
config.plugins.push(bundleAnalysis());
|
|
1042
|
+
}
|
|
1043
|
+
return config;
|
|
1044
|
+
};
|
|
1045
|
+
const getLibModeConfig = (entrypoint) => {
|
|
1046
|
+
const isVirtual = [
|
|
1047
|
+
"background",
|
|
1048
|
+
"content-script",
|
|
1049
|
+
"unlisted-script"
|
|
1050
|
+
].includes(entrypoint.type);
|
|
1051
|
+
const entry = isVirtual ? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}` : entrypoint.inputPath;
|
|
1052
|
+
const plugins = [
|
|
1053
|
+
entrypointGroupGlobals(entrypoint)
|
|
1054
|
+
];
|
|
1055
|
+
if (entrypoint.type === "content-script-style" || entrypoint.type === "unlisted-style") {
|
|
1056
|
+
plugins.push(cssEntrypoints(entrypoint, wxtConfig));
|
|
1057
|
+
}
|
|
1058
|
+
const libMode = {
|
|
1059
|
+
mode: wxtConfig.mode,
|
|
1060
|
+
plugins,
|
|
1061
|
+
build: {
|
|
1062
|
+
lib: {
|
|
1063
|
+
entry,
|
|
1064
|
+
formats: ["iife"],
|
|
1065
|
+
name: "_",
|
|
1066
|
+
fileName: entrypoint.name
|
|
1067
|
+
},
|
|
1068
|
+
rollupOptions: {
|
|
1069
|
+
output: {
|
|
1070
|
+
// There's only a single output for this build, so we use the desired bundle path for the
|
|
1071
|
+
// entry output (like "content-scripts/overlay.js")
|
|
1072
|
+
entryFileNames: getEntrypointBundlePath(
|
|
1073
|
+
entrypoint,
|
|
1074
|
+
wxtConfig.outDir,
|
|
1075
|
+
".js"
|
|
1076
|
+
),
|
|
1077
|
+
// Output content script CSS to `content-scripts/`, but all other scripts are written to
|
|
1078
|
+
// `assets/`.
|
|
1079
|
+
assetFileNames: ({ name }) => {
|
|
1080
|
+
if (entrypoint.type === "content-script" && name?.endsWith("css")) {
|
|
1081
|
+
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
1082
|
+
} else {
|
|
1083
|
+
return `assets/${entrypoint.name}.[ext]`;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
},
|
|
1089
|
+
define: {
|
|
1090
|
+
// See https://github.com/aklinker1/vite-plugin-web-extension/issues/96
|
|
1091
|
+
"process.env.NODE_ENV": JSON.stringify(wxtConfig.mode)
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
return libMode;
|
|
1095
|
+
};
|
|
1096
|
+
const getMultiPageConfig = (entrypoints) => {
|
|
1097
|
+
return {
|
|
1098
|
+
mode: wxtConfig.mode,
|
|
1099
|
+
plugins: [
|
|
1100
|
+
multipageMove(entrypoints, wxtConfig),
|
|
1101
|
+
entrypointGroupGlobals(entrypoints)
|
|
1102
|
+
],
|
|
1103
|
+
build: {
|
|
1104
|
+
rollupOptions: {
|
|
1105
|
+
input: entrypoints.reduce((input, entry) => {
|
|
1106
|
+
input[entry.name] = entry.inputPath;
|
|
1107
|
+
return input;
|
|
1108
|
+
}, {}),
|
|
1109
|
+
output: {
|
|
1110
|
+
// Include a hash to prevent conflicts
|
|
1111
|
+
chunkFileNames: "chunks/[name]-[hash].js",
|
|
1112
|
+
// Include a hash to prevent conflicts
|
|
1113
|
+
entryFileNames: "chunks/[name]-[hash].js",
|
|
1114
|
+
// We can't control the "name", so we need a hash to prevent conflicts
|
|
1115
|
+
assetFileNames: "assets/[name]-[hash].[ext]"
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
};
|
|
1121
|
+
const getCssConfig = (entrypoint) => {
|
|
1122
|
+
return {
|
|
1123
|
+
mode: wxtConfig.mode,
|
|
1124
|
+
plugins: [entrypointGroupGlobals(entrypoint)],
|
|
1125
|
+
build: {
|
|
1126
|
+
rollupOptions: {
|
|
1127
|
+
input: {
|
|
1128
|
+
[entrypoint.name]: entrypoint.inputPath
|
|
1129
|
+
},
|
|
1130
|
+
output: {
|
|
1131
|
+
assetFileNames: () => {
|
|
1132
|
+
if (entrypoint.type === "content-script-style") {
|
|
1133
|
+
return `content-scripts/${entrypoint.name}.[ext]`;
|
|
1134
|
+
} else {
|
|
1135
|
+
return `assets/${entrypoint.name}.[ext]`;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1101
1140
|
}
|
|
1141
|
+
};
|
|
1142
|
+
};
|
|
1143
|
+
return {
|
|
1144
|
+
name: "Vite",
|
|
1145
|
+
version: vite.version,
|
|
1146
|
+
async build(group) {
|
|
1147
|
+
let entryConfig;
|
|
1148
|
+
if (Array.isArray(group))
|
|
1149
|
+
entryConfig = getMultiPageConfig(group);
|
|
1150
|
+
else if (group.inputPath.endsWith(".css"))
|
|
1151
|
+
entryConfig = getCssConfig(group);
|
|
1152
|
+
else
|
|
1153
|
+
entryConfig = getLibModeConfig(group);
|
|
1154
|
+
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
|
|
1155
|
+
const result = await vite.build(buildConfig);
|
|
1156
|
+
return {
|
|
1157
|
+
entrypoints: group,
|
|
1158
|
+
chunks: getBuildOutputChunks(result)
|
|
1159
|
+
};
|
|
1160
|
+
},
|
|
1161
|
+
async createServer(info) {
|
|
1162
|
+
const serverConfig = {
|
|
1163
|
+
server: {
|
|
1164
|
+
port: info.port,
|
|
1165
|
+
strictPort: true,
|
|
1166
|
+
host: info.hostname,
|
|
1167
|
+
origin: info.origin
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
const baseConfig = await getBaseConfig();
|
|
1171
|
+
const viteServer = await vite.createServer(
|
|
1172
|
+
vite.mergeConfig(baseConfig, serverConfig)
|
|
1173
|
+
);
|
|
1174
|
+
const server = {
|
|
1175
|
+
async listen() {
|
|
1176
|
+
await viteServer.listen(info.port);
|
|
1177
|
+
},
|
|
1178
|
+
transformHtml(...args) {
|
|
1179
|
+
return viteServer.transformIndexHtml(...args);
|
|
1180
|
+
},
|
|
1181
|
+
ws: {
|
|
1182
|
+
send(message, payload) {
|
|
1183
|
+
return viteServer.ws.send(message, payload);
|
|
1184
|
+
},
|
|
1185
|
+
on(message, cb) {
|
|
1186
|
+
viteServer.ws.on(message, cb);
|
|
1187
|
+
}
|
|
1188
|
+
},
|
|
1189
|
+
watcher: viteServer.watcher
|
|
1190
|
+
};
|
|
1191
|
+
return server;
|
|
1102
1192
|
}
|
|
1103
1193
|
};
|
|
1104
1194
|
}
|
|
1195
|
+
function getBuildOutputChunks(result) {
|
|
1196
|
+
if ("on" in result)
|
|
1197
|
+
throw Error("wxt does not support vite watch mode.");
|
|
1198
|
+
if (Array.isArray(result))
|
|
1199
|
+
return result.flatMap(({ output }) => output);
|
|
1200
|
+
return result.output;
|
|
1201
|
+
}
|
|
1105
1202
|
|
|
1106
1203
|
// src/core/utils/building/get-internal-config.ts
|
|
1107
|
-
import
|
|
1108
|
-
|
|
1109
|
-
async function getInternalConfig(inlineConfig, command) {
|
|
1204
|
+
import defu2 from "defu";
|
|
1205
|
+
async function getInternalConfig(inlineConfig, command, server) {
|
|
1110
1206
|
let userConfig = {};
|
|
1111
1207
|
let userConfigMetadata;
|
|
1112
1208
|
if (inlineConfig.configFile !== false) {
|
|
@@ -1127,19 +1223,19 @@ async function getInternalConfig(inlineConfig, command) {
|
|
|
1127
1223
|
const manifestVersion = mergedConfig.manifestVersion ?? (browser === "firefox" || browser === "safari" ? 2 : 3);
|
|
1128
1224
|
const mode = mergedConfig.mode ?? (command === "build" ? "production" : "development");
|
|
1129
1225
|
const env = { browser, command, manifestVersion, mode };
|
|
1130
|
-
const root =
|
|
1226
|
+
const root = path4.resolve(
|
|
1131
1227
|
inlineConfig.root ?? userConfig.root ?? process.cwd()
|
|
1132
1228
|
);
|
|
1133
|
-
const wxtDir =
|
|
1134
|
-
const srcDir =
|
|
1135
|
-
const entrypointsDir =
|
|
1229
|
+
const wxtDir = path4.resolve(root, ".wxt");
|
|
1230
|
+
const srcDir = path4.resolve(root, mergedConfig.srcDir ?? root);
|
|
1231
|
+
const entrypointsDir = path4.resolve(
|
|
1136
1232
|
srcDir,
|
|
1137
1233
|
mergedConfig.entrypointsDir ?? "entrypoints"
|
|
1138
1234
|
);
|
|
1139
|
-
const publicDir =
|
|
1140
|
-
const typesDir =
|
|
1141
|
-
const outBaseDir =
|
|
1142
|
-
const outDir =
|
|
1235
|
+
const publicDir = path4.resolve(srcDir, mergedConfig.publicDir ?? "public");
|
|
1236
|
+
const typesDir = path4.resolve(wxtDir, "types");
|
|
1237
|
+
const outBaseDir = path4.resolve(root, mergedConfig.outDir ?? ".output");
|
|
1238
|
+
const outDir = path4.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
|
|
1143
1239
|
const runnerConfig = await loadConfig({
|
|
1144
1240
|
name: "web-ext",
|
|
1145
1241
|
cwd: root,
|
|
@@ -1155,7 +1251,7 @@ async function getInternalConfig(inlineConfig, command) {
|
|
|
1155
1251
|
"~": srcDir,
|
|
1156
1252
|
"@@": root,
|
|
1157
1253
|
"~~": root
|
|
1158
|
-
}).map(([key, value]) => [key,
|
|
1254
|
+
}).map(([key, value]) => [key, path4.resolve(root, value)])
|
|
1159
1255
|
);
|
|
1160
1256
|
const finalConfig = {
|
|
1161
1257
|
browser,
|
|
@@ -1176,8 +1272,6 @@ async function getInternalConfig(inlineConfig, command) {
|
|
|
1176
1272
|
runnerConfig,
|
|
1177
1273
|
srcDir,
|
|
1178
1274
|
typesDir,
|
|
1179
|
-
vite: () => ({}),
|
|
1180
|
-
// Real value added after this object is initialized.
|
|
1181
1275
|
wxtDir,
|
|
1182
1276
|
zip: resolveInternalZipConfig(root, mergedConfig),
|
|
1183
1277
|
transformManifest(manifest) {
|
|
@@ -1192,10 +1286,18 @@ async function getInternalConfig(inlineConfig, command) {
|
|
|
1192
1286
|
alias,
|
|
1193
1287
|
experimental: {
|
|
1194
1288
|
includeBrowserPolyfill: mergedConfig.experimental?.includeBrowserPolyfill ?? true
|
|
1195
|
-
}
|
|
1289
|
+
},
|
|
1290
|
+
server
|
|
1291
|
+
};
|
|
1292
|
+
const builder = await craeteViteBuilder(
|
|
1293
|
+
inlineConfig,
|
|
1294
|
+
userConfig,
|
|
1295
|
+
finalConfig
|
|
1296
|
+
);
|
|
1297
|
+
return {
|
|
1298
|
+
...finalConfig,
|
|
1299
|
+
builder
|
|
1196
1300
|
};
|
|
1197
|
-
finalConfig.vite = (env2) => resolveInternalViteConfig(env2, mergedConfig, finalConfig);
|
|
1198
|
-
return finalConfig;
|
|
1199
1301
|
}
|
|
1200
1302
|
async function resolveManifestConfig(env, manifest) {
|
|
1201
1303
|
return await (typeof manifest === "function" ? manifest(env) : manifest ?? {});
|
|
@@ -1207,26 +1309,18 @@ function mergeInlineConfig(inlineConfig, userConfig) {
|
|
|
1207
1309
|
} else if (userConfig.imports == null && inlineConfig.imports == null) {
|
|
1208
1310
|
imports = void 0;
|
|
1209
1311
|
} else {
|
|
1210
|
-
imports =
|
|
1211
|
-
userConfig.imports ?? {},
|
|
1212
|
-
inlineConfig.imports ?? {}
|
|
1213
|
-
);
|
|
1312
|
+
imports = defu2(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
|
1214
1313
|
}
|
|
1215
1314
|
const manifest = async (env) => {
|
|
1216
1315
|
const user = await resolveManifestConfig(env, userConfig.manifest);
|
|
1217
1316
|
const inline = await resolveManifestConfig(env, inlineConfig.manifest);
|
|
1218
|
-
return
|
|
1317
|
+
return defu2(inline, user);
|
|
1219
1318
|
};
|
|
1220
|
-
const
|
|
1221
|
-
const user = await userConfig.vite?.(env);
|
|
1222
|
-
const inline = await inlineConfig.vite?.(env);
|
|
1223
|
-
return vite2.mergeConfig(user ?? {}, inline ?? {});
|
|
1224
|
-
};
|
|
1225
|
-
const runner = defu(
|
|
1319
|
+
const runner = defu2(
|
|
1226
1320
|
inlineConfig.runner ?? {},
|
|
1227
1321
|
userConfig.runner ?? {}
|
|
1228
1322
|
);
|
|
1229
|
-
const zip =
|
|
1323
|
+
const zip = defu2(
|
|
1230
1324
|
inlineConfig.zip ?? {},
|
|
1231
1325
|
userConfig.zip ?? {}
|
|
1232
1326
|
);
|
|
@@ -1244,7 +1338,7 @@ function mergeInlineConfig(inlineConfig, userConfig) {
|
|
|
1244
1338
|
publicDir: inlineConfig.publicDir ?? userConfig.publicDir,
|
|
1245
1339
|
runner,
|
|
1246
1340
|
srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
|
|
1247
|
-
|
|
1341
|
+
outDir: inlineConfig.outDir ?? userConfig.outDir,
|
|
1248
1342
|
zip,
|
|
1249
1343
|
analysis: {
|
|
1250
1344
|
enabled: inlineConfig.analysis?.enabled ?? userConfig.analysis?.enabled,
|
|
@@ -1257,11 +1351,14 @@ function mergeInlineConfig(inlineConfig, userConfig) {
|
|
|
1257
1351
|
experimental: {
|
|
1258
1352
|
...userConfig.experimental,
|
|
1259
1353
|
...inlineConfig.experimental
|
|
1260
|
-
}
|
|
1354
|
+
},
|
|
1355
|
+
vite: void 0,
|
|
1356
|
+
transformManifest: void 0
|
|
1261
1357
|
};
|
|
1262
1358
|
}
|
|
1263
1359
|
function resolveInternalZipConfig(root, mergedConfig) {
|
|
1264
1360
|
return {
|
|
1361
|
+
name: void 0,
|
|
1265
1362
|
sourcesTemplate: "{{name}}-{{version}}-sources.zip",
|
|
1266
1363
|
artifactTemplate: "{{name}}-{{version}}-{{browser}}.zip",
|
|
1267
1364
|
sourcesRoot: root,
|
|
@@ -1280,38 +1377,6 @@ function resolveInternalZipConfig(root, mergedConfig) {
|
|
|
1280
1377
|
]
|
|
1281
1378
|
};
|
|
1282
1379
|
}
|
|
1283
|
-
async function resolveInternalViteConfig(env, mergedConfig, finalConfig) {
|
|
1284
|
-
const internalVite = await mergedConfig.vite?.(env) ?? {};
|
|
1285
|
-
internalVite.root = finalConfig.root;
|
|
1286
|
-
internalVite.configFile = false;
|
|
1287
|
-
internalVite.logLevel = "warn";
|
|
1288
|
-
internalVite.mode = env.mode;
|
|
1289
|
-
internalVite.build ??= {};
|
|
1290
|
-
internalVite.build.outDir = finalConfig.outDir;
|
|
1291
|
-
internalVite.build.emptyOutDir = false;
|
|
1292
|
-
internalVite.plugins ??= [];
|
|
1293
|
-
internalVite.plugins.push(download(finalConfig));
|
|
1294
|
-
internalVite.plugins.push(devHtmlPrerender(finalConfig));
|
|
1295
|
-
internalVite.plugins.push(unimport(finalConfig));
|
|
1296
|
-
internalVite.plugins.push(
|
|
1297
|
-
virtualEntrypoint("background", finalConfig)
|
|
1298
|
-
);
|
|
1299
|
-
internalVite.plugins.push(
|
|
1300
|
-
virtualEntrypoint("content-script", finalConfig)
|
|
1301
|
-
);
|
|
1302
|
-
internalVite.plugins.push(
|
|
1303
|
-
virtualEntrypoint("unlisted-script", finalConfig)
|
|
1304
|
-
);
|
|
1305
|
-
internalVite.plugins.push(devServerGlobals(finalConfig));
|
|
1306
|
-
internalVite.plugins.push(tsconfigPaths(finalConfig));
|
|
1307
|
-
internalVite.plugins.push(noopBackground());
|
|
1308
|
-
if (finalConfig.analysis.enabled) {
|
|
1309
|
-
internalVite.plugins.push(bundleAnalysis());
|
|
1310
|
-
}
|
|
1311
|
-
internalVite.plugins.push(globals(finalConfig));
|
|
1312
|
-
internalVite.plugins.push(excludeBrowserPolyfill(finalConfig));
|
|
1313
|
-
return internalVite;
|
|
1314
|
-
}
|
|
1315
1380
|
|
|
1316
1381
|
// src/core/utils/building/group-entrypoints.ts
|
|
1317
1382
|
function groupEntrypoints(entrypoints) {
|
|
@@ -1375,16 +1440,16 @@ ${noImports}`;
|
|
|
1375
1440
|
|
|
1376
1441
|
// src/core/utils/building/import-entrypoint.ts
|
|
1377
1442
|
import { transformSync } from "esbuild";
|
|
1378
|
-
async function importEntrypointFile(
|
|
1379
|
-
config.logger.debug("Loading file metadata:",
|
|
1380
|
-
const normalPath = normalizePath(
|
|
1443
|
+
async function importEntrypointFile(path6, config) {
|
|
1444
|
+
config.logger.debug("Loading file metadata:", path6);
|
|
1445
|
+
const normalPath = normalizePath(path6);
|
|
1381
1446
|
const unimport2 = createUnimport3({
|
|
1382
1447
|
...getUnimportOptions(config),
|
|
1383
1448
|
// Only allow specific imports, not all from the project
|
|
1384
1449
|
dirs: []
|
|
1385
1450
|
});
|
|
1386
1451
|
await unimport2.init();
|
|
1387
|
-
const text = await fs7.readFile(
|
|
1452
|
+
const text = await fs7.readFile(path6, "utf-8");
|
|
1388
1453
|
const textNoImports = removeProjectImportStatements(text);
|
|
1389
1454
|
const { code } = await unimport2.injectImports(textNoImports);
|
|
1390
1455
|
config.logger.debug(
|
|
@@ -1415,7 +1480,7 @@ async function importEntrypointFile(path7, config) {
|
|
|
1415
1480
|
}
|
|
1416
1481
|
});
|
|
1417
1482
|
try {
|
|
1418
|
-
const res = await jiti(
|
|
1483
|
+
const res = await jiti(path6);
|
|
1419
1484
|
return res.default;
|
|
1420
1485
|
} catch (err) {
|
|
1421
1486
|
config.logger.error(err);
|
|
@@ -1433,14 +1498,13 @@ function getEsbuildOptions(opts) {
|
|
|
1433
1498
|
|
|
1434
1499
|
// src/core/utils/building/internal-build.ts
|
|
1435
1500
|
import pc4 from "picocolors";
|
|
1436
|
-
import * as vite3 from "vite";
|
|
1437
1501
|
import fs11 from "fs-extra";
|
|
1438
1502
|
|
|
1439
1503
|
// src/core/utils/log/printBuildSummary.ts
|
|
1440
1504
|
import { resolve as resolve9 } from "path";
|
|
1441
1505
|
|
|
1442
1506
|
// src/core/utils/log/printFileList.ts
|
|
1443
|
-
import
|
|
1507
|
+
import path5 from "node:path";
|
|
1444
1508
|
import pc2 from "picocolors";
|
|
1445
1509
|
import fs8 from "fs-extra";
|
|
1446
1510
|
import { filesize } from "filesize";
|
|
@@ -1478,8 +1542,8 @@ async function printFileList(log, header, baseDir, files) {
|
|
|
1478
1542
|
const fileRows = await Promise.all(
|
|
1479
1543
|
files.map(async (file, i) => {
|
|
1480
1544
|
const parts = [
|
|
1481
|
-
|
|
1482
|
-
|
|
1545
|
+
path5.relative(process.cwd(), baseDir) + path5.sep,
|
|
1546
|
+
path5.relative(baseDir, file)
|
|
1483
1547
|
];
|
|
1484
1548
|
const prefix = i === files.length - 1 ? " \u2514\u2500" : " \u251C\u2500";
|
|
1485
1549
|
const color = getChunkColor(file);
|
|
@@ -1670,37 +1734,34 @@ async function getPackageJson(config) {
|
|
|
1670
1734
|
|
|
1671
1735
|
// src/core/utils/manifest.ts
|
|
1672
1736
|
import { produce } from "immer";
|
|
1673
|
-
import
|
|
1737
|
+
import defu3 from "defu";
|
|
1674
1738
|
async function writeManifest(manifest, output, config) {
|
|
1675
1739
|
const str = config.mode === "production" ? JSON.stringify(manifest) : JSON.stringify(manifest, null, 2);
|
|
1676
1740
|
await fs10.ensureDir(config.outDir);
|
|
1677
1741
|
await writeFileIfDifferent(resolve11(config.outDir, "manifest.json"), str);
|
|
1678
1742
|
output.publicAssets.unshift({
|
|
1679
1743
|
type: "asset",
|
|
1680
|
-
fileName: "manifest.json"
|
|
1681
|
-
name: "manifest",
|
|
1682
|
-
needsCodeReference: false,
|
|
1683
|
-
source: str
|
|
1744
|
+
fileName: "manifest.json"
|
|
1684
1745
|
});
|
|
1685
1746
|
}
|
|
1686
1747
|
async function generateMainfest(entrypoints, buildOutput, config) {
|
|
1687
1748
|
const pkg = await getPackageJson(config);
|
|
1688
1749
|
const versionName = config.manifest.version_name ?? pkg?.version;
|
|
1689
|
-
const
|
|
1750
|
+
const version2 = config.manifest.version ?? simplifyVersion(pkg?.version);
|
|
1690
1751
|
const baseManifest = {
|
|
1691
1752
|
manifest_version: config.manifestVersion,
|
|
1692
1753
|
name: pkg?.name,
|
|
1693
1754
|
description: pkg?.description,
|
|
1694
|
-
version:
|
|
1755
|
+
version: version2,
|
|
1695
1756
|
version_name: (
|
|
1696
1757
|
// Firefox doesn't support version_name
|
|
1697
|
-
config.browser === "firefox" || versionName ===
|
|
1758
|
+
config.browser === "firefox" || versionName === version2 ? void 0 : versionName
|
|
1698
1759
|
),
|
|
1699
1760
|
short_name: pkg?.shortName,
|
|
1700
1761
|
icons: discoverIcons(buildOutput)
|
|
1701
1762
|
};
|
|
1702
1763
|
const userManifest = config.manifest;
|
|
1703
|
-
const manifest =
|
|
1764
|
+
const manifest = defu3(
|
|
1704
1765
|
userManifest,
|
|
1705
1766
|
baseManifest
|
|
1706
1767
|
);
|
|
@@ -1722,14 +1783,14 @@ async function generateMainfest(entrypoints, buildOutput, config) {
|
|
|
1722
1783
|
return finalManifest;
|
|
1723
1784
|
}
|
|
1724
1785
|
function simplifyVersion(versionName) {
|
|
1725
|
-
const
|
|
1786
|
+
const version2 = /^((0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}).*$/.exec(
|
|
1726
1787
|
versionName
|
|
1727
1788
|
)?.[1];
|
|
1728
|
-
if (
|
|
1789
|
+
if (version2 == null)
|
|
1729
1790
|
throw Error(
|
|
1730
1791
|
`Cannot simplify package.json version "${versionName}" to a valid extension version, "X.Y.Z"`
|
|
1731
1792
|
);
|
|
1732
|
-
return
|
|
1793
|
+
return version2;
|
|
1733
1794
|
}
|
|
1734
1795
|
function addEntrypoints(manifest, entrypoints, buildOutput, config) {
|
|
1735
1796
|
const entriesByType = entrypoints.reduce((map, entrypoint) => {
|
|
@@ -2101,7 +2162,7 @@ async function internalBuild(config) {
|
|
|
2101
2162
|
const target = `${config.browser}-mv${config.manifestVersion}`;
|
|
2102
2163
|
config.logger.info(
|
|
2103
2164
|
`${verb} ${pc4.cyan(target)} for ${pc4.cyan(config.mode)} with ${pc4.green(
|
|
2104
|
-
|
|
2165
|
+
`${config.builder.name} ${config.builder.version}`
|
|
2105
2166
|
)}`
|
|
2106
2167
|
);
|
|
2107
2168
|
const startTime = Date.now();
|
|
@@ -2127,7 +2188,7 @@ async function internalBuild(config) {
|
|
|
2127
2188
|
return output;
|
|
2128
2189
|
}
|
|
2129
2190
|
async function combineAnalysisStats(config) {
|
|
2130
|
-
const { execaCommand } = await import("./execa-
|
|
2191
|
+
const { execaCommand } = await import("./execa-4F7CCWCA.js");
|
|
2131
2192
|
const unixFiles = await glob2(`stats-*.json`, {
|
|
2132
2193
|
cwd: config.outDir,
|
|
2133
2194
|
absolute: true
|
|
@@ -2150,7 +2211,7 @@ async function findEntrypoints(config) {
|
|
|
2150
2211
|
let hasBackground = false;
|
|
2151
2212
|
const possibleEntrypoints = await Promise.all(
|
|
2152
2213
|
relativePaths.map(async (relativePath) => {
|
|
2153
|
-
const
|
|
2214
|
+
const path6 = resolve12(config.entrypointsDir, relativePath);
|
|
2154
2215
|
const matchingGlob = pathGlobs.find(
|
|
2155
2216
|
(glob4) => minimatch(relativePath, glob4)
|
|
2156
2217
|
);
|
|
@@ -2170,23 +2231,23 @@ ${JSON.stringify(
|
|
|
2170
2231
|
return;
|
|
2171
2232
|
switch (type) {
|
|
2172
2233
|
case "popup":
|
|
2173
|
-
return await getPopupEntrypoint(config,
|
|
2234
|
+
return await getPopupEntrypoint(config, path6);
|
|
2174
2235
|
case "options":
|
|
2175
|
-
return await getOptionsEntrypoint(config,
|
|
2236
|
+
return await getOptionsEntrypoint(config, path6);
|
|
2176
2237
|
case "background":
|
|
2177
2238
|
hasBackground = true;
|
|
2178
|
-
return await getBackgroundEntrypoint(config,
|
|
2239
|
+
return await getBackgroundEntrypoint(config, path6);
|
|
2179
2240
|
case "content-script":
|
|
2180
|
-
return await getContentScriptEntrypoint(config,
|
|
2241
|
+
return await getContentScriptEntrypoint(config, path6);
|
|
2181
2242
|
case "unlisted-page":
|
|
2182
|
-
return await getUnlistedPageEntrypoint(config,
|
|
2243
|
+
return await getUnlistedPageEntrypoint(config, path6);
|
|
2183
2244
|
case "unlisted-script":
|
|
2184
|
-
return await getUnlistedScriptEntrypoint(config,
|
|
2245
|
+
return await getUnlistedScriptEntrypoint(config, path6);
|
|
2185
2246
|
case "content-script-style":
|
|
2186
2247
|
return {
|
|
2187
2248
|
type,
|
|
2188
|
-
name: getEntrypointName(config.entrypointsDir,
|
|
2189
|
-
inputPath:
|
|
2249
|
+
name: getEntrypointName(config.entrypointsDir, path6),
|
|
2250
|
+
inputPath: path6,
|
|
2190
2251
|
outputDir: resolve12(config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
2191
2252
|
options: {
|
|
2192
2253
|
include: void 0,
|
|
@@ -2196,8 +2257,8 @@ ${JSON.stringify(
|
|
|
2196
2257
|
default:
|
|
2197
2258
|
return {
|
|
2198
2259
|
type,
|
|
2199
|
-
name: getEntrypointName(config.entrypointsDir,
|
|
2200
|
-
inputPath:
|
|
2260
|
+
name: getEntrypointName(config.entrypointsDir, path6),
|
|
2261
|
+
inputPath: path6,
|
|
2201
2262
|
outputDir: config.outDir,
|
|
2202
2263
|
options: {
|
|
2203
2264
|
include: void 0,
|
|
@@ -2260,8 +2321,8 @@ function getHtmlBaseOptions(document) {
|
|
|
2260
2321
|
}
|
|
2261
2322
|
return options;
|
|
2262
2323
|
}
|
|
2263
|
-
async function getPopupEntrypoint(config,
|
|
2264
|
-
const content = await fs12.readFile(
|
|
2324
|
+
async function getPopupEntrypoint(config, path6) {
|
|
2325
|
+
const content = await fs12.readFile(path6, "utf-8");
|
|
2265
2326
|
const { document } = parseHTML2(content);
|
|
2266
2327
|
const options = getHtmlBaseOptions(document);
|
|
2267
2328
|
const title = document.querySelector("title");
|
|
@@ -2290,12 +2351,12 @@ async function getPopupEntrypoint(config, path7) {
|
|
|
2290
2351
|
type: "popup",
|
|
2291
2352
|
name: "popup",
|
|
2292
2353
|
options,
|
|
2293
|
-
inputPath:
|
|
2354
|
+
inputPath: path6,
|
|
2294
2355
|
outputDir: config.outDir
|
|
2295
2356
|
};
|
|
2296
2357
|
}
|
|
2297
|
-
async function getOptionsEntrypoint(config,
|
|
2298
|
-
const content = await fs12.readFile(
|
|
2358
|
+
async function getOptionsEntrypoint(config, path6) {
|
|
2359
|
+
const content = await fs12.readFile(path6, "utf-8");
|
|
2299
2360
|
const { document } = parseHTML2(content);
|
|
2300
2361
|
const options = getHtmlBaseOptions(document);
|
|
2301
2362
|
const openInTabContent = document.querySelector("meta[name='manifest.open_in_tab']")?.getAttribute("content");
|
|
@@ -2314,25 +2375,25 @@ async function getOptionsEntrypoint(config, path7) {
|
|
|
2314
2375
|
type: "options",
|
|
2315
2376
|
name: "options",
|
|
2316
2377
|
options,
|
|
2317
|
-
inputPath:
|
|
2378
|
+
inputPath: path6,
|
|
2318
2379
|
outputDir: config.outDir
|
|
2319
2380
|
};
|
|
2320
2381
|
}
|
|
2321
|
-
async function getUnlistedPageEntrypoint(config,
|
|
2322
|
-
const content = await fs12.readFile(
|
|
2382
|
+
async function getUnlistedPageEntrypoint(config, path6) {
|
|
2383
|
+
const content = await fs12.readFile(path6, "utf-8");
|
|
2323
2384
|
const { document } = parseHTML2(content);
|
|
2324
2385
|
return {
|
|
2325
2386
|
type: "unlisted-page",
|
|
2326
|
-
name: getEntrypointName(config.entrypointsDir,
|
|
2327
|
-
inputPath:
|
|
2387
|
+
name: getEntrypointName(config.entrypointsDir, path6),
|
|
2388
|
+
inputPath: path6,
|
|
2328
2389
|
outputDir: config.outDir,
|
|
2329
2390
|
options: getHtmlBaseOptions(document)
|
|
2330
2391
|
};
|
|
2331
2392
|
}
|
|
2332
|
-
async function getUnlistedScriptEntrypoint(config,
|
|
2333
|
-
const name = getEntrypointName(config.entrypointsDir,
|
|
2393
|
+
async function getUnlistedScriptEntrypoint(config, path6) {
|
|
2394
|
+
const name = getEntrypointName(config.entrypointsDir, path6);
|
|
2334
2395
|
const defaultExport = await importEntrypointFile(
|
|
2335
|
-
|
|
2396
|
+
path6,
|
|
2336
2397
|
config
|
|
2337
2398
|
);
|
|
2338
2399
|
if (defaultExport == null) {
|
|
@@ -2345,17 +2406,17 @@ async function getUnlistedScriptEntrypoint(config, path7) {
|
|
|
2345
2406
|
return {
|
|
2346
2407
|
type: "unlisted-script",
|
|
2347
2408
|
name,
|
|
2348
|
-
inputPath:
|
|
2409
|
+
inputPath: path6,
|
|
2349
2410
|
outputDir: config.outDir,
|
|
2350
2411
|
options
|
|
2351
2412
|
};
|
|
2352
2413
|
}
|
|
2353
|
-
async function getBackgroundEntrypoint(config,
|
|
2414
|
+
async function getBackgroundEntrypoint(config, path6) {
|
|
2354
2415
|
const name = "background";
|
|
2355
2416
|
let options = {};
|
|
2356
|
-
if (
|
|
2417
|
+
if (path6 !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
|
|
2357
2418
|
const defaultExport = await importEntrypointFile(
|
|
2358
|
-
|
|
2419
|
+
path6,
|
|
2359
2420
|
config
|
|
2360
2421
|
);
|
|
2361
2422
|
if (defaultExport == null) {
|
|
@@ -2369,7 +2430,7 @@ async function getBackgroundEntrypoint(config, path7) {
|
|
|
2369
2430
|
return {
|
|
2370
2431
|
type: "background",
|
|
2371
2432
|
name,
|
|
2372
|
-
inputPath:
|
|
2433
|
+
inputPath: path6,
|
|
2373
2434
|
outputDir: config.outDir,
|
|
2374
2435
|
options: {
|
|
2375
2436
|
...options,
|
|
@@ -2378,9 +2439,9 @@ async function getBackgroundEntrypoint(config, path7) {
|
|
|
2378
2439
|
}
|
|
2379
2440
|
};
|
|
2380
2441
|
}
|
|
2381
|
-
async function getContentScriptEntrypoint(config,
|
|
2382
|
-
const name = getEntrypointName(config.entrypointsDir,
|
|
2383
|
-
const { main: _, ...options } = await importEntrypointFile(
|
|
2442
|
+
async function getContentScriptEntrypoint(config, path6) {
|
|
2443
|
+
const name = getEntrypointName(config.entrypointsDir, path6);
|
|
2444
|
+
const { main: _, ...options } = await importEntrypointFile(path6, config);
|
|
2384
2445
|
if (options == null) {
|
|
2385
2446
|
throw Error(
|
|
2386
2447
|
`${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
|
|
@@ -2389,7 +2450,7 @@ async function getContentScriptEntrypoint(config, path7) {
|
|
|
2389
2450
|
return {
|
|
2390
2451
|
type: "content-script",
|
|
2391
2452
|
name,
|
|
2392
|
-
inputPath:
|
|
2453
|
+
inputPath: path6,
|
|
2393
2454
|
outputDir: resolve12(config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
|
2394
2455
|
options
|
|
2395
2456
|
};
|
|
@@ -2438,9 +2499,12 @@ var PATH_GLOB_TO_TYPE_MAP = {
|
|
|
2438
2499
|
var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
|
|
2439
2500
|
|
|
2440
2501
|
export {
|
|
2502
|
+
detectDevChanges,
|
|
2441
2503
|
getEntrypointOutputFile,
|
|
2442
2504
|
getEntrypointBundlePath,
|
|
2443
2505
|
resolvePerBrowserOption,
|
|
2506
|
+
findEntrypoints,
|
|
2507
|
+
generateTypesDir,
|
|
2444
2508
|
formatDuration,
|
|
2445
2509
|
download,
|
|
2446
2510
|
unimport,
|
|
@@ -2448,9 +2512,6 @@ export {
|
|
|
2448
2512
|
globals,
|
|
2449
2513
|
webextensionPolyfillAlias,
|
|
2450
2514
|
webextensionPolyfillInlineDeps,
|
|
2451
|
-
detectDevChanges,
|
|
2452
|
-
findEntrypoints,
|
|
2453
|
-
generateTypesDir,
|
|
2454
2515
|
getInternalConfig,
|
|
2455
2516
|
kebabCaseAlphanumeric,
|
|
2456
2517
|
printFileList,
|