@crxjs/vite-plugin 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +30 -0
- package/dist/index.mjs +290 -50
- package/index.d.cts +1 -0
- package/package.json +16 -5
package/dist/index.d.ts
CHANGED
|
@@ -84,6 +84,7 @@ interface ManifestV3 {
|
|
|
84
84
|
match_about_blank?: boolean | undefined;
|
|
85
85
|
include_globs?: string[] | undefined;
|
|
86
86
|
exclude_globs?: string[] | undefined;
|
|
87
|
+
world?: chrome.scripting.ExecutionWorld | string | undefined;
|
|
87
88
|
}[] | undefined;
|
|
88
89
|
content_security_policy?: {
|
|
89
90
|
extension_pages?: string;
|
|
@@ -202,7 +203,29 @@ interface ManifestV3 {
|
|
|
202
203
|
update_url?: string | undefined;
|
|
203
204
|
version_name?: string | undefined;
|
|
204
205
|
web_accessible_resources?: (WebAccessibleResourceById | WebAccessibleResourceByMatch)[] | undefined;
|
|
206
|
+
browser_specific_settings?: {
|
|
207
|
+
gecko: {
|
|
208
|
+
id: string;
|
|
209
|
+
strict_min_version?: string | undefined;
|
|
210
|
+
strict_max_version?: string | undefined;
|
|
211
|
+
update_url?: string | undefined;
|
|
212
|
+
data_collection_permissions: {
|
|
213
|
+
/**
|
|
214
|
+
* available value: "personallyIdentifyingInfo" | "healthInfo" | "financialAndPaymentInfo" | "authenticationInfo" | "personalCommunications" | "locationInfo" | "browsingActivity" | "websiteContent" | "websiteActivity" | "searchTerms" | "bookmarksInfo" | "none".
|
|
215
|
+
* see also: https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/
|
|
216
|
+
*/
|
|
217
|
+
required: GeckoPermissionsRequired[];
|
|
218
|
+
/**
|
|
219
|
+
* available value: "personallyIdentifyingInfo" | "healthInfo" | "financialAndPaymentInfo" | "authenticationInfo" | "personalCommunications" | "locationInfo" | "browsingActivity" | "websiteContent" | "websiteActivity" | "searchTerms" | "bookmarksInfo" | "technicalAndInteraction".
|
|
220
|
+
* see also: https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/
|
|
221
|
+
*/
|
|
222
|
+
optional?: GeckoPermissionsOptional[] | undefined;
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
} | undefined;
|
|
205
226
|
}
|
|
227
|
+
type GeckoPermissionsRequired = "personallyIdentifyingInfo" | "healthInfo" | "financialAndPaymentInfo" | "authenticationInfo" | "personalCommunications" | "locationInfo" | "browsingActivity" | "websiteContent" | "websiteActivity" | "searchTerms" | "bookmarksInfo" | "none";
|
|
228
|
+
type GeckoPermissionsOptional = "personallyIdentifyingInfo" | "healthInfo" | "financialAndPaymentInfo" | "authenticationInfo" | "personalCommunications" | "locationInfo" | "browsingActivity" | "websiteContent" | "websiteActivity" | "searchTerms" | "bookmarksInfo" | "technicalAndInteraction";
|
|
206
229
|
|
|
207
230
|
type ManifestV3Fn = (env: ConfigEnv) => ManifestV3 | Promise<ManifestV3>;
|
|
208
231
|
type ManifestV3Export = ManifestV3 | Promise<ManifestV3> | ManifestV3Fn;
|
|
@@ -263,6 +286,13 @@ type FilePathFields<T extends string> = {
|
|
|
263
286
|
match_about_blank?: boolean;
|
|
264
287
|
include_globs?: string[];
|
|
265
288
|
exclude_globs?: string[];
|
|
289
|
+
/**
|
|
290
|
+
* - 'ISOLATED' (default): Content script runs in an isolated world.
|
|
291
|
+
* - 'MAIN': Content script runs in the main world.
|
|
292
|
+
* NOTE: MAIN currently does NOT support crxjs HMR
|
|
293
|
+
* @see https://developer.chrome.com/docs/extensions/mv3/content_scripts/#world
|
|
294
|
+
*/
|
|
295
|
+
world?: 'ISOLATED' | 'MAIN';
|
|
266
296
|
}[];
|
|
267
297
|
input_components?: {
|
|
268
298
|
name: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { simple } from 'acorn-walk';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
|
-
import debug$
|
|
4
|
-
import { join, normalize,
|
|
3
|
+
import debug$5 from 'debug';
|
|
4
|
+
import { join, normalize, dirname, basename, isAbsolute, relative, resolve, parse as parse$1 } from 'pathe';
|
|
5
5
|
import { Subject, filter, ReplaySubject, switchMap, of, startWith, map, BehaviorSubject, mergeMap, firstValueFrom, takeUntil, first, toArray, retry, concatWith, Subscription, buffer } from 'rxjs';
|
|
6
6
|
import fsx from 'fs-extra';
|
|
7
7
|
import { performance } from 'perf_hooks';
|
|
@@ -10,12 +10,12 @@ import * as lexer from 'es-module-lexer';
|
|
|
10
10
|
import { readFile as readFile$1 } from 'fs/promises';
|
|
11
11
|
import MagicString from 'magic-string';
|
|
12
12
|
import convertSourceMap from 'convert-source-map';
|
|
13
|
+
import pc from 'picocolors';
|
|
13
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
|
|
18
|
-
import { load } from 'cheerio';
|
|
18
|
+
import { parse } from 'node-html-parser';
|
|
19
19
|
import jsesc from 'jsesc';
|
|
20
20
|
|
|
21
21
|
const pluginName$1 = "crx:optionsProvider";
|
|
@@ -58,9 +58,9 @@ function isCrxPlugin(p) {
|
|
|
58
58
|
return !!p && typeof p === "object" && !(p instanceof Promise) && !Array.isArray(p) && p.name.startsWith("crx:");
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
var workerHmrClient = "const ownOrigin = `chrome-extension://${chrome.runtime.id}`;\nself.addEventListener(\"fetch\", (fetchEvent) => {\n const url = new URL(fetchEvent.request.url);\n if (url.origin === ownOrigin) {\n fetchEvent.respondWith(sendToServer(fetchEvent.request));\n }\n});\nasync function sendToServer(req) {\n const url = new URL(req.url);\n const requestHeaders = new Headers(req.headers);\n url.protocol = \"
|
|
61
|
+
var workerHmrClient = "const ownOrigin = `chrome-extension://${chrome.runtime.id}`;\nself.addEventListener(\"fetch\", (fetchEvent) => {\n const url = new URL(fetchEvent.request.url);\n if (url.origin === ownOrigin) {\n fetchEvent.respondWith(sendToServer(fetchEvent.request));\n }\n});\nasync function sendToServer(req) {\n const url = new URL(req.url);\n const requestHeaders = new Headers(req.headers);\n url.protocol = __SERVER_PROTO__ + \":\";\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 headers: requestHeaders\n });\n const responseHeaders = new Headers(response.headers);\n responseHeaders.set(\n \"Content-Type\",\n responseHeaders.get(\"Content-Type\") ?? \"text/javascript\"\n );\n responseHeaders.set(\n \"Cache-Control\",\n responseHeaders.get(\"Cache-Control\") ?? \"\"\n );\n return new Response(response.body, {\n headers: responseHeaders\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) => {\n if (chrome.runtime.lastError) {\n console.error(chrome.runtime.lastError);\n }\n ports.delete(port2);\n });\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 socketToken = __HMR_TOKEN__;\nconst socketHost = `${__HMR_HOSTNAME__ || location.hostname}:${__HMR_PORT__}`;\nconst socket = new WebSocket(\n `${socketProtocol}://${socketHost}?token=${socketToken}`,\n \"vite-hmr\"\n);\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";
|
|
62
62
|
|
|
63
|
-
const _debug = (id) => debug$
|
|
63
|
+
const _debug = (id) => debug$5("crx").extend(id);
|
|
64
64
|
const hash = (data, length = 5) => createHash("sha1").update(data).digest("base64").replace(/[^A-Za-z0-9]/g, "").slice(0, length);
|
|
65
65
|
const isString = (x) => typeof x === "string";
|
|
66
66
|
function isObject(value) {
|
|
@@ -140,7 +140,13 @@ function defineClientValues(code, config) {
|
|
|
140
140
|
if (hmrBase !== "/") {
|
|
141
141
|
hmrPort = normalize(`${hmrPort}${hmrBase}`);
|
|
142
142
|
}
|
|
143
|
-
return code.replace(`__MODE__`, JSON.stringify(config.mode)).replace(`__BASE__`, JSON.stringify(config.base)).replace(`__DEFINES__`, serializeDefine(config.define || {})).replace(`__HMR_TOKEN__`, JSON.stringify(config.webSocketToken || "")).replace(`__HMR_PROTOCOL__`, JSON.stringify(protocol)).replace(`__HMR_HOSTNAME__`, JSON.stringify(host)).replace(`__HMR_PORT__`, JSON.stringify(hmrPort)).replace(`__HMR_TIMEOUT__`, JSON.stringify(timeout)).replace(`__HMR_ENABLE_OVERLAY__`, JSON.stringify(overlay)).replace(
|
|
143
|
+
return code.replace(`__MODE__`, JSON.stringify(config.mode)).replace(`__BASE__`, JSON.stringify(config.base)).replace(`__DEFINES__`, serializeDefine(config.define || {})).replace(`__HMR_TOKEN__`, JSON.stringify(config.webSocketToken || "")).replace(`__HMR_PROTOCOL__`, JSON.stringify(protocol)).replace(`__HMR_HOSTNAME__`, JSON.stringify(host)).replace(`__HMR_PORT__`, JSON.stringify(hmrPort)).replace(`__HMR_TIMEOUT__`, JSON.stringify(timeout)).replace(`__HMR_ENABLE_OVERLAY__`, JSON.stringify(overlay)).replace(
|
|
144
|
+
`__SERVER_PROTO__`,
|
|
145
|
+
JSON.stringify(config.server.https ? "https" : "http")
|
|
146
|
+
).replace(
|
|
147
|
+
`__SERVER_PORT__`,
|
|
148
|
+
JSON.stringify(config.server.port?.toString())
|
|
149
|
+
);
|
|
144
150
|
function serializeDefine(define) {
|
|
145
151
|
let res = `{`;
|
|
146
152
|
for (const key in define) {
|
|
@@ -177,6 +183,17 @@ class RxMap extends Map {
|
|
|
177
183
|
const outputFiles = new RxMap();
|
|
178
184
|
|
|
179
185
|
_debug("file-writer").extend("utilities");
|
|
186
|
+
function sanitizeUnderscorePrefix(fileName) {
|
|
187
|
+
const dir = dirname(fileName);
|
|
188
|
+
let base = basename(fileName);
|
|
189
|
+
while (base.startsWith("_")) {
|
|
190
|
+
base = base.slice(1);
|
|
191
|
+
}
|
|
192
|
+
if (!base) {
|
|
193
|
+
base = "file";
|
|
194
|
+
}
|
|
195
|
+
return dir === "." ? base : join(dir, base);
|
|
196
|
+
}
|
|
180
197
|
function prefix$1(prefix2, text) {
|
|
181
198
|
return text.startsWith(prefix2) ? text : prefix2 + text;
|
|
182
199
|
}
|
|
@@ -200,6 +217,7 @@ function getFileName({ type, id }) {
|
|
|
200
217
|
} else if (fileName.startsWith(".vite/deps/")) {
|
|
201
218
|
fileName = `vendor/${fileName.slice(".vite/deps/".length)}`;
|
|
202
219
|
}
|
|
220
|
+
fileName = sanitizeUnderscorePrefix(fileName);
|
|
203
221
|
switch (type) {
|
|
204
222
|
case "iife":
|
|
205
223
|
return `${fileName}.iife.js`;
|
|
@@ -257,6 +275,20 @@ const manifestId = "/@crx/manifest";
|
|
|
257
275
|
const preambleId = "/@crx/client-preamble";
|
|
258
276
|
const stubId = "/@crx/stub";
|
|
259
277
|
const workerClientId = "/@crx/client-worker";
|
|
278
|
+
const contentCssPrefix = "/@crx/content-css/";
|
|
279
|
+
function isContentCssId(id) {
|
|
280
|
+
return id.startsWith(contentCssPrefix);
|
|
281
|
+
}
|
|
282
|
+
function getContentCssId(index) {
|
|
283
|
+
return `${contentCssPrefix}${index}`;
|
|
284
|
+
}
|
|
285
|
+
function getContentCssIndex(id) {
|
|
286
|
+
if (!isContentCssId(id))
|
|
287
|
+
return null;
|
|
288
|
+
const indexStr = id.slice(contentCssPrefix.length);
|
|
289
|
+
const index = parseInt(indexStr, 10);
|
|
290
|
+
return isNaN(index) ? null : index;
|
|
291
|
+
}
|
|
260
292
|
|
|
261
293
|
const pluginBackground = () => {
|
|
262
294
|
let config;
|
|
@@ -271,7 +303,7 @@ const pluginBackground = () => {
|
|
|
271
303
|
},
|
|
272
304
|
load(id) {
|
|
273
305
|
if (id === workerClientId) {
|
|
274
|
-
const base =
|
|
306
|
+
const base = `${config.server.https ? "https" : "http"}://localhost:${config.server.port}/`;
|
|
275
307
|
return defineClientValues(
|
|
276
308
|
workerHmrClient.replace("__BASE__", JSON.stringify(base)),
|
|
277
309
|
config
|
|
@@ -294,24 +326,25 @@ const pluginBackground = () => {
|
|
|
294
326
|
const worker = browser === "firefox" ? manifest.background?.scripts[0] : manifest.background?.service_worker;
|
|
295
327
|
let loader;
|
|
296
328
|
if (config.command === "serve") {
|
|
329
|
+
const proto = config.server.https ? "https" : "http";
|
|
297
330
|
const port = config.server.port?.toString();
|
|
298
331
|
if (typeof port === "undefined")
|
|
299
332
|
throw new Error("server port is undefined in watch mode");
|
|
300
333
|
if (browser === "firefox") {
|
|
301
|
-
loader = `import('
|
|
334
|
+
loader = `import('${proto}://localhost:${port}/@vite/env');
|
|
302
335
|
`;
|
|
303
|
-
loader += `import('
|
|
336
|
+
loader += `import('${proto}://localhost:${port}${workerClientId}');
|
|
304
337
|
`;
|
|
305
338
|
if (worker)
|
|
306
|
-
loader += `import('
|
|
339
|
+
loader += `import('${proto}://localhost:${port}/${worker}');
|
|
307
340
|
`;
|
|
308
341
|
} else {
|
|
309
|
-
loader = `import '
|
|
342
|
+
loader = `import '${proto}://localhost:${port}/@vite/env';
|
|
310
343
|
`;
|
|
311
|
-
loader += `import '
|
|
344
|
+
loader += `import '${proto}://localhost:${port}${workerClientId}';
|
|
312
345
|
`;
|
|
313
346
|
if (worker)
|
|
314
|
-
loader += `import '
|
|
347
|
+
loader += `import '${proto}://localhost:${port}/${worker}';
|
|
315
348
|
`;
|
|
316
349
|
}
|
|
317
350
|
} else if (worker) {
|
|
@@ -347,8 +380,12 @@ var contentHmrPort = "function isCrxHMRPayload(x) {\n return x.type === \"custo
|
|
|
347
380
|
|
|
348
381
|
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";
|
|
349
382
|
|
|
383
|
+
var contentDevMainLoader = "(function () {\n 'use strict';\n\n const injectTime = performance.now();\n (async () => {\n console.warn(__SCRIPT__, \"Content-script doesn't support HMR because the world is MAIN\");\n const { onExecute } = await import(\n /* @vite-ignore */\n __SCRIPT__\n );\n onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } });\n })().catch(console.error);\n\n})();\n";
|
|
384
|
+
|
|
350
385
|
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";
|
|
351
386
|
|
|
387
|
+
var contentProMainLoader = "(function () {\n 'use strict';\n\n const injectTime = performance.now();\n (async () => {\n const { onExecute } = await import(\n /* @vite-ignore */\n __SCRIPT__\n );\n onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } });\n })().catch(console.error);\n\n})();\n";
|
|
388
|
+
|
|
352
389
|
const contentScripts = new RxMap();
|
|
353
390
|
contentScripts.change$.pipe(filter(RxMap.isChangeType.set)).subscribe(({ map, value }) => {
|
|
354
391
|
const keyNames = [
|
|
@@ -381,6 +418,14 @@ function createDevLoader({
|
|
|
381
418
|
function createProLoader({ fileName }) {
|
|
382
419
|
return contentProLoader.replace(/__SCRIPT__/g, JSON.stringify(fileName));
|
|
383
420
|
}
|
|
421
|
+
function createDevMainLoader({
|
|
422
|
+
fileName
|
|
423
|
+
}) {
|
|
424
|
+
return contentDevMainLoader.replace(/__SCRIPT__/g, JSON.stringify(fileName)).replace(/__TIMESTAMP__/g, JSON.stringify(Date.now()));
|
|
425
|
+
}
|
|
426
|
+
function createProMainLoader({ fileName }) {
|
|
427
|
+
return contentProMainLoader.replace(/__SCRIPT__/g, JSON.stringify(fileName));
|
|
428
|
+
}
|
|
384
429
|
|
|
385
430
|
const serverEvent$ = new ReplaySubject(1);
|
|
386
431
|
const close$ = serverEvent$.pipe(
|
|
@@ -503,7 +548,7 @@ async function allFilesReady() {
|
|
|
503
548
|
}
|
|
504
549
|
|
|
505
550
|
const { outputFile } = fsx;
|
|
506
|
-
_debug("file-writer");
|
|
551
|
+
const debug$4 = _debug("file-writer");
|
|
507
552
|
async function start({
|
|
508
553
|
server
|
|
509
554
|
}) {
|
|
@@ -534,6 +579,12 @@ async function close() {
|
|
|
534
579
|
}
|
|
535
580
|
function add(script) {
|
|
536
581
|
const fileName = getFileName(script);
|
|
582
|
+
debug$4(
|
|
583
|
+
"add: script.id=%s script.type=%s fileName=%s",
|
|
584
|
+
script.id,
|
|
585
|
+
script.type,
|
|
586
|
+
fileName
|
|
587
|
+
);
|
|
537
588
|
let file = outputFiles.get(fileName);
|
|
538
589
|
if (typeof file === "undefined") {
|
|
539
590
|
file = formatFileData({
|
|
@@ -542,6 +593,17 @@ function add(script) {
|
|
|
542
593
|
file: write(script)
|
|
543
594
|
});
|
|
544
595
|
outputFiles.set(file.fileName, file);
|
|
596
|
+
debug$4("add: stored new file %s", file.fileName);
|
|
597
|
+
} else {
|
|
598
|
+
const isVirtualModule = script.id.startsWith("/@id/") || script.id.startsWith("/__");
|
|
599
|
+
if (isVirtualModule) {
|
|
600
|
+
debug$4(
|
|
601
|
+
"add: virtual module already exists, triggering re-write for %s",
|
|
602
|
+
fileName
|
|
603
|
+
);
|
|
604
|
+
file.file = write(script);
|
|
605
|
+
outputFiles.set(fileName, file);
|
|
606
|
+
}
|
|
545
607
|
}
|
|
546
608
|
return file;
|
|
547
609
|
}
|
|
@@ -549,15 +611,19 @@ function update(_id) {
|
|
|
549
611
|
const id = prefix$1("/", _id);
|
|
550
612
|
const types = ["iife", "module"];
|
|
551
613
|
const updatedFiles = [];
|
|
614
|
+
debug$4("update called: _id=%s id=%s", _id, id);
|
|
552
615
|
for (const type of types) {
|
|
553
616
|
const fileName = getFileName({ id, type });
|
|
617
|
+
debug$4("update: looking for fileName=%s", fileName);
|
|
554
618
|
const scriptFile = outputFiles.get(fileName);
|
|
555
619
|
if (scriptFile) {
|
|
620
|
+
debug$4("update: found file, calling write()");
|
|
556
621
|
scriptFile.file = write({ id, type });
|
|
557
622
|
updatedFiles.push(scriptFile);
|
|
558
623
|
outputFiles.set(fileName, scriptFile);
|
|
559
624
|
}
|
|
560
625
|
}
|
|
626
|
+
debug$4("update: returning %d files", updatedFiles.length);
|
|
561
627
|
return updatedFiles;
|
|
562
628
|
}
|
|
563
629
|
async function write(fileId) {
|
|
@@ -593,15 +659,37 @@ async function write(fileId) {
|
|
|
593
659
|
}
|
|
594
660
|
|
|
595
661
|
const pluginContentScripts = () => {
|
|
662
|
+
const pluginName = "crx:content-scripts";
|
|
596
663
|
let server;
|
|
597
664
|
let preambleCode;
|
|
598
665
|
let hmrTimeout;
|
|
599
666
|
let sub = new Subscription();
|
|
667
|
+
const worldMainIds = /* @__PURE__ */ new Set();
|
|
668
|
+
const findWorldMainIds = async (config, env) => {
|
|
669
|
+
const { manifest: _manifest } = await getOptions(config);
|
|
670
|
+
const manifest = await (typeof _manifest === "function" ? _manifest(env) : _manifest);
|
|
671
|
+
(manifest.content_scripts || []).forEach(({ world, js }) => {
|
|
672
|
+
if (world === "MAIN" && js) {
|
|
673
|
+
js.forEach((path) => worldMainIds.add(prefix$1("/", path)));
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
if (worldMainIds.size) {
|
|
677
|
+
const name = `[${pluginName}]`;
|
|
678
|
+
const message = pc.yellow(
|
|
679
|
+
[
|
|
680
|
+
`${name} Some content-scripts don't support HMR because the world is MAIN:`,
|
|
681
|
+
...[...worldMainIds].map((id) => ` ${id}`)
|
|
682
|
+
].join("\r\n")
|
|
683
|
+
);
|
|
684
|
+
console.log(message);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
600
687
|
return [
|
|
601
688
|
{
|
|
602
|
-
name:
|
|
689
|
+
name: pluginName,
|
|
603
690
|
apply: "serve",
|
|
604
|
-
async config(config) {
|
|
691
|
+
async config(config, env) {
|
|
692
|
+
await findWorldMainIds(config, env);
|
|
605
693
|
const { contentScripts: contentScripts2 = {} } = await getOptions(config);
|
|
606
694
|
hmrTimeout = contentScripts2.hmrTimeout ?? 5e3;
|
|
607
695
|
preambleCode = preambleCode ?? contentScripts2.preambleCode;
|
|
@@ -630,7 +718,9 @@ const pluginContentScripts = () => {
|
|
|
630
718
|
const loader = add({
|
|
631
719
|
type: "asset",
|
|
632
720
|
id: getFileName({ type: "loader", id }),
|
|
633
|
-
source:
|
|
721
|
+
source: worldMainIds.has(file.id) ? createDevMainLoader({
|
|
722
|
+
fileName: `./${file.fileName.split("/").at(-1)}`
|
|
723
|
+
}) : createDevLoader({
|
|
634
724
|
preamble: preamble.fileName,
|
|
635
725
|
client: client.fileName,
|
|
636
726
|
fileName: file.fileName
|
|
@@ -671,10 +761,11 @@ const pluginContentScripts = () => {
|
|
|
671
761
|
}
|
|
672
762
|
},
|
|
673
763
|
{
|
|
674
|
-
name:
|
|
764
|
+
name: pluginName,
|
|
675
765
|
apply: "build",
|
|
676
766
|
enforce: "pre",
|
|
677
|
-
config(config) {
|
|
767
|
+
async config(config, env) {
|
|
768
|
+
await findWorldMainIds(config, env);
|
|
678
769
|
return {
|
|
679
770
|
...config,
|
|
680
771
|
build: {
|
|
@@ -705,7 +796,9 @@ const pluginContentScripts = () => {
|
|
|
705
796
|
type: "loader",
|
|
706
797
|
id: basename(script.id)
|
|
707
798
|
}),
|
|
708
|
-
source:
|
|
799
|
+
source: worldMainIds.has(script.id) ? createProMainLoader({
|
|
800
|
+
fileName: `./${fileName.split("/").at(-1)}`
|
|
801
|
+
}) : createProLoader({ fileName })
|
|
709
802
|
});
|
|
710
803
|
script.loaderName = this.getFileName(refId);
|
|
711
804
|
} else {
|
|
@@ -753,8 +846,48 @@ const pluginContentScriptsCss = () => {
|
|
|
753
846
|
};
|
|
754
847
|
};
|
|
755
848
|
|
|
849
|
+
const contentCssEntries = /* @__PURE__ */ new Map();
|
|
850
|
+
function getContentCssEntries() {
|
|
851
|
+
return Array.from(contentCssEntries.values());
|
|
852
|
+
}
|
|
853
|
+
function clearContentCssEntries() {
|
|
854
|
+
contentCssEntries.clear();
|
|
855
|
+
}
|
|
856
|
+
function registerContentCssEntry(index, cssFiles) {
|
|
857
|
+
const virtualId = getContentCssId(index);
|
|
858
|
+
const entry = { index, cssFiles, virtualId };
|
|
859
|
+
contentCssEntries.set(index, entry);
|
|
860
|
+
return entry;
|
|
861
|
+
}
|
|
756
862
|
const pluginDeclaredContentScripts = () => {
|
|
757
|
-
return
|
|
863
|
+
return {
|
|
864
|
+
name: "crx:content-scripts-declared-css",
|
|
865
|
+
apply: "serve",
|
|
866
|
+
resolveId(source) {
|
|
867
|
+
if (isContentCssId(source)) {
|
|
868
|
+
return source;
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
load(id) {
|
|
872
|
+
if (!isContentCssId(id))
|
|
873
|
+
return;
|
|
874
|
+
const index = getContentCssIndex(id);
|
|
875
|
+
if (index === null)
|
|
876
|
+
return;
|
|
877
|
+
const entry = contentCssEntries.get(index);
|
|
878
|
+
if (!entry) {
|
|
879
|
+
console.warn(
|
|
880
|
+
`[crx:content-scripts-declared-css] No CSS entry found for index ${index}`
|
|
881
|
+
);
|
|
882
|
+
return "";
|
|
883
|
+
}
|
|
884
|
+
const cssImports = entry.cssFiles.map((cssPath) => {
|
|
885
|
+
const importPath = cssPath.startsWith("/") ? cssPath : `/${cssPath}`;
|
|
886
|
+
return `import "${importPath}";`;
|
|
887
|
+
}).join("\n");
|
|
888
|
+
return cssImports + "\n";
|
|
889
|
+
}
|
|
890
|
+
};
|
|
758
891
|
};
|
|
759
892
|
|
|
760
893
|
const _dynamicScriptRegEx = /\b(import.meta).CRX_DYNAMIC_SCRIPT_(.+?)[,;]/gm;
|
|
@@ -1067,7 +1200,7 @@ const pluginFileWriterPublic = () => {
|
|
|
1067
1200
|
};
|
|
1068
1201
|
};
|
|
1069
1202
|
|
|
1070
|
-
const debug$
|
|
1203
|
+
const debug$3 = _debug("file-writer").extend("hmr");
|
|
1071
1204
|
const isCustomPayload = (p) => {
|
|
1072
1205
|
return p.type === "custom";
|
|
1073
1206
|
};
|
|
@@ -1105,7 +1238,21 @@ const crxHMRPayload$ = hmrPayload$.pipe(
|
|
|
1105
1238
|
return prune;
|
|
1106
1239
|
}
|
|
1107
1240
|
case "update": {
|
|
1108
|
-
|
|
1241
|
+
debug$3("update payload with %d updates", p.updates.length);
|
|
1242
|
+
for (const u of p.updates) {
|
|
1243
|
+
debug$3(
|
|
1244
|
+
"update item: path=%s acceptedPath=%s type=%s",
|
|
1245
|
+
u.path,
|
|
1246
|
+
u.acceptedPath,
|
|
1247
|
+
u.type
|
|
1248
|
+
);
|
|
1249
|
+
const isVirtualModule = u.path.startsWith("/@id/") || u.path.startsWith("/__");
|
|
1250
|
+
if (isVirtualModule) {
|
|
1251
|
+
debug$3("updating virtual module: %s", u.path);
|
|
1252
|
+
update(u.path);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
const update_ = {
|
|
1109
1256
|
type: "update",
|
|
1110
1257
|
updates: p.updates.map(({ acceptedPath: ap, path: p2, ...rest }) => ({
|
|
1111
1258
|
...rest,
|
|
@@ -1113,7 +1260,7 @@ const crxHMRPayload$ = hmrPayload$.pipe(
|
|
|
1113
1260
|
path: prefix$1("/", getFileName({ id: p2, type: "module" }))
|
|
1114
1261
|
}))
|
|
1115
1262
|
};
|
|
1116
|
-
return
|
|
1263
|
+
return update_;
|
|
1117
1264
|
}
|
|
1118
1265
|
default:
|
|
1119
1266
|
return p;
|
|
@@ -1132,7 +1279,7 @@ const crxHMRPayload$ = hmrPayload$.pipe(
|
|
|
1132
1279
|
}
|
|
1133
1280
|
}),
|
|
1134
1281
|
map((data) => {
|
|
1135
|
-
debug$
|
|
1282
|
+
debug$3(`hmr payload`, data);
|
|
1136
1283
|
return {
|
|
1137
1284
|
type: "custom",
|
|
1138
1285
|
event: "crx:content-script-payload",
|
|
@@ -1157,7 +1304,7 @@ function isImporter(file) {
|
|
|
1157
1304
|
return pred;
|
|
1158
1305
|
}
|
|
1159
1306
|
|
|
1160
|
-
const debug$
|
|
1307
|
+
const debug$2 = _debug("hmr");
|
|
1161
1308
|
const crxRuntimeReload = {
|
|
1162
1309
|
type: "custom",
|
|
1163
1310
|
event: "crx:runtime-reload"
|
|
@@ -1225,25 +1372,51 @@ const pluginHMR = () => {
|
|
|
1225
1372
|
const { root } = server.config;
|
|
1226
1373
|
const relFiles = /* @__PURE__ */ new Set();
|
|
1227
1374
|
const fsFiles = /* @__PURE__ */ new Set();
|
|
1375
|
+
const virtualModules = /* @__PURE__ */ new Set();
|
|
1228
1376
|
for (const m of modules) {
|
|
1229
1377
|
if (m.id?.startsWith(root)) {
|
|
1230
1378
|
relFiles.add(m.id.slice(server.config.root.length));
|
|
1231
1379
|
} else if (m.url?.startsWith("/@fs")) {
|
|
1232
1380
|
fsFiles.add(m.url);
|
|
1381
|
+
} else if (m.id?.startsWith("\0") || m.url?.startsWith("/@id/__x00__")) {
|
|
1382
|
+
const virtualId = m.url ?? m.id;
|
|
1383
|
+
if (virtualId) {
|
|
1384
|
+
virtualModules.add(virtualId);
|
|
1385
|
+
debug$2("virtual module detected:", virtualId);
|
|
1386
|
+
}
|
|
1233
1387
|
}
|
|
1234
1388
|
}
|
|
1235
1389
|
fsFiles.forEach((file) => update(file));
|
|
1390
|
+
virtualModules.forEach((file) => update(file));
|
|
1236
1391
|
if (inputManifestFiles.background.length) {
|
|
1237
1392
|
const background = prefix$1("/", inputManifestFiles.background[0]);
|
|
1238
1393
|
if (relFiles.has(background) || modules.some(isImporter(join(server.config.root, background)))) {
|
|
1239
|
-
debug$
|
|
1394
|
+
debug$2("sending runtime reload");
|
|
1240
1395
|
server.ws.send(crxRuntimeReload);
|
|
1241
1396
|
}
|
|
1242
1397
|
}
|
|
1243
1398
|
for (const [key, script] of contentScripts)
|
|
1244
1399
|
if (key === script.id) {
|
|
1245
|
-
if (
|
|
1246
|
-
|
|
1400
|
+
if (isContentCssId(script.id)) {
|
|
1401
|
+
const cssEntries = getContentCssEntries();
|
|
1402
|
+
const entry = cssEntries.find((e) => e.virtualId === script.id);
|
|
1403
|
+
if (entry) {
|
|
1404
|
+
const changedCssFiles = [...relFiles].filter(
|
|
1405
|
+
(relFile) => entry.cssFiles.some(
|
|
1406
|
+
(cssFile) => relFile === prefix$1("/", cssFile) || relFile.endsWith(cssFile)
|
|
1407
|
+
)
|
|
1408
|
+
);
|
|
1409
|
+
if (changedCssFiles.length > 0) {
|
|
1410
|
+
changedCssFiles.forEach((relFile) => update(relFile));
|
|
1411
|
+
update(script.id);
|
|
1412
|
+
virtualModules.forEach((file) => update(file));
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
} else {
|
|
1416
|
+
if (relFiles.has(script.id) || modules.some(isImporter(join(server.config.root, script.id)))) {
|
|
1417
|
+
relFiles.forEach((relFile) => update(relFile));
|
|
1418
|
+
virtualModules.forEach((file) => update(file));
|
|
1419
|
+
}
|
|
1247
1420
|
}
|
|
1248
1421
|
}
|
|
1249
1422
|
}
|
|
@@ -1302,12 +1475,20 @@ const pluginPrint = () => {
|
|
|
1302
1475
|
|
|
1303
1476
|
var loader = "try {\n for (const p of JSON.parse(SCRIPTS)) {\n const url = new URL(p, \"https://stub\");\n url.searchParams.set(\"t\", Date.now().toString());\n const req = url.pathname + url.search;\n await import(\n /* @vite-ignore */\n req\n );\n }\n} catch (error) {\n console.error(error);\n}\n";
|
|
1304
1477
|
|
|
1478
|
+
function extractScriptsAndRemove(html) {
|
|
1479
|
+
const root = parse(html);
|
|
1480
|
+
const scripts = root.querySelectorAll("script");
|
|
1481
|
+
const scriptSrcs = scripts.map((el) => el.getAttribute("src"));
|
|
1482
|
+
scripts.forEach((el) => el.remove());
|
|
1483
|
+
return { scriptSrcs, html: root.toString() };
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1305
1486
|
const pluginName = "crx:html-inline-scripts";
|
|
1306
|
-
const debug = _debug(pluginName);
|
|
1487
|
+
const debug$1 = _debug(pluginName);
|
|
1307
1488
|
const prefix = "@crx/inline-script";
|
|
1308
1489
|
const isInlineTag = (t) => t.tag === "script" && !t.attrs?.src;
|
|
1309
1490
|
const toKey = (ctx) => {
|
|
1310
|
-
const { dir, name } = parse(ctx.path);
|
|
1491
|
+
const { dir, name } = parse$1(ctx.path);
|
|
1311
1492
|
return join(prefix, dir, name);
|
|
1312
1493
|
};
|
|
1313
1494
|
const pluginHtmlInlineScripts = () => {
|
|
@@ -1373,19 +1554,18 @@ const pluginHtmlInlineScripts = () => {
|
|
|
1373
1554
|
const key = toKey(ctx);
|
|
1374
1555
|
const p = pages.get(key);
|
|
1375
1556
|
if (p?.scripts.some(isInlineTag)) {
|
|
1376
|
-
const
|
|
1557
|
+
const { scriptSrcs, html: cleanedHtml } = extractScriptsAndRemove(html);
|
|
1377
1558
|
p.scripts.push(
|
|
1378
|
-
|
|
1559
|
+
...scriptSrcs.map((src) => ({
|
|
1379
1560
|
tag: "script",
|
|
1380
|
-
attrs: { src
|
|
1561
|
+
attrs: { src, type: "module" }
|
|
1381
1562
|
}))
|
|
1382
1563
|
);
|
|
1383
|
-
$("script").remove();
|
|
1384
1564
|
const loader2 = {
|
|
1385
1565
|
tag: "script",
|
|
1386
1566
|
attrs: { src: `${key}?t=${Date.now()}`, type: "module" }
|
|
1387
1567
|
};
|
|
1388
|
-
return { html:
|
|
1568
|
+
return { html: cleanedHtml, tags: [loader2] };
|
|
1389
1569
|
}
|
|
1390
1570
|
return p?.scripts ?? void 0;
|
|
1391
1571
|
}
|
|
@@ -1427,21 +1607,21 @@ const pluginHtmlInlineScripts = () => {
|
|
|
1427
1607
|
})}"`;
|
|
1428
1608
|
return [inline, loader.replace("SCRIPTS", json)].join("\n");
|
|
1429
1609
|
} else {
|
|
1430
|
-
debug("page missing %s", id);
|
|
1610
|
+
debug$1("page missing %s", id);
|
|
1431
1611
|
}
|
|
1432
1612
|
}
|
|
1433
1613
|
}
|
|
1434
1614
|
};
|
|
1435
1615
|
};
|
|
1436
1616
|
|
|
1437
|
-
var loadingPageScript = "const VITE_URL = \"
|
|
1617
|
+
var loadingPageScript = "const VITE_URL = \"%PROTO%://localhost:%PORT%\";\ndocument.body.innerHTML = /* html */\n`\n<style>\n :root {\n color-scheme: light;\n --ink: #111827;\n --muted: #5f6b7a;\n --muted-subtle: rgba(95, 107, 122, 0.7);\n --muted-hint: rgba(95, 107, 122, 0.6);\n --card: #ffffff;\n --badge-bg: rgba(17, 24, 39, 0.04);\n --accent: #ff6b2c;\n --accent-2: #2563eb;\n --link-underline: rgba(37, 99, 235, 0.45);\n --glow-1: rgba(37, 99, 235, 0.12);\n --glow-2: rgba(255, 107, 44, 0.1);\n --button-grad-1: #ff7a43;\n --button-grad-2: #ff9a73;\n --button-shadow: rgba(255, 107, 44, 0.18);\n --button-shadow-hover: rgba(255, 107, 44, 0.22);\n --pulse: rgba(255, 107, 44, 0.6);\n --pulse-ring: rgba(255, 107, 44, 0.5);\n }\n\n @media (prefers-color-scheme: dark) {\n :root {\n color-scheme: dark;\n --ink: #e5e7eb;\n --muted: #a3aab5;\n --muted-subtle: rgba(163, 170, 181, 0.78);\n --muted-hint: rgba(163, 170, 181, 0.6);\n --card: #0f172a;\n --badge-bg: rgba(148, 163, 184, 0.16);\n --accent: #ff8a5a;\n --accent-2: #7aa2ff;\n --link-underline: rgba(122, 162, 255, 0.45);\n --glow-1: rgba(96, 165, 250, 0.14);\n --glow-2: rgba(251, 146, 60, 0.16);\n --button-grad-1: #f07b4d;\n --button-grad-2: #f39a76;\n --button-shadow: rgba(240, 123, 77, 0.16);\n --button-shadow-hover: rgba(240, 123, 77, 0.2);\n --pulse: rgba(255, 138, 90, 0.65);\n --pulse-ring: rgba(255, 138, 90, 0.5);\n }\n }\n\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n\n body {\n font-family: \"IBM Plex Sans\", \"Inter\", -apple-system, system-ui, sans-serif;\n color: var(--ink);\n background: transparent;\n width: 420px;\n height: 250px;\n margin: 0;\n padding: 0 !important;\n }\n\n #app {\n background: var(--card);\n position: relative;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 100%;\n padding: 24px 24px 20px;\n gap: 14px;\n justify-content: center;\n }\n\n #app::before {\n content: \"\";\n position: absolute;\n inset: 0;\n background:\n radial-gradient(240px 140px at 100% 0%, var(--glow-1), transparent 70%),\n radial-gradient(220px 140px at 0% 100%, var(--glow-2), transparent 70%);\n pointer-events: none;\n }\n\n .header {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 6px;\n align-items: flex-start;\n padding-right: 96px;\n }\n\n .header-text {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .badge {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 10px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--muted);\n background: var(--badge-bg);\n border-radius: 999px;\n padding: 6px 10px;\n white-space: nowrap;\n position: absolute;\n top: 0;\n right: 0;\n }\n\n .pulse {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--accent);\n box-shadow: 0 0 0 0 var(--pulse);\n animation: pulse 1.6s ease-in-out infinite;\n }\n\n h1 {\n font-size: clamp(18px, 4vw, 22px);\n letter-spacing: -0.02em;\n line-height: 1.25;\n }\n\n p {\n margin: 0;\n color: var(--muted);\n font-size: 13px;\n line-height: 1.6;\n }\n\n .subtle {\n color: var(--muted-subtle);\n font-size: 12px;\n }\n\n a {\n color: var(--accent-2);\n text-decoration: none;\n border-bottom: 1px dashed var(--link-underline);\n }\n\n .content {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .footer {\n display: flex;\n flex-direction: column;\n gap: 10px;\n align-items: center;\n }\n\n .actions {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n justify-content: center;\n }\n\n button {\n appearance: none;\n border: none;\n border-radius: 999px;\n background: linear-gradient(135deg, var(--button-grad-1), var(--button-grad-2));\n color: white;\n padding: 8px 14px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n box-shadow: 0 8px 16px var(--button-shadow);\n transition: transform 160ms ease, box-shadow 160ms ease;\n }\n\n button:hover {\n transform: translateY(-1px);\n box-shadow: 0 10px 20px var(--button-shadow-hover);\n }\n\n button:focus-visible {\n outline: 2px solid var(--accent-2);\n outline-offset: 2px;\n }\n\n .hint {\n font-size: 11px;\n color: var(--muted-hint);\n text-align: center;\n }\n\n @keyframes pulse {\n 0% { box-shadow: 0 0 0 0 var(--pulse-ring); }\n 70% { box-shadow: 0 0 0 10px rgba(255, 107, 44, 0); }\n 100% { box-shadow: 0 0 0 0 rgba(255, 107, 44, 0); }\n }\n</style>\n\n<div id=\"app\">\n <div class=\"header\">\n <span class=\"badge\"><span class=\"pulse\"></span>dev server</span>\n <div class=\"header-text\">\n <h1>CRXJS DEV MODE</h1>\n <p class=\"subtle\">Connecting to the Vite dev server\\u2026</p>\n </div>\n </div>\n\n <div class=\"content\">\n <p>\n Cannot connect to <a href=\"${VITE_URL}\">${VITE_URL}</a>.\n Make sure Vite is running, then reload the extension.\n </p>\n <p>This page will close automatically after the extension reloads.</p>\n </div>\n\n <div class=\"footer\">\n <div class=\"actions\">\n <button>Reload Extension</button>\n </div>\n <div class=\"hint\">Tip: if the URL is wrong, restart Vite so it picks the right port.</div>\n </div>\n</div>\n`;\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";
|
|
1438
1618
|
|
|
1439
|
-
var loadingPageHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>
|
|
1619
|
+
var loadingPageHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>CRXJS DEV MODE</title>\n <script src=\"%SCRIPT%\" type=\"module\"></script>\n </head>\n <body>\n <p>An unknown error occurred. Failed to load the script.</p>\n </body>\n</html>\n";
|
|
1440
1620
|
|
|
1441
1621
|
const { readFile } = promises;
|
|
1442
1622
|
const pluginManifest = () => {
|
|
1443
1623
|
let manifest;
|
|
1444
|
-
let plugins;
|
|
1624
|
+
let plugins = [];
|
|
1445
1625
|
let refId;
|
|
1446
1626
|
let config;
|
|
1447
1627
|
return [
|
|
@@ -1486,6 +1666,14 @@ const pluginManifest = () => {
|
|
|
1486
1666
|
};
|
|
1487
1667
|
}
|
|
1488
1668
|
},
|
|
1669
|
+
// Use configResolved to get plugins for rolldown-vite (Vite 7) compatibility
|
|
1670
|
+
// In rolldown-vite, buildStart doesn't receive options.plugins, so we grab
|
|
1671
|
+
// them from the resolved config instead
|
|
1672
|
+
configResolved(resolvedConfig) {
|
|
1673
|
+
if (resolvedConfig.plugins) {
|
|
1674
|
+
plugins = resolvedConfig.plugins;
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1489
1677
|
buildStart(options) {
|
|
1490
1678
|
if (options.plugins)
|
|
1491
1679
|
plugins = options.plugins;
|
|
@@ -1581,8 +1769,33 @@ const pluginManifest = () => {
|
|
|
1581
1769
|
}
|
|
1582
1770
|
}
|
|
1583
1771
|
if (config.command === "serve") {
|
|
1772
|
+
clearContentCssEntries();
|
|
1584
1773
|
if (manifest2.content_scripts)
|
|
1585
|
-
for (
|
|
1774
|
+
for (let i = 0; i < manifest2.content_scripts.length; i++) {
|
|
1775
|
+
const {
|
|
1776
|
+
js = [],
|
|
1777
|
+
css = [],
|
|
1778
|
+
matches = []
|
|
1779
|
+
} = manifest2.content_scripts[i];
|
|
1780
|
+
if (css.length > 0) {
|
|
1781
|
+
const cssEntry = registerContentCssEntry(i, css);
|
|
1782
|
+
contentScripts.set(
|
|
1783
|
+
cssEntry.virtualId,
|
|
1784
|
+
formatFileData({
|
|
1785
|
+
type: "loader",
|
|
1786
|
+
id: cssEntry.virtualId,
|
|
1787
|
+
matches,
|
|
1788
|
+
refId: hashScriptId({
|
|
1789
|
+
type: "loader",
|
|
1790
|
+
id: cssEntry.virtualId
|
|
1791
|
+
}),
|
|
1792
|
+
fileName: getFileName({
|
|
1793
|
+
type: "loader",
|
|
1794
|
+
id: cssEntry.virtualId
|
|
1795
|
+
})
|
|
1796
|
+
})
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1586
1799
|
for (const id2 of js) {
|
|
1587
1800
|
contentScripts.set(
|
|
1588
1801
|
prefix$1("/", id2),
|
|
@@ -1595,6 +1808,7 @@ const pluginManifest = () => {
|
|
|
1595
1808
|
})
|
|
1596
1809
|
);
|
|
1597
1810
|
}
|
|
1811
|
+
}
|
|
1598
1812
|
} else {
|
|
1599
1813
|
if (manifest2.content_scripts)
|
|
1600
1814
|
for (const { js = [], matches = [] } of manifest2.content_scripts)
|
|
@@ -1652,12 +1866,26 @@ const pluginManifest = () => {
|
|
|
1652
1866
|
const manifestJs = bundle[manifestName];
|
|
1653
1867
|
let manifest2 = decodeManifest.call(this, manifestJs.code);
|
|
1654
1868
|
if (config.command === "serve") {
|
|
1655
|
-
if (manifest2.content_scripts)
|
|
1656
|
-
|
|
1657
|
-
|
|
1869
|
+
if (manifest2.content_scripts) {
|
|
1870
|
+
const cssEntries = getContentCssEntries();
|
|
1871
|
+
const cssEntryMap = new Map(cssEntries.map((e) => [e.index, e]));
|
|
1872
|
+
for (let i = 0; i < manifest2.content_scripts.length; i++) {
|
|
1873
|
+
const script = manifest2.content_scripts[i];
|
|
1874
|
+
const cssEntry = cssEntryMap.get(i);
|
|
1875
|
+
const jsLoaders = (script.js || []).map(
|
|
1658
1876
|
(id) => getFileName({ id, type: "loader" })
|
|
1659
1877
|
);
|
|
1878
|
+
if (cssEntry) {
|
|
1879
|
+
const cssLoader = getFileName({
|
|
1880
|
+
id: cssEntry.virtualId,
|
|
1881
|
+
type: "loader"
|
|
1882
|
+
});
|
|
1883
|
+
script.js = [cssLoader, ...jsLoaders];
|
|
1884
|
+
} else {
|
|
1885
|
+
script.js = jsLoaders;
|
|
1886
|
+
}
|
|
1660
1887
|
}
|
|
1888
|
+
}
|
|
1661
1889
|
} else {
|
|
1662
1890
|
if (manifest2.background && "service_worker" in manifest2.background) {
|
|
1663
1891
|
const ref = manifest2.background.service_worker;
|
|
@@ -1706,6 +1934,7 @@ const pluginManifest = () => {
|
|
|
1706
1934
|
}
|
|
1707
1935
|
}
|
|
1708
1936
|
const assetTypes = [
|
|
1937
|
+
"contentStyles",
|
|
1709
1938
|
"icons",
|
|
1710
1939
|
"locales",
|
|
1711
1940
|
"rulesets",
|
|
@@ -1743,10 +1972,7 @@ Public dir: "${config.publicDir}"`
|
|
|
1743
1972
|
const refId2 = this.emitFile({
|
|
1744
1973
|
type: "asset",
|
|
1745
1974
|
name: "loading-page.js",
|
|
1746
|
-
source: loadingPageScript.replace(
|
|
1747
|
-
"%PORT%",
|
|
1748
|
-
`${config.server.port ?? 0}`
|
|
1749
|
-
)
|
|
1975
|
+
source: loadingPageScript.replace("%PROTO%", config.server.https ? "https" : "http").replace("%PORT%", `${config.server.port ?? 0}`)
|
|
1750
1976
|
});
|
|
1751
1977
|
const loadingPageScriptName = this.getFileName(refId2);
|
|
1752
1978
|
files.html.map(
|
|
@@ -1838,11 +2064,12 @@ const defineDynamicResource = ({
|
|
|
1838
2064
|
});
|
|
1839
2065
|
const DYNAMIC_RESOURCE = "<dynamic_resource>";
|
|
1840
2066
|
|
|
1841
|
-
_debug("web-acc-res");
|
|
2067
|
+
const debug = _debug("web-acc-res");
|
|
1842
2068
|
const pluginWebAccessibleResources = () => {
|
|
1843
2069
|
let config;
|
|
1844
2070
|
let injectCss;
|
|
1845
2071
|
let browser;
|
|
2072
|
+
let userWantsViteManifest;
|
|
1846
2073
|
return [
|
|
1847
2074
|
{
|
|
1848
2075
|
name: "crx:web-accessible-resources",
|
|
@@ -1882,6 +2109,7 @@ const pluginWebAccessibleResources = () => {
|
|
|
1882
2109
|
const contentScripts2 = opts.contentScripts || {};
|
|
1883
2110
|
browser = opts.browser || "chrome";
|
|
1884
2111
|
injectCss = contentScripts2.injectCss ?? true;
|
|
2112
|
+
userWantsViteManifest = build?.manifest;
|
|
1885
2113
|
return { ...config2, build: { ...build, manifest: command === "build" } };
|
|
1886
2114
|
},
|
|
1887
2115
|
configResolved(_config) {
|
|
@@ -2016,6 +2244,18 @@ const pluginWebAccessibleResources = () => {
|
|
|
2016
2244
|
delete manifest.web_accessible_resources;
|
|
2017
2245
|
else
|
|
2018
2246
|
manifest.web_accessible_resources = combinedResources;
|
|
2247
|
+
if (!userWantsViteManifest) {
|
|
2248
|
+
const viteMajorVersion = parseInt(version.split(".")[0]);
|
|
2249
|
+
const manifestPath = viteMajorVersion > 4 ? ".vite/manifest.json" : "manifest.json";
|
|
2250
|
+
if (bundle[manifestPath]) {
|
|
2251
|
+
debug(
|
|
2252
|
+
"Removing Vite manifest: %s (userWantsViteManifest=%s)",
|
|
2253
|
+
manifestPath,
|
|
2254
|
+
userWantsViteManifest
|
|
2255
|
+
);
|
|
2256
|
+
delete bundle[manifestPath];
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2019
2259
|
return manifest;
|
|
2020
2260
|
}
|
|
2021
2261
|
}
|
package/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/index.d.ts'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crxjs/vite-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Build Chrome Extensions with this Vite plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rollup-plugin",
|
|
@@ -27,9 +27,14 @@
|
|
|
27
27
|
"type": "module",
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./index.d.cts",
|
|
36
|
+
"default": "./index.cjs"
|
|
37
|
+
}
|
|
33
38
|
},
|
|
34
39
|
"./*": "./*",
|
|
35
40
|
"./client": {
|
|
@@ -44,13 +49,13 @@
|
|
|
44
49
|
"types",
|
|
45
50
|
"manifest.schema.json",
|
|
46
51
|
"index.cjs",
|
|
52
|
+
"index.d.cts",
|
|
47
53
|
"client.d.ts"
|
|
48
54
|
],
|
|
49
55
|
"dependencies": {
|
|
50
56
|
"@rollup/pluginutils": "^4.1.2",
|
|
51
57
|
"@webcomponents/custom-elements": "^1.5.0",
|
|
52
58
|
"acorn-walk": "^8.2.0",
|
|
53
|
-
"cheerio": "^1.0.0-rc.10",
|
|
54
59
|
"convert-source-map": "^1.7.0",
|
|
55
60
|
"debug": "^4.3.3",
|
|
56
61
|
"es-module-lexer": "^0.10.0",
|
|
@@ -58,6 +63,7 @@
|
|
|
58
63
|
"fs-extra": "^10.0.1",
|
|
59
64
|
"jsesc": "^3.0.2",
|
|
60
65
|
"magic-string": "^0.30.12",
|
|
66
|
+
"node-html-parser": "^7.0.2",
|
|
61
67
|
"pathe": "^2.0.1",
|
|
62
68
|
"picocolors": "^1.1.1",
|
|
63
69
|
"react-refresh": "^0.13.0",
|
|
@@ -102,12 +108,17 @@
|
|
|
102
108
|
"svelte": "^3.48.0",
|
|
103
109
|
"type-fest": "^5.1.0",
|
|
104
110
|
"typescript": "^4.6.4",
|
|
111
|
+
"unocss": "^66.5.12",
|
|
105
112
|
"vite": "^3.2.11",
|
|
106
113
|
"vite-plugin-inspect": "0.7.25",
|
|
107
114
|
"vitest": "0.28.5",
|
|
108
115
|
"vue": "3.2.47"
|
|
109
116
|
},
|
|
117
|
+
"peerDependencies": {
|
|
118
|
+
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
119
|
+
},
|
|
110
120
|
"scripts": {
|
|
121
|
+
"release": "bumpp",
|
|
111
122
|
"format": "prettier -w -c ../../.prettierrc.yaml",
|
|
112
123
|
"build": "run-s build:clean build:js",
|
|
113
124
|
"build:clean": "rimraf dist",
|