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