@crxjs/vite-plugin 2.0.0-beta.2 → 2.0.0-beta.22
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/client.d.ts +15 -0
- package/dist/index.cjs +0 -1848
- package/dist/index.d.ts +33 -12
- package/dist/index.mjs +249 -76
- package/package.json +22 -20
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { simple } from 'acorn-walk';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
|
-
import debug$
|
|
3
|
+
import debug$3 from 'debug';
|
|
4
4
|
import v8 from 'v8';
|
|
5
5
|
import { posix } from 'path';
|
|
6
|
-
import { Subject, filter, ReplaySubject, switchMap, of, startWith, map, mergeMap, firstValueFrom, takeUntil, first, toArray, retry, concatWith, Subscription, buffer } from 'rxjs';
|
|
6
|
+
import { Subject, filter, ReplaySubject, switchMap, of, startWith, map, BehaviorSubject, mergeMap, firstValueFrom, takeUntil, first, toArray, retry, concatWith, Subscription, buffer } from 'rxjs';
|
|
7
7
|
import fsx from 'fs-extra';
|
|
8
8
|
import { performance } from 'perf_hooks';
|
|
9
9
|
import { rollup } from 'rollup';
|
|
10
10
|
import * as lexer from 'es-module-lexer';
|
|
11
11
|
import { readFile as readFile$1 } from 'fs/promises';
|
|
12
12
|
import MagicString from 'magic-string';
|
|
13
|
-
import
|
|
13
|
+
import convertSourceMap from 'convert-source-map';
|
|
14
|
+
import { createLogger, version } from 'vite';
|
|
14
15
|
import { readFileSync, existsSync, promises } from 'fs';
|
|
15
16
|
import { createRequire } from 'module';
|
|
16
17
|
import fg from 'fast-glob';
|
|
17
|
-
import getPort, { portNumbers } from 'get-port';
|
|
18
18
|
import { load } from 'cheerio';
|
|
19
19
|
import jsesc from 'jsesc';
|
|
20
20
|
import colors from 'picocolors';
|
|
@@ -25,17 +25,22 @@ const pluginOptionsProvider = (options) => {
|
|
|
25
25
|
name: pluginName$1,
|
|
26
26
|
api: {
|
|
27
27
|
crx: {
|
|
28
|
+
// during testing this can be null, we don't provide options through the test config
|
|
28
29
|
options
|
|
29
30
|
}
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
32
|
}
|
|
31
33
|
};
|
|
32
34
|
};
|
|
33
|
-
const getOptions = ({
|
|
35
|
+
const getOptions = async ({
|
|
36
|
+
plugins
|
|
37
|
+
}) => {
|
|
34
38
|
if (typeof plugins === "undefined") {
|
|
35
39
|
throw new Error("config.plugins is undefined");
|
|
36
40
|
}
|
|
41
|
+
const awaitedPlugins = await Promise.all(plugins);
|
|
37
42
|
let options;
|
|
38
|
-
for (const p of
|
|
43
|
+
for (const p of awaitedPlugins.flat()) {
|
|
39
44
|
if (isCrxPlugin(p)) {
|
|
40
45
|
if (p.name === pluginName$1) {
|
|
41
46
|
const plugin = p;
|
|
@@ -56,7 +61,7 @@ function isCrxPlugin(p) {
|
|
|
56
61
|
|
|
57
62
|
var workerHmrClient = "const ownOrigin = new URL(chrome.runtime.getURL(\"/\")).origin;\nself.addEventListener(\"fetch\", (fetchEvent) => {\n const url = new URL(fetchEvent.request.url);\n if (url.origin === ownOrigin) {\n fetchEvent.respondWith(sendToServer(url));\n }\n});\nasync function sendToServer(url) {\n url.protocol = \"http:\";\n url.host = \"localhost\";\n url.port = __SERVER_PORT__;\n url.searchParams.set(\"t\", Date.now().toString());\n const response = await fetch(url.href.replace(/=$|=(?=&)/g, \"\"));\n return new Response(response.body, {\n headers: {\n \"Content-Type\": response.headers.get(\"Content-Type\") ?? \"text/javascript\"\n }\n });\n}\nconst ports = /* @__PURE__ */ new Set();\nchrome.runtime.onConnect.addListener((port) => {\n if (port.name === \"@crx/client\") {\n ports.add(port);\n port.onDisconnect.addListener((port2) => ports.delete(port2));\n port.onMessage.addListener((message) => {\n });\n port.postMessage({ data: JSON.stringify({ type: \"connected\" }) });\n }\n});\nfunction notifyContentScripts(payload) {\n const data = JSON.stringify(payload);\n for (const port of ports)\n port.postMessage({ data });\n}\nconsole.log(\"[vite] connecting...\");\nconst socketProtocol = __HMR_PROTOCOL__ || (location.protocol === \"https:\" ? \"wss\" : \"ws\");\nconst socketHost = `${__HMR_HOSTNAME__ || location.hostname}:${__HMR_PORT__}`;\nconst socket = new WebSocket(`${socketProtocol}://${socketHost}`, \"vite-hmr\");\nconst base = __BASE__ || \"/\";\nsocket.addEventListener(\"message\", async ({ data }) => {\n handleSocketMessage(JSON.parse(data));\n});\nfunction isCrxHmrPayload(x) {\n return x.type === \"custom\" && x.event.startsWith(\"crx:\");\n}\nfunction handleSocketMessage(payload) {\n if (isCrxHmrPayload(payload)) {\n handleCrxHmrPayload(payload);\n } else if (payload.type === \"connected\") {\n console.log(`[vite] connected.`);\n const interval = setInterval(() => socket.send(\"ping\"), __HMR_TIMEOUT__);\n socket.addEventListener(\"close\", () => clearInterval(interval));\n }\n}\nfunction handleCrxHmrPayload(payload) {\n notifyContentScripts(payload);\n switch (payload.event) {\n case \"crx:runtime-reload\":\n console.log(\"[crx] runtime reload\");\n chrome.runtime.reload();\n break;\n }\n}\nasync function waitForSuccessfulPing(ms = 1e3) {\n while (true) {\n try {\n await fetch(`${base}__vite_ping`);\n break;\n } catch (e) {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n }\n}\nsocket.addEventListener(\"close\", async ({ wasClean }) => {\n if (wasClean)\n return;\n console.log(`[vite] server connection lost. polling for restart...`);\n await waitForSuccessfulPing();\n handleCrxHmrPayload({\n type: \"custom\",\n event: \"crx:runtime-reload\"\n });\n});\n";
|
|
58
63
|
|
|
59
|
-
const _debug = (id) => debug$
|
|
64
|
+
const _debug = (id) => debug$3("crx").extend(id);
|
|
60
65
|
const structuredClone = (obj) => {
|
|
61
66
|
return v8.deserialize(v8.serialize(obj));
|
|
62
67
|
};
|
|
@@ -202,7 +207,7 @@ function formatFileData(script) {
|
|
|
202
207
|
return script;
|
|
203
208
|
}
|
|
204
209
|
function getFileName({ type, id }) {
|
|
205
|
-
let fileName = id.replace(/t=\d+&/, "").replace(/^\//, "").replace(/\?/g, "__").replace(/&/g, "_").replace(/=/g, "--");
|
|
210
|
+
let fileName = id.replace(/t=\d+&/, "").replace(/\?t=\d+$/, "").replace(/^\//, "").replace(/\?/g, "__").replace(/&/g, "_").replace(/=/g, "--");
|
|
206
211
|
if (fileName.includes("node_modules/")) {
|
|
207
212
|
fileName = `vendor/${fileName.split("node_modules/").pop().replace(/\//g, "-")}`;
|
|
208
213
|
} else if (fileName.startsWith("@")) {
|
|
@@ -270,6 +275,7 @@ const workerClientId = "/@crx/client-worker";
|
|
|
270
275
|
|
|
271
276
|
const pluginBackground = () => {
|
|
272
277
|
let config;
|
|
278
|
+
let browser;
|
|
273
279
|
return [
|
|
274
280
|
{
|
|
275
281
|
name: "crx:background-client",
|
|
@@ -290,24 +296,39 @@ const pluginBackground = () => {
|
|
|
290
296
|
},
|
|
291
297
|
{
|
|
292
298
|
name: "crx:background-loader-file",
|
|
299
|
+
// this should happen after other plugins; the loader file is an implementation detail
|
|
293
300
|
enforce: "post",
|
|
301
|
+
async config(config2) {
|
|
302
|
+
const opts = await getOptions(config2);
|
|
303
|
+
browser = opts.browser || "chrome";
|
|
304
|
+
},
|
|
294
305
|
configResolved(_config) {
|
|
295
306
|
config = _config;
|
|
296
307
|
},
|
|
297
308
|
renderCrxManifest(manifest) {
|
|
298
|
-
const worker = manifest.background?.service_worker;
|
|
309
|
+
const worker = browser === "firefox" ? manifest.background?.scripts[0] : manifest.background?.service_worker;
|
|
299
310
|
let loader;
|
|
300
311
|
if (config.command === "serve") {
|
|
301
312
|
const port = config.server.port?.toString();
|
|
302
313
|
if (typeof port === "undefined")
|
|
303
314
|
throw new Error("server port is undefined in watch mode");
|
|
304
|
-
|
|
315
|
+
if (browser === "firefox") {
|
|
316
|
+
loader = `import('http://localhost:${port}/@vite/env');
|
|
317
|
+
`;
|
|
318
|
+
loader += `import('http://localhost:${port}${workerClientId}');
|
|
319
|
+
`;
|
|
320
|
+
if (worker)
|
|
321
|
+
loader += `import('http://localhost:${port}/${worker}');
|
|
322
|
+
`;
|
|
323
|
+
} else {
|
|
324
|
+
loader = `import 'http://localhost:${port}/@vite/env';
|
|
305
325
|
`;
|
|
306
|
-
|
|
326
|
+
loader += `import 'http://localhost:${port}${workerClientId}';
|
|
307
327
|
`;
|
|
308
|
-
|
|
309
|
-
|
|
328
|
+
if (worker)
|
|
329
|
+
loader += `import 'http://localhost:${port}/${worker}';
|
|
310
330
|
`;
|
|
331
|
+
}
|
|
311
332
|
} else if (worker) {
|
|
312
333
|
loader = `import './${worker}';
|
|
313
334
|
`;
|
|
@@ -316,13 +337,21 @@ const pluginBackground = () => {
|
|
|
316
337
|
}
|
|
317
338
|
const refId = this.emitFile({
|
|
318
339
|
type: "asset",
|
|
340
|
+
// fileName b/c service worker must be at root of crx
|
|
319
341
|
fileName: getFileName({ type: "loader", id: "service-worker" }),
|
|
320
342
|
source: loader
|
|
321
343
|
});
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
344
|
+
if (browser !== "firefox") {
|
|
345
|
+
manifest.background = {
|
|
346
|
+
service_worker: this.getFileName(refId),
|
|
347
|
+
type: "module"
|
|
348
|
+
};
|
|
349
|
+
} else {
|
|
350
|
+
manifest.background = {
|
|
351
|
+
scripts: [this.getFileName(refId)],
|
|
352
|
+
type: "module"
|
|
353
|
+
};
|
|
354
|
+
}
|
|
326
355
|
return manifest;
|
|
327
356
|
}
|
|
328
357
|
}
|
|
@@ -331,9 +360,9 @@ const pluginBackground = () => {
|
|
|
331
360
|
|
|
332
361
|
var contentHmrPort = "function isCrxHMRPayload(x) {\n return x.type === \"custom\" && x.event.startsWith(\"crx:\");\n}\nclass HMRPort {\n port;\n callbacks = /* @__PURE__ */ new Map();\n constructor() {\n setInterval(() => {\n try {\n this.port?.postMessage({ data: \"ping\" });\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Extension context invalidated.\")) {\n location.reload();\n } else\n throw error;\n }\n }, __CRX_HMR_TIMEOUT__);\n setInterval(this.initPort, 5 * 60 * 1e3);\n this.initPort();\n }\n initPort = () => {\n this.port?.disconnect();\n this.port = chrome.runtime.connect({ name: \"@crx/client\" });\n this.port.onDisconnect.addListener(this.handleDisconnect.bind(this));\n this.port.onMessage.addListener(this.handleMessage.bind(this));\n this.port.postMessage({ type: \"connected\" });\n };\n handleDisconnect = () => {\n if (this.callbacks.has(\"close\"))\n for (const cb of this.callbacks.get(\"close\")) {\n cb({ wasClean: true });\n }\n };\n handleMessage = (message) => {\n const forward = (data) => {\n if (this.callbacks.has(\"message\"))\n for (const cb of this.callbacks.get(\"message\")) {\n cb({ data });\n }\n };\n const payload = JSON.parse(message.data);\n if (isCrxHMRPayload(payload)) {\n if (payload.event === \"crx:runtime-reload\") {\n console.log(\"[crx] runtime reload\");\n setTimeout(() => location.reload(), 500);\n } else {\n forward(JSON.stringify(payload.data));\n }\n } else {\n forward(message.data);\n }\n };\n addEventListener = (event, callback) => {\n const cbs = this.callbacks.get(event) ?? /* @__PURE__ */ new Set();\n cbs.add(callback);\n this.callbacks.set(event, cbs);\n };\n send = (data) => {\n if (this.port)\n this.port.postMessage({ data });\n else\n throw new Error(\"HMRPort is not initialized\");\n };\n}\n\nexport { HMRPort };\n";
|
|
333
362
|
|
|
334
|
-
var contentDevLoader = "(function () {\n 'use strict';\n\n (async () => {\n if (__PREAMBLE__)\n await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__PREAMBLE__)\n );\n await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__CLIENT__)\n );\n await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__SCRIPT__)\n );\n })().catch(console.error);\n\n})();\n";
|
|
363
|
+
var contentDevLoader = "(function () {\n 'use strict';\n\n const injectTime = performance.now();\n (async () => {\n if (__PREAMBLE__)\n await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__PREAMBLE__)\n );\n await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__CLIENT__)\n );\n const { onExecute } = await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__SCRIPT__)\n );\n onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } });\n })().catch(console.error);\n\n})();\n";
|
|
335
364
|
|
|
336
|
-
var contentProLoader = "(function () {\n 'use strict';\n\n (async () => {\n await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__SCRIPT__)\n );\n })().catch(console.error);\n\n})();\n";
|
|
365
|
+
var contentProLoader = "(function () {\n 'use strict';\n\n const injectTime = performance.now();\n (async () => {\n const { onExecute } = await import(\n /* @vite-ignore */\n chrome.runtime.getURL(__SCRIPT__)\n );\n onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } });\n })().catch(console.error);\n\n})();\n";
|
|
337
366
|
|
|
338
367
|
const contentScripts = new RxMap();
|
|
339
368
|
contentScripts.change$.pipe(filter(RxMap.isChangeType.set)).subscribe(({ map, value }) => {
|
|
@@ -391,6 +420,10 @@ const allFilesReady$ = buildEnd$.pipe(
|
|
|
391
420
|
map(() => [...outputFiles.values()]),
|
|
392
421
|
switchMap((files) => Promise.allSettled(files.map(({ file }) => file)))
|
|
393
422
|
);
|
|
423
|
+
const timestamp$ = new BehaviorSubject(Date.now());
|
|
424
|
+
allFilesReady$.subscribe(() => {
|
|
425
|
+
timestamp$.next(Date.now());
|
|
426
|
+
});
|
|
394
427
|
const isRejected = (x) => x?.status === "rejected";
|
|
395
428
|
const fileWriterError$ = allFilesReady$.pipe(
|
|
396
429
|
mergeMap((results) => results.filter(isRejected)),
|
|
@@ -424,16 +457,36 @@ function prepAsset(fileName, { id, source }) {
|
|
|
424
457
|
}
|
|
425
458
|
function prepScript(fileName, script) {
|
|
426
459
|
return ($) => $.pipe(
|
|
460
|
+
// get script contents from dev server
|
|
427
461
|
mergeMap(async ({ server }) => {
|
|
428
462
|
const target = getOutputPath(server, fileName);
|
|
429
463
|
const viteUrl = getViteUrl(script);
|
|
430
464
|
const transformResult = await server.transformRequest(viteUrl);
|
|
431
465
|
if (!transformResult)
|
|
432
466
|
throw new TypeError(`Unable to load "${script.id}" from server.`);
|
|
433
|
-
const {
|
|
434
|
-
|
|
467
|
+
const { deps = [], dynamicDeps = [], map: map2 } = transformResult;
|
|
468
|
+
let { code } = transformResult;
|
|
469
|
+
try {
|
|
470
|
+
if (map2 && server.config.build.sourcemap === "inline") {
|
|
471
|
+
code = code.replace(/\n*\/\/# sourceMappingURL=[^\n]+/g, "");
|
|
472
|
+
const sourceMap = convertSourceMap.fromObject(map2).toComment();
|
|
473
|
+
code += `
|
|
474
|
+
${sourceMap}
|
|
475
|
+
`;
|
|
476
|
+
}
|
|
477
|
+
} catch (error) {
|
|
478
|
+
console.warn("Failed to inline source map", error);
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
target,
|
|
482
|
+
code,
|
|
483
|
+
deps: [...deps, ...dynamicDeps].flat(),
|
|
484
|
+
server
|
|
485
|
+
};
|
|
435
486
|
}),
|
|
487
|
+
// retry in case of dependency rebundle
|
|
436
488
|
retry({ count: 10, delay: 100 }),
|
|
489
|
+
// patch content scripts
|
|
437
490
|
mergeMap(async ({ target, server, ...rest }) => {
|
|
438
491
|
const plugins = server.config.plugins;
|
|
439
492
|
let { code, deps } = rest;
|
|
@@ -453,7 +506,8 @@ function prepScript(fileName, script) {
|
|
|
453
506
|
if (i.n) {
|
|
454
507
|
depSet.add(i.n);
|
|
455
508
|
const fileName2 = getFileName({ type: "module", id: i.n });
|
|
456
|
-
|
|
509
|
+
const fullImport = code.substring(i.s, i.e);
|
|
510
|
+
magic.overwrite(i.s, i.e, fullImport.replace(i.n, `/${fileName2}`));
|
|
457
511
|
}
|
|
458
512
|
return { target, source: magic.toString(), deps: [...depSet] };
|
|
459
513
|
})
|
|
@@ -524,8 +578,11 @@ function update(_id) {
|
|
|
524
578
|
async function write(fileId) {
|
|
525
579
|
const start2 = performance.now();
|
|
526
580
|
const deps = await firstValueFrom(
|
|
581
|
+
// wait for start event
|
|
527
582
|
start$.pipe(
|
|
583
|
+
// prepare either asset or script contents
|
|
528
584
|
prepFileData(fileId),
|
|
585
|
+
// output file and add dependencies to file writer
|
|
529
586
|
mergeMap(async ({ target, source, deps: deps2 }) => {
|
|
530
587
|
const files = deps2.map((id) => {
|
|
531
588
|
const r = [add({ id, type: "module" })];
|
|
@@ -541,6 +598,7 @@ async function write(fileId) {
|
|
|
541
598
|
await outputFile(target, source, { encoding: "utf8" });
|
|
542
599
|
return files;
|
|
543
600
|
}),
|
|
601
|
+
// abort write operation on close event
|
|
544
602
|
takeUntil(close$),
|
|
545
603
|
concatWith(of([]))
|
|
546
604
|
)
|
|
@@ -558,15 +616,15 @@ const pluginContentScripts = () => {
|
|
|
558
616
|
{
|
|
559
617
|
name: "crx:content-scripts",
|
|
560
618
|
apply: "serve",
|
|
561
|
-
config(config) {
|
|
562
|
-
const { contentScripts: contentScripts2 = {} } = getOptions(config);
|
|
619
|
+
async config(config) {
|
|
620
|
+
const { contentScripts: contentScripts2 = {} } = await getOptions(config);
|
|
563
621
|
hmrTimeout = contentScripts2.hmrTimeout ?? 5e3;
|
|
564
622
|
preambleCode = preambleCode ?? contentScripts2.preambleCode;
|
|
565
623
|
},
|
|
566
624
|
async configureServer(_server) {
|
|
567
625
|
server = _server;
|
|
568
626
|
if (typeof preambleCode === "undefined" && server.config.plugins.some(
|
|
569
|
-
({ name = "none" }) => name.toLowerCase().includes("react")
|
|
627
|
+
({ name = "none" }) => name.toLowerCase().includes("react") && !name.toLowerCase().includes("preact")
|
|
570
628
|
)) {
|
|
571
629
|
try {
|
|
572
630
|
const react = await import('@vitejs/plugin-react');
|
|
@@ -631,6 +689,19 @@ const pluginContentScripts = () => {
|
|
|
631
689
|
name: "crx:content-scripts",
|
|
632
690
|
apply: "build",
|
|
633
691
|
enforce: "pre",
|
|
692
|
+
config(config) {
|
|
693
|
+
return {
|
|
694
|
+
...config,
|
|
695
|
+
build: {
|
|
696
|
+
...config.build,
|
|
697
|
+
rollupOptions: {
|
|
698
|
+
...config.build?.rollupOptions,
|
|
699
|
+
// keep exports for content script module api
|
|
700
|
+
preserveEntrySignatures: config.build?.rollupOptions?.preserveEntrySignatures ?? "exports-only"
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
},
|
|
634
705
|
generateBundle() {
|
|
635
706
|
for (const [key, script] of contentScripts)
|
|
636
707
|
if (key === script.refId) {
|
|
@@ -661,8 +732,8 @@ const pluginContentScriptsCss = () => {
|
|
|
661
732
|
return {
|
|
662
733
|
name: "crx:content-scripts-css",
|
|
663
734
|
enforce: "post",
|
|
664
|
-
config(config) {
|
|
665
|
-
const { contentScripts: contentScripts2 = {} } = getOptions(config);
|
|
735
|
+
async config(config) {
|
|
736
|
+
const { contentScripts: contentScripts2 = {} } = await getOptions(config);
|
|
666
737
|
injectCss = contentScripts2.injectCss ?? true;
|
|
667
738
|
},
|
|
668
739
|
renderCrxManifest(manifest) {
|
|
@@ -691,7 +762,7 @@ const pluginDeclaredContentScripts = () => {
|
|
|
691
762
|
return [];
|
|
692
763
|
};
|
|
693
764
|
|
|
694
|
-
const _dynamicScriptRegEx = /\b(import.meta).CRX_DYNAMIC_SCRIPT_(.+?)
|
|
765
|
+
const _dynamicScriptRegEx = /\b(import.meta).CRX_DYNAMIC_SCRIPT_(.+?)[,;]/gm;
|
|
695
766
|
const dynamicScriptRegEx = () => {
|
|
696
767
|
_dynamicScriptRegEx.lastIndex = 0;
|
|
697
768
|
return _dynamicScriptRegEx;
|
|
@@ -705,6 +776,34 @@ const pluginDynamicContentScripts = () => {
|
|
|
705
776
|
configResolved(_config) {
|
|
706
777
|
config = _config;
|
|
707
778
|
},
|
|
779
|
+
configureServer(server) {
|
|
780
|
+
return () => {
|
|
781
|
+
server.middlewares.use(async (req, res, next) => {
|
|
782
|
+
try {
|
|
783
|
+
await allFilesReady();
|
|
784
|
+
next();
|
|
785
|
+
} catch (error) {
|
|
786
|
+
let err;
|
|
787
|
+
if (error instanceof Error) {
|
|
788
|
+
err = error;
|
|
789
|
+
} else if (typeof error === "string") {
|
|
790
|
+
err = new Error(error);
|
|
791
|
+
} else {
|
|
792
|
+
err = new Error(
|
|
793
|
+
`Unexpected error "${error}" in middleware for "${req.url}"`
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
server.ws.send({
|
|
797
|
+
type: "error",
|
|
798
|
+
err: {
|
|
799
|
+
message: err.message,
|
|
800
|
+
stack: err.stack ?? "no stack available"
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
};
|
|
806
|
+
},
|
|
708
807
|
async resolveId(_source, importer) {
|
|
709
808
|
if (importer && _source.includes("?script")) {
|
|
710
809
|
const url = new URL(_source, "stub://stub");
|
|
@@ -773,7 +872,6 @@ const pluginDynamicContentScripts = () => {
|
|
|
773
872
|
if (config.command === "build") {
|
|
774
873
|
return `export default import.meta.CRX_DYNAMIC_SCRIPT_${script.refId};`;
|
|
775
874
|
} else if (typeof script.fileName === "string") {
|
|
776
|
-
await fileReady(script);
|
|
777
875
|
return `export default ${JSON.stringify(script.fileName)};`;
|
|
778
876
|
} else {
|
|
779
877
|
throw new Error(
|
|
@@ -786,6 +884,12 @@ const pluginDynamicContentScripts = () => {
|
|
|
786
884
|
{
|
|
787
885
|
name: "crx:dynamic-content-scripts-build",
|
|
788
886
|
apply: "build",
|
|
887
|
+
/**
|
|
888
|
+
* Replace dynamic script placeholders during build.
|
|
889
|
+
*
|
|
890
|
+
* Can't use `renderChunk` b/c pre plugin crx:content-scripts uses
|
|
891
|
+
* `generateBundle` to emit loaders. Must come after "enforce: pre".
|
|
892
|
+
*/
|
|
789
893
|
generateBundle(options, bundle) {
|
|
790
894
|
for (const chunk of Object.values(bundle))
|
|
791
895
|
if (chunk.type === "chunk") {
|
|
@@ -804,7 +908,7 @@ const pluginDynamicContentScripts = () => {
|
|
|
804
908
|
);
|
|
805
909
|
return `${JSON.stringify(
|
|
806
910
|
`/${script.loaderName ?? script.fileName}`
|
|
807
|
-
)}
|
|
911
|
+
)}${match.split(scriptKey)[1]}`;
|
|
808
912
|
}
|
|
809
913
|
);
|
|
810
914
|
chunk.code = replaced;
|
|
@@ -815,29 +919,42 @@ const pluginDynamicContentScripts = () => {
|
|
|
815
919
|
];
|
|
816
920
|
};
|
|
817
921
|
|
|
922
|
+
const { remove } = fsx;
|
|
818
923
|
const logger = createLogger("error", { prefix: "crxjs" });
|
|
819
924
|
const pluginFileWriter = () => {
|
|
820
925
|
fileWriterError$.subscribe((error) => {
|
|
821
926
|
logger.error(error.err.message, { error: error.err });
|
|
822
927
|
});
|
|
823
|
-
return
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
console.error(error);
|
|
832
|
-
server.close();
|
|
928
|
+
return [
|
|
929
|
+
{
|
|
930
|
+
name: "crx:file-writer-empty-out-dir",
|
|
931
|
+
apply: "serve",
|
|
932
|
+
enforce: "pre",
|
|
933
|
+
async configResolved(config) {
|
|
934
|
+
if (config.build.emptyOutDir) {
|
|
935
|
+
await remove(config.build.outDir);
|
|
833
936
|
}
|
|
834
|
-
}
|
|
835
|
-
server.httpServer?.on("close", () => close());
|
|
937
|
+
}
|
|
836
938
|
},
|
|
837
|
-
|
|
838
|
-
|
|
939
|
+
{
|
|
940
|
+
name: "crx:file-writer",
|
|
941
|
+
apply: "serve",
|
|
942
|
+
configureServer(server) {
|
|
943
|
+
server.httpServer?.on("listening", async () => {
|
|
944
|
+
try {
|
|
945
|
+
await start({ server });
|
|
946
|
+
} catch (error) {
|
|
947
|
+
console.error(error);
|
|
948
|
+
server.close();
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
server.httpServer?.on("close", () => close());
|
|
952
|
+
},
|
|
953
|
+
closeBundle() {
|
|
954
|
+
outputFiles.clear();
|
|
955
|
+
}
|
|
839
956
|
}
|
|
840
|
-
|
|
957
|
+
];
|
|
841
958
|
};
|
|
842
959
|
|
|
843
960
|
const _require = typeof require === "undefined" ? createRequire(import.meta.url) : require;
|
|
@@ -882,7 +999,9 @@ async function manifestFiles(manifest, options = {}) {
|
|
|
882
999
|
) ?? [];
|
|
883
1000
|
const contentScripts = manifest.content_scripts?.flatMap(({ js }) => js) ?? [];
|
|
884
1001
|
const contentStyles = manifest.content_scripts?.flatMap(({ css }) => css);
|
|
885
|
-
const serviceWorker = manifest.background
|
|
1002
|
+
const serviceWorker = manifest.background && "service_worker" in manifest.background ? manifest.background.service_worker : void 0;
|
|
1003
|
+
const backgroundScripts = manifest.background && "scripts" in manifest.background ? manifest.background.scripts : void 0;
|
|
1004
|
+
const background = serviceWorker ? [serviceWorker].filter(isString) : backgroundScripts ? backgroundScripts.filter(isString) : [];
|
|
886
1005
|
const htmlPages = htmlFiles(manifest);
|
|
887
1006
|
const icons = [
|
|
888
1007
|
Object.values(
|
|
@@ -903,7 +1022,7 @@ async function manifestFiles(manifest, options = {}) {
|
|
|
903
1022
|
return r;
|
|
904
1023
|
})
|
|
905
1024
|
);
|
|
906
|
-
webAccessibleResources = resources.flat().filter(isString);
|
|
1025
|
+
webAccessibleResources = [...new Set(resources.flat())].filter(isString);
|
|
907
1026
|
}
|
|
908
1027
|
return {
|
|
909
1028
|
contentScripts: [...new Set(contentScripts)].filter(isString),
|
|
@@ -912,7 +1031,7 @@ async function manifestFiles(manifest, options = {}) {
|
|
|
912
1031
|
icons: [...new Set(icons)].filter(isString),
|
|
913
1032
|
locales: [...new Set(locales)].filter(isString),
|
|
914
1033
|
rulesets: [...new Set(rulesets)].filter(isString),
|
|
915
|
-
background
|
|
1034
|
+
background,
|
|
916
1035
|
webAccessibleResources
|
|
917
1036
|
};
|
|
918
1037
|
}
|
|
@@ -927,7 +1046,8 @@ function htmlFiles(manifest) {
|
|
|
927
1046
|
manifest.devtools_page,
|
|
928
1047
|
manifest.options_page,
|
|
929
1048
|
manifest.options_ui?.page,
|
|
930
|
-
manifest.sandbox?.pages
|
|
1049
|
+
manifest.sandbox?.pages,
|
|
1050
|
+
manifest.side_panel?.default_path
|
|
931
1051
|
].flat().filter(isString).map((s) => s.split("#")[0]).sort();
|
|
932
1052
|
return [...new Set(files)];
|
|
933
1053
|
}
|
|
@@ -952,11 +1072,13 @@ const pluginFileWriterPublic = () => {
|
|
|
952
1072
|
};
|
|
953
1073
|
};
|
|
954
1074
|
|
|
955
|
-
_debug("file-writer").extend("hmr");
|
|
956
|
-
const
|
|
1075
|
+
const debug$2 = _debug("file-writer").extend("hmr");
|
|
1076
|
+
const isCustomPayload = (p) => {
|
|
1077
|
+
return p.type === "custom";
|
|
1078
|
+
};
|
|
957
1079
|
const hmrPayload$ = new Subject();
|
|
958
1080
|
const crxHMRPayload$ = hmrPayload$.pipe(
|
|
959
|
-
filter((p) => !
|
|
1081
|
+
filter((p) => !isCustomPayload(p)),
|
|
960
1082
|
buffer(allFilesReady$),
|
|
961
1083
|
mergeMap((pps) => {
|
|
962
1084
|
let fullReload;
|
|
@@ -1015,6 +1137,7 @@ const crxHMRPayload$ = hmrPayload$.pipe(
|
|
|
1015
1137
|
}
|
|
1016
1138
|
}),
|
|
1017
1139
|
map((data) => {
|
|
1140
|
+
debug$2(`hmr payload`, data);
|
|
1018
1141
|
return {
|
|
1019
1142
|
type: "custom",
|
|
1020
1143
|
event: "crx:content-script-payload",
|
|
@@ -1054,6 +1177,7 @@ const pluginHMR = () => {
|
|
|
1054
1177
|
name: "crx:hmr",
|
|
1055
1178
|
apply: "serve",
|
|
1056
1179
|
enforce: "pre",
|
|
1180
|
+
// server hmr host should be localhost
|
|
1057
1181
|
async config({ server = {}, ...config2 }) {
|
|
1058
1182
|
if (server.hmr === false)
|
|
1059
1183
|
return;
|
|
@@ -1061,9 +1185,9 @@ const pluginHMR = () => {
|
|
|
1061
1185
|
server.hmr = {};
|
|
1062
1186
|
server.hmr = server.hmr ?? {};
|
|
1063
1187
|
server.hmr.host = "localhost";
|
|
1064
|
-
server.hmr.port = server.hmr.port ?? await getPort({ port: portNumbers(5200, 5300) });
|
|
1065
1188
|
return { server, ...config2 };
|
|
1066
1189
|
},
|
|
1190
|
+
// server should ignore outdir
|
|
1067
1191
|
configResolved(_config) {
|
|
1068
1192
|
config = _config;
|
|
1069
1193
|
const { watch = {} } = config.server;
|
|
@@ -1101,6 +1225,7 @@ const pluginHMR = () => {
|
|
|
1101
1225
|
closeBundle() {
|
|
1102
1226
|
subs.unsubscribe();
|
|
1103
1227
|
},
|
|
1228
|
+
// background changes require a full extension reload
|
|
1104
1229
|
handleHotUpdate({ modules, server }) {
|
|
1105
1230
|
const { root } = server.config;
|
|
1106
1231
|
const relFiles = /* @__PURE__ */ new Set();
|
|
@@ -1128,6 +1253,7 @@ const pluginHMR = () => {
|
|
|
1128
1253
|
name: "crx:hmr",
|
|
1129
1254
|
apply: "serve",
|
|
1130
1255
|
enforce: "post",
|
|
1256
|
+
// get final output manifest for handleHotUpdate 👆
|
|
1131
1257
|
async transformCrxManifest(manifest) {
|
|
1132
1258
|
inputManifestFiles = await manifestFiles(manifest, { cwd: config.root });
|
|
1133
1259
|
return null;
|
|
@@ -1218,6 +1344,7 @@ const pluginHtmlInlineScripts = () => {
|
|
|
1218
1344
|
};
|
|
1219
1345
|
const postPlugin = {
|
|
1220
1346
|
name: "crx:html-auditor-post",
|
|
1347
|
+
// this hook isn't audited b/c we add it after we set up the auditors
|
|
1221
1348
|
transformIndexHtml(html, ctx) {
|
|
1222
1349
|
const key = toKey(ctx);
|
|
1223
1350
|
const p = pages.get(key);
|
|
@@ -1283,9 +1410,9 @@ const pluginHtmlInlineScripts = () => {
|
|
|
1283
1410
|
};
|
|
1284
1411
|
};
|
|
1285
1412
|
|
|
1286
|
-
var
|
|
1413
|
+
var loadingPageScript = "const VITE_URL = \"http://localhost:%PORT%\";\ndocument.body.innerHTML = `\n<div\n id=\"app\"\n style=\"\n border: 1px solid #ddd;\n padding: 20px;\n border-radius: 5px;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n \"\n >\n <h1 style=\"color: #333\">Vite Dev Mode</h1>\n <p style=\"color: #666\">\n Cannot connect to the Vite Dev Server on <a href=\"${VITE_URL}\">${VITE_URL}</a>\n </p>\n <p style=\"color: #666\">\n Double-check that Vite is working and reload the extension.\n </p>\n <p style=\"color: #666\">\n This page will close when the extension reloads.\n </p>\n <button\n style=\"\n padding: 10px 20px;\n border: none;\n background-color: #007bff;\n color: #fff;\n border-radius: 5px;\n cursor: pointer;\n \"\n >\n Reload Extension\n </button>\n </div>`;\ndocument.body.querySelector(\"button\")?.addEventListener(\"click\", () => {\n chrome.runtime.reload();\n});\nlet tries = 0;\nlet ready = false;\ndo {\n try {\n await fetch(VITE_URL);\n ready = true;\n } catch {\n const timeout = Math.min(100 * Math.pow(2, ++tries), 5e3);\n console.log(`[CRXJS] Vite Dev Server is not available on ${VITE_URL}`);\n console.log(`[CRXJS] Retrying in ${timeout}ms...`);\n await new Promise((resolve) => setTimeout(resolve, timeout));\n }\n} while (!ready);\nlocation.reload();\n";
|
|
1287
1414
|
|
|
1288
|
-
var
|
|
1415
|
+
var loadingPageHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>Vite Dev Mode</title>\n <script src=\"%SCRIPT%\" type=\"module\"></script>\n </head>\n <body\n style=\"font-family: Arial, sans-serif; padding: 20px; text-align: center\"\n >\n <h1>Vite Dev Mode</h1>\n </body>\n</html>\n";
|
|
1289
1416
|
|
|
1290
1417
|
const { readFile } = promises;
|
|
1291
1418
|
const pluginManifest = () => {
|
|
@@ -1344,7 +1471,7 @@ const pluginManifest = () => {
|
|
|
1344
1471
|
name: "crx:manifest-loader",
|
|
1345
1472
|
enforce: "pre",
|
|
1346
1473
|
buildStart(options) {
|
|
1347
|
-
if (typeof options.input !== "undefined") {
|
|
1474
|
+
if (typeof options.input !== "undefined" && !("ssr" in this)) {
|
|
1348
1475
|
refId = this.emitFile({
|
|
1349
1476
|
type: "chunk",
|
|
1350
1477
|
id: manifestId,
|
|
@@ -1464,7 +1591,7 @@ const pluginManifest = () => {
|
|
|
1464
1591
|
})
|
|
1465
1592
|
);
|
|
1466
1593
|
}
|
|
1467
|
-
if (manifest2.background
|
|
1594
|
+
if (manifest2.background && "service_worker" in manifest2.background) {
|
|
1468
1595
|
const file = manifest2.background.service_worker;
|
|
1469
1596
|
const id2 = join(config.root, file);
|
|
1470
1597
|
const refId2 = this.emitFile({
|
|
@@ -1474,6 +1601,16 @@ const pluginManifest = () => {
|
|
|
1474
1601
|
});
|
|
1475
1602
|
manifest2.background.service_worker = refId2;
|
|
1476
1603
|
}
|
|
1604
|
+
if (manifest2.background && "scripts" in manifest2.background) {
|
|
1605
|
+
const file = manifest2.background.scripts[0];
|
|
1606
|
+
const id2 = join(config.root, file);
|
|
1607
|
+
const refId2 = this.emitFile({
|
|
1608
|
+
type: "chunk",
|
|
1609
|
+
id: id2,
|
|
1610
|
+
name: basename(file)
|
|
1611
|
+
});
|
|
1612
|
+
manifest2.background.scripts = [refId2];
|
|
1613
|
+
}
|
|
1477
1614
|
for (const file of htmlFiles(manifest2)) {
|
|
1478
1615
|
const id2 = join(config.root, file);
|
|
1479
1616
|
this.emitFile({
|
|
@@ -1484,7 +1621,7 @@ const pluginManifest = () => {
|
|
|
1484
1621
|
}
|
|
1485
1622
|
}
|
|
1486
1623
|
const encoded = encodeManifest(manifest2);
|
|
1487
|
-
return encoded;
|
|
1624
|
+
return { code: encoded, map: null };
|
|
1488
1625
|
},
|
|
1489
1626
|
async generateBundle(options, bundle) {
|
|
1490
1627
|
const manifestName = this.getFileName(refId);
|
|
@@ -1498,11 +1635,16 @@ const pluginManifest = () => {
|
|
|
1498
1635
|
);
|
|
1499
1636
|
}
|
|
1500
1637
|
} else {
|
|
1501
|
-
if (manifest2.background
|
|
1638
|
+
if (manifest2.background && "service_worker" in manifest2.background) {
|
|
1502
1639
|
const ref = manifest2.background.service_worker;
|
|
1503
1640
|
const name = this.getFileName(ref);
|
|
1504
1641
|
manifest2.background.service_worker = name;
|
|
1505
1642
|
}
|
|
1643
|
+
if (manifest2.background && "scripts" in manifest2.background) {
|
|
1644
|
+
const ref = manifest2.background.scripts[0];
|
|
1645
|
+
const name = this.getFileName(ref);
|
|
1646
|
+
manifest2.background.scripts = [name];
|
|
1647
|
+
}
|
|
1506
1648
|
manifest2.content_scripts = manifest2.content_scripts?.map(
|
|
1507
1649
|
({ js = [], ...rest }) => {
|
|
1508
1650
|
return {
|
|
@@ -1562,6 +1704,7 @@ Public dir: "${config.publicDir}"`
|
|
|
1562
1704
|
this.emitFile({
|
|
1563
1705
|
type: "asset",
|
|
1564
1706
|
fileName: f,
|
|
1707
|
+
// TODO: cache source buffer
|
|
1565
1708
|
source: await readFile(filename)
|
|
1566
1709
|
});
|
|
1567
1710
|
}
|
|
@@ -1570,17 +1713,20 @@ Public dir: "${config.publicDir}"`
|
|
|
1570
1713
|
if (config.command === "serve" && files.html.length) {
|
|
1571
1714
|
const refId2 = this.emitFile({
|
|
1572
1715
|
type: "asset",
|
|
1573
|
-
name: "
|
|
1574
|
-
source:
|
|
1716
|
+
name: "loading-page.js",
|
|
1717
|
+
source: loadingPageScript.replace(
|
|
1718
|
+
"%PORT%",
|
|
1719
|
+
`${config.server.port ?? 0}`
|
|
1720
|
+
)
|
|
1575
1721
|
});
|
|
1576
|
-
const
|
|
1722
|
+
const loadingPageScriptName = this.getFileName(refId2);
|
|
1577
1723
|
files.html.map(
|
|
1578
1724
|
(f) => this.emitFile({
|
|
1579
1725
|
type: "asset",
|
|
1580
1726
|
fileName: f,
|
|
1581
|
-
source:
|
|
1727
|
+
source: loadingPageHtml.replace(
|
|
1582
1728
|
"%SCRIPT%",
|
|
1583
|
-
`/${
|
|
1729
|
+
`/${loadingPageScriptName}`
|
|
1584
1730
|
)
|
|
1585
1731
|
})
|
|
1586
1732
|
);
|
|
@@ -1590,10 +1736,10 @@ Public dir: "${config.publicDir}"`
|
|
|
1590
1736
|
this.emitFile({
|
|
1591
1737
|
type: "asset",
|
|
1592
1738
|
fileName: "manifest.json",
|
|
1593
|
-
source: JSON.stringify(manifest2, null, 2)
|
|
1739
|
+
source: JSON.stringify(manifest2, null, 2) + "\n"
|
|
1594
1740
|
});
|
|
1595
1741
|
} else {
|
|
1596
|
-
manifestJson.source = JSON.stringify(manifest2, null, 2);
|
|
1742
|
+
manifestJson.source = JSON.stringify(manifest2, null, 2) + "\n";
|
|
1597
1743
|
}
|
|
1598
1744
|
delete bundle[manifestName];
|
|
1599
1745
|
}
|
|
@@ -1609,7 +1755,11 @@ function compileFileResources(fileName, {
|
|
|
1609
1755
|
assets: /* @__PURE__ */ new Set(),
|
|
1610
1756
|
css: /* @__PURE__ */ new Set(),
|
|
1611
1757
|
imports: /* @__PURE__ */ new Set()
|
|
1612
|
-
}) {
|
|
1758
|
+
}, processedFiles = /* @__PURE__ */ new Set()) {
|
|
1759
|
+
if (processedFiles.has(fileName)) {
|
|
1760
|
+
return resources;
|
|
1761
|
+
}
|
|
1762
|
+
processedFiles.add(fileName);
|
|
1613
1763
|
const chunk = chunks.get(fileName);
|
|
1614
1764
|
if (chunk) {
|
|
1615
1765
|
const { modules, facadeModuleId, imports, dynamicImports } = chunk;
|
|
@@ -1618,7 +1768,7 @@ function compileFileResources(fileName, {
|
|
|
1618
1768
|
for (const x of dynamicImports)
|
|
1619
1769
|
resources.imports.add(x);
|
|
1620
1770
|
for (const x of [...imports, ...dynamicImports])
|
|
1621
|
-
compileFileResources(x, { chunks, files, config }, resources);
|
|
1771
|
+
compileFileResources(x, { chunks, files, config }, resources, processedFiles);
|
|
1622
1772
|
for (const m of Object.keys(modules))
|
|
1623
1773
|
if (m !== facadeModuleId) {
|
|
1624
1774
|
const key = prefix$1("/", relative(config.root, m.split("?")[0]));
|
|
@@ -1631,7 +1781,8 @@ function compileFileResources(fileName, {
|
|
|
1631
1781
|
compileFileResources(
|
|
1632
1782
|
script.fileName,
|
|
1633
1783
|
{ chunks, files, config },
|
|
1634
|
-
resources
|
|
1784
|
+
resources,
|
|
1785
|
+
processedFiles
|
|
1635
1786
|
);
|
|
1636
1787
|
}
|
|
1637
1788
|
}
|
|
@@ -1662,22 +1813,34 @@ _debug("web-acc-res");
|
|
|
1662
1813
|
const pluginWebAccessibleResources = () => {
|
|
1663
1814
|
let config;
|
|
1664
1815
|
let injectCss;
|
|
1816
|
+
let browser;
|
|
1665
1817
|
return [
|
|
1666
1818
|
{
|
|
1667
1819
|
name: "crx:web-accessible-resources",
|
|
1668
1820
|
apply: "serve",
|
|
1669
1821
|
enforce: "post",
|
|
1822
|
+
async config(config2) {
|
|
1823
|
+
const opts = await getOptions(config2);
|
|
1824
|
+
browser = opts.browser || "chrome";
|
|
1825
|
+
},
|
|
1670
1826
|
renderCrxManifest(manifest) {
|
|
1671
1827
|
manifest.web_accessible_resources = manifest.web_accessible_resources ?? [];
|
|
1672
1828
|
manifest.web_accessible_resources = manifest.web_accessible_resources.map(({ resources, ...rest }) => ({
|
|
1673
1829
|
resources: resources.filter((r) => r !== DYNAMIC_RESOURCE),
|
|
1674
1830
|
...rest
|
|
1675
1831
|
})).filter(({ resources }) => resources.length);
|
|
1676
|
-
|
|
1677
|
-
|
|
1832
|
+
const war = {
|
|
1833
|
+
// all web origins can access
|
|
1678
1834
|
matches: ["<all_urls>"],
|
|
1679
|
-
resources
|
|
1680
|
-
|
|
1835
|
+
// all resources are web accessible
|
|
1836
|
+
resources: ["**/*", "*"],
|
|
1837
|
+
// change the extension origin on every reload
|
|
1838
|
+
use_dynamic_url: true
|
|
1839
|
+
};
|
|
1840
|
+
if (browser === "firefox") {
|
|
1841
|
+
delete war.use_dynamic_url;
|
|
1842
|
+
}
|
|
1843
|
+
manifest.web_accessible_resources.push(war);
|
|
1681
1844
|
return manifest;
|
|
1682
1845
|
}
|
|
1683
1846
|
},
|
|
@@ -1686,7 +1849,9 @@ const pluginWebAccessibleResources = () => {
|
|
|
1686
1849
|
apply: "build",
|
|
1687
1850
|
enforce: "post",
|
|
1688
1851
|
async config({ build, ...config2 }, { command }) {
|
|
1689
|
-
const
|
|
1852
|
+
const opts = await getOptions(config2);
|
|
1853
|
+
const contentScripts2 = opts.contentScripts || {};
|
|
1854
|
+
browser = opts.browser || "chrome";
|
|
1690
1855
|
injectCss = contentScripts2.injectCss ?? true;
|
|
1691
1856
|
return { ...config2, build: { ...build, manifest: command === "build" } };
|
|
1692
1857
|
},
|
|
@@ -1715,9 +1880,11 @@ const pluginWebAccessibleResources = () => {
|
|
|
1715
1880
|
dynamicScriptMatches.add("https://*/*");
|
|
1716
1881
|
}
|
|
1717
1882
|
if (contentScripts.size > 0) {
|
|
1883
|
+
const viteMajorVersion = parseInt(version.split(".")[0]);
|
|
1884
|
+
const manifestPath = viteMajorVersion > 4 ? ".vite/manifest.json" : "manifest.json";
|
|
1718
1885
|
const viteManifest = parseJsonAsset(
|
|
1719
1886
|
bundle,
|
|
1720
|
-
|
|
1887
|
+
manifestPath
|
|
1721
1888
|
);
|
|
1722
1889
|
const viteFiles = /* @__PURE__ */ new Map();
|
|
1723
1890
|
for (const [, file] of Object.entries(viteManifest))
|
|
@@ -1745,7 +1912,7 @@ const pluginWebAccessibleResources = () => {
|
|
|
1745
1912
|
{ chunks: bundleChunks, files: viteFiles, config }
|
|
1746
1913
|
);
|
|
1747
1914
|
contentScripts.get(key).css = [...css];
|
|
1748
|
-
if (type === "loader")
|
|
1915
|
+
if (type === "loader" || isDynamicScript)
|
|
1749
1916
|
imports.add(fileName);
|
|
1750
1917
|
const resource = {
|
|
1751
1918
|
matches: isDynamicScript ? [...dynamicScriptMatches] : matches,
|
|
@@ -1794,6 +1961,11 @@ const pluginWebAccessibleResources = () => {
|
|
|
1794
1961
|
use_dynamic_url
|
|
1795
1962
|
});
|
|
1796
1963
|
}
|
|
1964
|
+
if (browser === "firefox") {
|
|
1965
|
+
for (const war of combinedResources) {
|
|
1966
|
+
delete war.use_dynamic_url;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1797
1969
|
if (combinedResources.length === 0)
|
|
1798
1970
|
delete manifest.web_accessible_resources;
|
|
1799
1971
|
else
|
|
@@ -1805,6 +1977,7 @@ const pluginWebAccessibleResources = () => {
|
|
|
1805
1977
|
};
|
|
1806
1978
|
|
|
1807
1979
|
const crx = (options) => {
|
|
1980
|
+
contentScripts.clear();
|
|
1808
1981
|
return [
|
|
1809
1982
|
pluginOptionsProvider(options),
|
|
1810
1983
|
pluginBackground(),
|