@crxjs/vite-plugin 2.0.0-beta.9 → 2.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/README.md +43 -19
- package/client.d.ts +15 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +131 -17
- package/dist/index.mjs +295 -103
- package/index.cjs +8 -0
- package/package.json +38 -36
package/README.md
CHANGED
|
@@ -1,30 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://github.com/crxjs/rollup-plugin-chrome-extension)
|
|
5
|
-

|
|
3
|
+
<h1 align="center">CRXJS</h1>
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
Modern Chrome extension development with built-in <code>HMR</code> and <code>zero-config</code> setup
|
|
7
|
+
</p>
|
|
8
8
|
|
|
9
|
-
>
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@crxjs/vite-plugin">
|
|
11
|
+
<img src="https://img.shields.io/npm/v/@crxjs/vite-plugin?color=298cd6&label=CRXJS&labelColor=f2bae4" alt="NPM version">
|
|
12
|
+
</a>
|
|
13
|
+
</p>
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
<h2 align="center">
|
|
16
|
+
<a href="https://crxjs.dev/vite-plugin">📚 Documentation</a> |
|
|
17
|
+
<a href="https://discord.gg/5yHKEa9v">💬 Discord </a>
|
|
18
|
+
</h2>
|
|
12
19
|
|
|
13
|
-
- True HMR for extension pages and content scripts
|
|
14
|
-
- Simple config - everything is in the extension manifest
|
|
15
|
-
- Static asset imports with automatic web-accessible resources
|
|
16
20
|
|
|
17
|
-
##
|
|
21
|
+
## 📦 Create CRXJS Project
|
|
22
|
+
```shell
|
|
23
|
+
npm create crxjs@latest
|
|
24
|
+
```
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
> [!IMPORTANT]
|
|
27
|
+
> `@latest` MUST NOT be omitted, otherwise `npm` may resolve to a cached and outdated version of the package.
|
|
21
28
|
|
|
22
|
-
##
|
|
29
|
+
## ✨ Features
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
- 🧩 **Full Vite Plugin Ecosystem** - Leverage any Vite-compatible plugins with zero extra setup
|
|
32
|
+
- ⚙️ **Zero Configuration** - Start developing immediately with intelligent defaults
|
|
33
|
+
- 3️⃣ **Manifest V3 Support** - Built for modern Chrome extensions with enhanced security
|
|
34
|
+
- 🔥 **True Hot Module Replacement** - Instant UI updates while preserving extension state 🎈**works with content scripts**
|
|
35
|
+
- 📁 **Static Asset Import** - Directly reference images/fonts in your code
|
|
36
|
+
- 🤖 **Auto Web-Accessible Resources** - Automatic generation of `web_accessible_resources` manifest entries
|
|
37
|
+
|
|
38
|
+
> [!NOTE]
|
|
39
|
+
> Looking for MV2 support? See [`rollup-plugin`](packages/rollup-plugin/README.md)
|
|
40
|
+
|
|
41
|
+
## 💝 Contributors
|
|
42
|
+
|
|
43
|
+
This project exists thanks to all the people who contribute.
|
|
26
44
|
|
|
27
|
-
|
|
45
|
+
And thank you to all our backers! 🙏
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
<a href="https://github.com/crxjs/chrome-extension-tools/graphs/contributors">
|
|
48
|
+
<img src="https://contrib.rocks/image?repo=crxjs/chrome-extension-tools" />
|
|
49
|
+
</a>
|
|
50
|
+
|
|
51
|
+
## 🤝 Supporting
|
|
52
|
+
|
|
53
|
+
If these plugins have helped you ship your product faster, please consider
|
|
54
|
+
[sponsoring me](https://github.com/sponsors/jacksteamdev) on GitHub.
|
package/client.d.ts
CHANGED
|
@@ -57,3 +57,18 @@ declare module '*?script&module' {
|
|
|
57
57
|
const fileName: string
|
|
58
58
|
export default fileName
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
declare namespace ContentScriptAPI {
|
|
62
|
+
export interface ExecuteFnOptions {
|
|
63
|
+
perf: {
|
|
64
|
+
injectTime: number
|
|
65
|
+
loadTime: number
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export interface ExecuteFn {
|
|
69
|
+
(options: ExecuteFnOptions): void
|
|
70
|
+
}
|
|
71
|
+
export interface ModuleExports {
|
|
72
|
+
onExecute?: ExecuteFn
|
|
73
|
+
}
|
|
74
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
const defineManifest = (manifest) => manifest;
|
|
6
6
|
const defineDynamicResource = ({
|
|
7
7
|
matches = ["http://*/*", "https://*/*"],
|
|
8
|
-
use_dynamic_url =
|
|
8
|
+
use_dynamic_url = false
|
|
9
9
|
}) => ({
|
|
10
10
|
matches,
|
|
11
11
|
resources: [DYNAMIC_RESOURCE],
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,14 @@ interface WebAccessibleResourceById {
|
|
|
17
17
|
resources: string[];
|
|
18
18
|
use_dynamic_url?: boolean;
|
|
19
19
|
}
|
|
20
|
+
interface ChromeManifestBackground {
|
|
21
|
+
service_worker: string;
|
|
22
|
+
type?: 'module' | (string & {});
|
|
23
|
+
}
|
|
24
|
+
interface FirefoxManifestBackground {
|
|
25
|
+
scripts: string[];
|
|
26
|
+
persistent?: false;
|
|
27
|
+
}
|
|
20
28
|
interface ManifestV3 {
|
|
21
29
|
manifest_version: number;
|
|
22
30
|
name: string;
|
|
@@ -25,11 +33,13 @@ interface ManifestV3 {
|
|
|
25
33
|
description?: string | undefined;
|
|
26
34
|
icons?: chrome.runtime.ManifestIcons | undefined;
|
|
27
35
|
action?: chrome.runtime.ManifestAction | undefined;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
/**
|
|
37
|
+
* @see https://developer.chrome.com/docs/extensions/reference/manifest/author
|
|
38
|
+
*/
|
|
39
|
+
author?: {
|
|
40
|
+
email: string;
|
|
32
41
|
} | undefined;
|
|
42
|
+
background?: ChromeManifestBackground | FirefoxManifestBackground | undefined;
|
|
33
43
|
chrome_settings_overrides?: {
|
|
34
44
|
homepage?: string | undefined;
|
|
35
45
|
search_provider?: chrome.runtime.SearchProvider | undefined;
|
|
@@ -118,12 +128,12 @@ interface ManifestV3 {
|
|
|
118
128
|
} | undefined;
|
|
119
129
|
incognito?: string | undefined;
|
|
120
130
|
input_components?: {
|
|
121
|
-
name
|
|
122
|
-
type?: string | undefined;
|
|
131
|
+
name: string;
|
|
123
132
|
id?: string | undefined;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
language?: string | string[] | undefined;
|
|
134
|
+
layouts?: string | string[] | undefined;
|
|
135
|
+
input_view?: string | undefined;
|
|
136
|
+
options_page?: string | undefined;
|
|
127
137
|
}[] | undefined;
|
|
128
138
|
key?: string | undefined;
|
|
129
139
|
minimum_chrome_version?: string | undefined;
|
|
@@ -166,6 +176,9 @@ interface ManifestV3 {
|
|
|
166
176
|
pages: string[];
|
|
167
177
|
content_security_policy?: string | undefined;
|
|
168
178
|
} | undefined;
|
|
179
|
+
side_panel?: {
|
|
180
|
+
default_path?: string | undefined;
|
|
181
|
+
} | undefined;
|
|
169
182
|
short_name?: string | undefined;
|
|
170
183
|
spellcheck?: {
|
|
171
184
|
dictionary_language?: string | undefined;
|
|
@@ -189,9 +202,98 @@ interface ManifestV3 {
|
|
|
189
202
|
web_accessible_resources?: (WebAccessibleResourceById | WebAccessibleResourceByMatch)[] | undefined;
|
|
190
203
|
}
|
|
191
204
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
type ManifestV3Fn = (env: ConfigEnv) => ManifestV3 | Promise<ManifestV3>;
|
|
206
|
+
type ManifestV3Export = ManifestV3 | Promise<ManifestV3> | ManifestV3Fn;
|
|
207
|
+
type Code = '.' | '/' | '\\';
|
|
208
|
+
type ManifestFilePath<T extends string> = T extends `${Code}${string}` ? never : T extends `${string}.${infer Ext}` ? Ext extends '' ? never : T : never;
|
|
209
|
+
interface ManifestIcons<T extends string> {
|
|
210
|
+
[size: number]: ManifestFilePath<T>;
|
|
211
|
+
}
|
|
212
|
+
type FilePathFields<T extends string> = {
|
|
213
|
+
icons?: ManifestIcons<T>;
|
|
214
|
+
action?: {
|
|
215
|
+
/**
|
|
216
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
217
|
+
* - Format: "subdir/icon.png" (no leading ./ or /)
|
|
218
|
+
*
|
|
219
|
+
* @example "assets/icon.png"
|
|
220
|
+
*/
|
|
221
|
+
default_icon?: ManifestIcons<T>;
|
|
222
|
+
default_title?: string;
|
|
223
|
+
/**
|
|
224
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
225
|
+
* - Format: "subdir/index.html" (no leading ./ or /)
|
|
226
|
+
*
|
|
227
|
+
* @example "src/popup.html"
|
|
228
|
+
*/
|
|
229
|
+
default_popup?: ManifestFilePath<T>;
|
|
230
|
+
};
|
|
231
|
+
background?: {
|
|
232
|
+
/**
|
|
233
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
234
|
+
* - Format: "subdir/index.js" (no leading ./ or /)
|
|
235
|
+
*
|
|
236
|
+
* @example "src/background.js"
|
|
237
|
+
*/
|
|
238
|
+
service_worker: ManifestFilePath<T>;
|
|
239
|
+
type?: 'module' | (string & {});
|
|
240
|
+
} | FirefoxManifestBackground;
|
|
241
|
+
content_scripts?: {
|
|
242
|
+
matches?: string[];
|
|
243
|
+
exclude_matches?: string[];
|
|
244
|
+
/**
|
|
245
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
246
|
+
* - Format: "subdir/content.css" (no leading ./ or /)
|
|
247
|
+
*
|
|
248
|
+
* @example "src/content.css"
|
|
249
|
+
*/
|
|
250
|
+
css?: ManifestFilePath<T>[];
|
|
251
|
+
/**
|
|
252
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
253
|
+
* - Format: "subdir/content.js" (no leading ./ or /)
|
|
254
|
+
*
|
|
255
|
+
* @example "src/content.js"
|
|
256
|
+
*/
|
|
257
|
+
js?: ManifestFilePath<T>[];
|
|
258
|
+
run_at?: string;
|
|
259
|
+
all_frames?: boolean;
|
|
260
|
+
match_about_blank?: boolean;
|
|
261
|
+
include_globs?: string[];
|
|
262
|
+
exclude_globs?: string[];
|
|
263
|
+
}[];
|
|
264
|
+
input_components?: {
|
|
265
|
+
name: string;
|
|
266
|
+
id?: string;
|
|
267
|
+
language?: string | string[];
|
|
268
|
+
layouts?: string | string[];
|
|
269
|
+
input_view?: string;
|
|
270
|
+
/**
|
|
271
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
272
|
+
* - Format: "subdir/options.html" (no leading ./ or /)
|
|
273
|
+
*
|
|
274
|
+
* @example "src/options.html"
|
|
275
|
+
*/
|
|
276
|
+
options_page?: ManifestFilePath<T>;
|
|
277
|
+
}[];
|
|
278
|
+
/**
|
|
279
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
280
|
+
* - Format: "subdir/options.html" (no leading ./ or /)
|
|
281
|
+
*
|
|
282
|
+
* @example "src/options.html"
|
|
283
|
+
*/
|
|
284
|
+
options_page?: ManifestFilePath<T>;
|
|
285
|
+
/**
|
|
286
|
+
* - Relative to Vite project root (where vite.config.js is)
|
|
287
|
+
* - Format: "subdir/devtools.html" (no leading ./ or /)
|
|
288
|
+
*
|
|
289
|
+
* @example "src/devtools.html"
|
|
290
|
+
*/
|
|
291
|
+
devtools_page?: ManifestFilePath<T>;
|
|
292
|
+
};
|
|
293
|
+
type ManifestOptions<T extends string> = Omit<ManifestV3, keyof FilePathFields<string>> & FilePathFields<T>;
|
|
294
|
+
type ManifestV3Options<T extends string = string> = ManifestOptions<T> | Promise<ManifestOptions<T>> | ManifestV3Define<T>;
|
|
295
|
+
type ManifestV3Define<T extends string> = (env: ConfigEnv) => ManifestOptions<T> | Promise<ManifestOptions<T>>;
|
|
296
|
+
declare const defineManifest: <T extends string>(manifest: ManifestV3Options<T>) => ManifestV3Export;
|
|
195
297
|
/**
|
|
196
298
|
* Content script resources like CSS and image files must be declared in the
|
|
197
299
|
* manifest under `web_accessible_resources`. Manifest V3 uses a match pattern
|
|
@@ -219,19 +321,25 @@ declare const defineManifest: (manifest: ManifestV3Export) => ManifestV3Export;
|
|
|
219
321
|
*/
|
|
220
322
|
declare const defineDynamicResource: ({ matches, use_dynamic_url, }: Omit<WebAccessibleResourceByMatch, 'resources'>) => WebAccessibleResourceByMatch;
|
|
221
323
|
|
|
222
|
-
|
|
324
|
+
type CrxDevAssetId = {
|
|
223
325
|
id: string;
|
|
224
326
|
type: 'asset';
|
|
225
327
|
source?: string | Uint8Array;
|
|
226
328
|
};
|
|
227
|
-
|
|
329
|
+
type CrxDevScriptId = {
|
|
228
330
|
id: string;
|
|
229
331
|
type: 'module' | 'iife';
|
|
230
332
|
};
|
|
231
333
|
interface CrxPlugin extends Plugin {
|
|
232
|
-
/**
|
|
334
|
+
/**
|
|
335
|
+
* Runs during the transform hook for the manifest. Filenames use input
|
|
336
|
+
* filenames.
|
|
337
|
+
*/
|
|
233
338
|
transformCrxManifest?: (this: PluginContext, manifest: ManifestV3) => Promise<ManifestV3 | null | undefined> | ManifestV3 | null | undefined;
|
|
234
|
-
/**
|
|
339
|
+
/**
|
|
340
|
+
* Runs during generateBundle, before manifest output. Filenames use output
|
|
341
|
+
* filenames.
|
|
342
|
+
*/
|
|
235
343
|
renderCrxManifest?: (this: PluginContext, manifest: ManifestV3, bundle: OutputBundle) => Promise<ManifestV3 | null | undefined> | ManifestV3 | null | undefined;
|
|
236
344
|
/**
|
|
237
345
|
* Runs in the file writer on content scripts during development. `script.id`
|
|
@@ -246,12 +354,18 @@ interface CrxOptions {
|
|
|
246
354
|
injectCss?: boolean;
|
|
247
355
|
};
|
|
248
356
|
fastGlobOptions?: Options;
|
|
357
|
+
/**
|
|
358
|
+
* The browser that this extension is targeting, can be "firefox" or "chrome".
|
|
359
|
+
* Default is "chrome".
|
|
360
|
+
*/
|
|
361
|
+
browser?: Browser;
|
|
249
362
|
}
|
|
363
|
+
type Browser = 'firefox' | 'chrome';
|
|
250
364
|
|
|
251
365
|
/** Resolves when all existing files in scriptFiles are written. */
|
|
252
366
|
declare function allFilesReady(): Promise<void>;
|
|
253
367
|
|
|
254
|
-
|
|
368
|
+
type FileWriterId = {
|
|
255
369
|
type: CrxDevAssetId['type'] | CrxDevScriptId['type'] | 'loader';
|
|
256
370
|
id: string;
|
|
257
371
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { simple } from 'acorn-walk';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
|
-
import debug$
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { Subject, filter, ReplaySubject, switchMap, of, startWith, map, mergeMap, firstValueFrom, takeUntil, first, toArray, retry, concatWith, Subscription, buffer } from 'rxjs';
|
|
3
|
+
import debug$3 from 'debug';
|
|
4
|
+
import { join, normalize, isAbsolute, basename, relative, resolve, dirname, parse } from 'pathe';
|
|
5
|
+
import { Subject, filter, ReplaySubject, switchMap, of, startWith, map, BehaviorSubject, mergeMap, firstValueFrom, takeUntil, first, toArray, retry, concatWith, Subscription, buffer } from 'rxjs';
|
|
7
6
|
import fsx from 'fs-extra';
|
|
8
7
|
import { performance } from 'perf_hooks';
|
|
9
8
|
import { rollup } from 'rollup';
|
|
10
9
|
import * as lexer from 'es-module-lexer';
|
|
11
10
|
import { readFile as readFile$1 } from 'fs/promises';
|
|
12
11
|
import MagicString from 'magic-string';
|
|
13
|
-
import
|
|
12
|
+
import convertSourceMap from 'convert-source-map';
|
|
13
|
+
import { createLogger, version } from 'vite';
|
|
14
14
|
import { readFileSync, existsSync, promises } from 'fs';
|
|
15
15
|
import { createRequire } from 'module';
|
|
16
16
|
import fg from 'fast-glob';
|
|
17
|
+
import pc from 'picocolors';
|
|
17
18
|
import { load } from 'cheerio';
|
|
18
19
|
import jsesc from 'jsesc';
|
|
19
|
-
import colors from 'picocolors';
|
|
20
20
|
|
|
21
21
|
const pluginName$1 = "crx:optionsProvider";
|
|
22
22
|
const pluginOptionsProvider = (options) => {
|
|
@@ -24,8 +24,10 @@ const pluginOptionsProvider = (options) => {
|
|
|
24
24
|
name: pluginName$1,
|
|
25
25
|
api: {
|
|
26
26
|
crx: {
|
|
27
|
+
// during testing this can be null, we don't provide options through the test config
|
|
27
28
|
options
|
|
28
29
|
}
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
31
|
}
|
|
30
32
|
};
|
|
31
33
|
};
|
|
@@ -56,12 +58,9 @@ function isCrxPlugin(p) {
|
|
|
56
58
|
return !!p && typeof p === "object" && !(p instanceof Promise) && !Array.isArray(p) && p.name.startsWith("crx:");
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
var workerHmrClient = "const ownOrigin =
|
|
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 = \"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 headers: requestHeaders\n });\n const responseHeaders = new Headers(response.headers);\n responseHeaders.set(\"Content-Type\", responseHeaders.get(\"Content-Type\") ?? \"text/javascript\");\n responseHeaders.set(\"Cache-Control\", responseHeaders.get(\"Cache-Control\") ?? \"\");\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(`${socketProtocol}://${socketHost}?token=${socketToken}`, \"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";
|
|
60
62
|
|
|
61
|
-
const _debug = (id) => debug$
|
|
62
|
-
const structuredClone = (obj) => {
|
|
63
|
-
return v8.deserialize(v8.serialize(obj));
|
|
64
|
-
};
|
|
63
|
+
const _debug = (id) => debug$3("crx").extend(id);
|
|
65
64
|
const hash = (data, length = 5) => createHash("sha1").update(data).digest("base64").replace(/[^A-Za-z0-9]/g, "").slice(0, length);
|
|
66
65
|
const isString = (x) => typeof x === "string";
|
|
67
66
|
function isObject(value) {
|
|
@@ -113,22 +112,6 @@ const getMatchPatternOrigin = (pattern) => {
|
|
|
113
112
|
return pathname ? `${root}/*` : root;
|
|
114
113
|
};
|
|
115
114
|
|
|
116
|
-
const {
|
|
117
|
-
basename,
|
|
118
|
-
dirname,
|
|
119
|
-
extname,
|
|
120
|
-
delimiter,
|
|
121
|
-
format,
|
|
122
|
-
isAbsolute,
|
|
123
|
-
join,
|
|
124
|
-
normalize,
|
|
125
|
-
parse,
|
|
126
|
-
relative,
|
|
127
|
-
resolve,
|
|
128
|
-
toNamespacedPath,
|
|
129
|
-
sep
|
|
130
|
-
} = posix;
|
|
131
|
-
|
|
132
115
|
function defineClientValues(code, config) {
|
|
133
116
|
let options = config.server.hmr;
|
|
134
117
|
options = options && typeof options !== "boolean" ? options : {};
|
|
@@ -152,7 +135,7 @@ function defineClientValues(code, config) {
|
|
|
152
135
|
if (hmrBase !== "/") {
|
|
153
136
|
hmrPort = normalize(`${hmrPort}${hmrBase}`);
|
|
154
137
|
}
|
|
155
|
-
return code.replace(`__MODE__`, JSON.stringify(config.mode)).replace(`__BASE__`, JSON.stringify(config.base)).replace(`__DEFINES__`, serializeDefine(config.define || {})).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(`__SERVER_PORT__`, JSON.stringify(config.server.port?.toString()));
|
|
138
|
+
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(`__SERVER_PORT__`, JSON.stringify(config.server.port?.toString()));
|
|
156
139
|
function serializeDefine(define) {
|
|
157
140
|
let res = `{`;
|
|
158
141
|
for (const key in define) {
|
|
@@ -204,7 +187,7 @@ function formatFileData(script) {
|
|
|
204
187
|
return script;
|
|
205
188
|
}
|
|
206
189
|
function getFileName({ type, id }) {
|
|
207
|
-
let fileName = id.replace(/t=\d+&/, "").replace(/^\//, "").replace(/\?/g, "__").replace(/&/g, "_").replace(/=/g, "--");
|
|
190
|
+
let fileName = id.replace(/t=\d+&/, "").replace(/\?t=\d+$/, "").replace(/^\//, "").replace(/\?/g, "__").replace(/&/g, "_").replace(/=/g, "--");
|
|
208
191
|
if (fileName.includes("node_modules/")) {
|
|
209
192
|
fileName = `vendor/${fileName.split("node_modules/").pop().replace(/\//g, "-")}`;
|
|
210
193
|
} else if (fileName.startsWith("@")) {
|
|
@@ -272,6 +255,7 @@ const workerClientId = "/@crx/client-worker";
|
|
|
272
255
|
|
|
273
256
|
const pluginBackground = () => {
|
|
274
257
|
let config;
|
|
258
|
+
let browser;
|
|
275
259
|
return [
|
|
276
260
|
{
|
|
277
261
|
name: "crx:background-client",
|
|
@@ -292,24 +276,39 @@ const pluginBackground = () => {
|
|
|
292
276
|
},
|
|
293
277
|
{
|
|
294
278
|
name: "crx:background-loader-file",
|
|
279
|
+
// this should happen after other plugins; the loader file is an implementation detail
|
|
295
280
|
enforce: "post",
|
|
281
|
+
async config(config2) {
|
|
282
|
+
const opts = await getOptions(config2);
|
|
283
|
+
browser = opts.browser || "chrome";
|
|
284
|
+
},
|
|
296
285
|
configResolved(_config) {
|
|
297
286
|
config = _config;
|
|
298
287
|
},
|
|
299
288
|
renderCrxManifest(manifest) {
|
|
300
|
-
const worker = manifest.background?.service_worker;
|
|
289
|
+
const worker = browser === "firefox" ? manifest.background?.scripts[0] : manifest.background?.service_worker;
|
|
301
290
|
let loader;
|
|
302
291
|
if (config.command === "serve") {
|
|
303
292
|
const port = config.server.port?.toString();
|
|
304
293
|
if (typeof port === "undefined")
|
|
305
294
|
throw new Error("server port is undefined in watch mode");
|
|
306
|
-
|
|
295
|
+
if (browser === "firefox") {
|
|
296
|
+
loader = `import('http://localhost:${port}/@vite/env');
|
|
297
|
+
`;
|
|
298
|
+
loader += `import('http://localhost:${port}${workerClientId}');
|
|
299
|
+
`;
|
|
300
|
+
if (worker)
|
|
301
|
+
loader += `import('http://localhost:${port}/${worker}');
|
|
302
|
+
`;
|
|
303
|
+
} else {
|
|
304
|
+
loader = `import 'http://localhost:${port}/@vite/env';
|
|
307
305
|
`;
|
|
308
|
-
|
|
306
|
+
loader += `import 'http://localhost:${port}${workerClientId}';
|
|
309
307
|
`;
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
if (worker)
|
|
309
|
+
loader += `import 'http://localhost:${port}/${worker}';
|
|
312
310
|
`;
|
|
311
|
+
}
|
|
313
312
|
} else if (worker) {
|
|
314
313
|
loader = `import './${worker}';
|
|
315
314
|
`;
|
|
@@ -318,13 +317,21 @@ const pluginBackground = () => {
|
|
|
318
317
|
}
|
|
319
318
|
const refId = this.emitFile({
|
|
320
319
|
type: "asset",
|
|
320
|
+
// fileName b/c service worker must be at root of crx
|
|
321
321
|
fileName: getFileName({ type: "loader", id: "service-worker" }),
|
|
322
322
|
source: loader
|
|
323
323
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
324
|
+
if (browser !== "firefox") {
|
|
325
|
+
manifest.background = {
|
|
326
|
+
service_worker: this.getFileName(refId),
|
|
327
|
+
type: "module"
|
|
328
|
+
};
|
|
329
|
+
} else {
|
|
330
|
+
manifest.background = {
|
|
331
|
+
scripts: [this.getFileName(refId)],
|
|
332
|
+
type: "module"
|
|
333
|
+
};
|
|
334
|
+
}
|
|
328
335
|
return manifest;
|
|
329
336
|
}
|
|
330
337
|
}
|
|
@@ -333,9 +340,9 @@ const pluginBackground = () => {
|
|
|
333
340
|
|
|
334
341
|
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";
|
|
335
342
|
|
|
336
|
-
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";
|
|
343
|
+
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";
|
|
337
344
|
|
|
338
|
-
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";
|
|
345
|
+
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";
|
|
339
346
|
|
|
340
347
|
const contentScripts = new RxMap();
|
|
341
348
|
contentScripts.change$.pipe(filter(RxMap.isChangeType.set)).subscribe(({ map, value }) => {
|
|
@@ -393,6 +400,10 @@ const allFilesReady$ = buildEnd$.pipe(
|
|
|
393
400
|
map(() => [...outputFiles.values()]),
|
|
394
401
|
switchMap((files) => Promise.allSettled(files.map(({ file }) => file)))
|
|
395
402
|
);
|
|
403
|
+
const timestamp$ = new BehaviorSubject(Date.now());
|
|
404
|
+
allFilesReady$.subscribe(() => {
|
|
405
|
+
timestamp$.next(Date.now());
|
|
406
|
+
});
|
|
396
407
|
const isRejected = (x) => x?.status === "rejected";
|
|
397
408
|
const fileWriterError$ = allFilesReady$.pipe(
|
|
398
409
|
mergeMap((results) => results.filter(isRejected)),
|
|
@@ -426,16 +437,36 @@ function prepAsset(fileName, { id, source }) {
|
|
|
426
437
|
}
|
|
427
438
|
function prepScript(fileName, script) {
|
|
428
439
|
return ($) => $.pipe(
|
|
440
|
+
// get script contents from dev server
|
|
429
441
|
mergeMap(async ({ server }) => {
|
|
430
442
|
const target = getOutputPath(server, fileName);
|
|
431
443
|
const viteUrl = getViteUrl(script);
|
|
432
444
|
const transformResult = await server.transformRequest(viteUrl);
|
|
433
445
|
if (!transformResult)
|
|
434
446
|
throw new TypeError(`Unable to load "${script.id}" from server.`);
|
|
435
|
-
const {
|
|
436
|
-
|
|
447
|
+
const { deps = [], dynamicDeps = [], map: map2 } = transformResult;
|
|
448
|
+
let { code } = transformResult;
|
|
449
|
+
try {
|
|
450
|
+
if (map2 && server.config.build.sourcemap === "inline") {
|
|
451
|
+
code = code.replace(/\n*\/\/# sourceMappingURL=[^\n]+/g, "");
|
|
452
|
+
const sourceMap = convertSourceMap.fromObject(map2).toComment();
|
|
453
|
+
code += `
|
|
454
|
+
${sourceMap}
|
|
455
|
+
`;
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
console.warn("Failed to inline source map", error);
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
target,
|
|
462
|
+
code,
|
|
463
|
+
deps: [...deps, ...dynamicDeps].flat(),
|
|
464
|
+
server
|
|
465
|
+
};
|
|
437
466
|
}),
|
|
467
|
+
// retry in case of dependency rebundle
|
|
438
468
|
retry({ count: 10, delay: 100 }),
|
|
469
|
+
// patch content scripts
|
|
439
470
|
mergeMap(async ({ target, server, ...rest }) => {
|
|
440
471
|
const plugins = server.config.plugins;
|
|
441
472
|
let { code, deps } = rest;
|
|
@@ -455,7 +486,8 @@ function prepScript(fileName, script) {
|
|
|
455
486
|
if (i.n) {
|
|
456
487
|
depSet.add(i.n);
|
|
457
488
|
const fileName2 = getFileName({ type: "module", id: i.n });
|
|
458
|
-
|
|
489
|
+
const fullImport = code.substring(i.s, i.e);
|
|
490
|
+
magic.overwrite(i.s, i.e, fullImport.replace(i.n, `/${fileName2}`));
|
|
459
491
|
}
|
|
460
492
|
return { target, source: magic.toString(), deps: [...depSet] };
|
|
461
493
|
})
|
|
@@ -526,8 +558,11 @@ function update(_id) {
|
|
|
526
558
|
async function write(fileId) {
|
|
527
559
|
const start2 = performance.now();
|
|
528
560
|
const deps = await firstValueFrom(
|
|
561
|
+
// wait for start event
|
|
529
562
|
start$.pipe(
|
|
563
|
+
// prepare either asset or script contents
|
|
530
564
|
prepFileData(fileId),
|
|
565
|
+
// output file and add dependencies to file writer
|
|
531
566
|
mergeMap(async ({ target, source, deps: deps2 }) => {
|
|
532
567
|
const files = deps2.map((id) => {
|
|
533
568
|
const r = [add({ id, type: "module" })];
|
|
@@ -543,6 +578,7 @@ async function write(fileId) {
|
|
|
543
578
|
await outputFile(target, source, { encoding: "utf8" });
|
|
544
579
|
return files;
|
|
545
580
|
}),
|
|
581
|
+
// abort write operation on close event
|
|
546
582
|
takeUntil(close$),
|
|
547
583
|
concatWith(of([]))
|
|
548
584
|
)
|
|
@@ -633,7 +669,20 @@ const pluginContentScripts = () => {
|
|
|
633
669
|
name: "crx:content-scripts",
|
|
634
670
|
apply: "build",
|
|
635
671
|
enforce: "pre",
|
|
636
|
-
|
|
672
|
+
config(config) {
|
|
673
|
+
return {
|
|
674
|
+
...config,
|
|
675
|
+
build: {
|
|
676
|
+
...config.build,
|
|
677
|
+
rollupOptions: {
|
|
678
|
+
...config.build?.rollupOptions,
|
|
679
|
+
// keep exports for content script module api
|
|
680
|
+
preserveEntrySignatures: config.build?.rollupOptions?.preserveEntrySignatures ?? "exports-only"
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
},
|
|
685
|
+
generateBundle(_options, bundle) {
|
|
637
686
|
for (const [key, script] of contentScripts)
|
|
638
687
|
if (key === script.refId) {
|
|
639
688
|
if (script.type === "module") {
|
|
@@ -642,12 +691,22 @@ const pluginContentScripts = () => {
|
|
|
642
691
|
} else if (script.type === "loader") {
|
|
643
692
|
const fileName = this.getFileName(script.refId);
|
|
644
693
|
script.fileName = fileName;
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
694
|
+
const bundleFileInfo = bundle[fileName];
|
|
695
|
+
const shouldUseLoader = !(bundleFileInfo.type === "chunk" && bundleFileInfo.imports.length === 0 && bundleFileInfo.dynamicImports.length === 0 && bundleFileInfo.exports.length === 0);
|
|
696
|
+
if (shouldUseLoader) {
|
|
697
|
+
const refId = this.emitFile({
|
|
698
|
+
type: "asset",
|
|
699
|
+
name: getFileName({
|
|
700
|
+
type: "loader",
|
|
701
|
+
id: basename(script.id)
|
|
702
|
+
}),
|
|
703
|
+
source: createProLoader({ fileName })
|
|
704
|
+
});
|
|
705
|
+
script.loaderName = this.getFileName(refId);
|
|
706
|
+
} else {
|
|
707
|
+
bundleFileInfo.code = `(function(){${bundleFileInfo.code}})()
|
|
708
|
+
`;
|
|
709
|
+
}
|
|
651
710
|
} else if (script.type === "iife") {
|
|
652
711
|
throw new Error("IIFE content scripts are not implemented");
|
|
653
712
|
}
|
|
@@ -707,6 +766,34 @@ const pluginDynamicContentScripts = () => {
|
|
|
707
766
|
configResolved(_config) {
|
|
708
767
|
config = _config;
|
|
709
768
|
},
|
|
769
|
+
configureServer(server) {
|
|
770
|
+
return () => {
|
|
771
|
+
server.middlewares.use(async (req, res, next) => {
|
|
772
|
+
try {
|
|
773
|
+
await allFilesReady();
|
|
774
|
+
next();
|
|
775
|
+
} catch (error) {
|
|
776
|
+
let err;
|
|
777
|
+
if (error instanceof Error) {
|
|
778
|
+
err = error;
|
|
779
|
+
} else if (typeof error === "string") {
|
|
780
|
+
err = new Error(error);
|
|
781
|
+
} else {
|
|
782
|
+
err = new Error(
|
|
783
|
+
`Unexpected error "${error}" in middleware for "${req.url}"`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
server.ws.send({
|
|
787
|
+
type: "error",
|
|
788
|
+
err: {
|
|
789
|
+
message: err.message,
|
|
790
|
+
stack: err.stack ?? "no stack available"
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
};
|
|
796
|
+
},
|
|
710
797
|
async resolveId(_source, importer) {
|
|
711
798
|
if (importer && _source.includes("?script")) {
|
|
712
799
|
const url = new URL(_source, "stub://stub");
|
|
@@ -775,7 +862,6 @@ const pluginDynamicContentScripts = () => {
|
|
|
775
862
|
if (config.command === "build") {
|
|
776
863
|
return `export default import.meta.CRX_DYNAMIC_SCRIPT_${script.refId};`;
|
|
777
864
|
} else if (typeof script.fileName === "string") {
|
|
778
|
-
await fileReady(script);
|
|
779
865
|
return `export default ${JSON.stringify(script.fileName)};`;
|
|
780
866
|
} else {
|
|
781
867
|
throw new Error(
|
|
@@ -788,6 +874,12 @@ const pluginDynamicContentScripts = () => {
|
|
|
788
874
|
{
|
|
789
875
|
name: "crx:dynamic-content-scripts-build",
|
|
790
876
|
apply: "build",
|
|
877
|
+
/**
|
|
878
|
+
* Replace dynamic script placeholders during build.
|
|
879
|
+
*
|
|
880
|
+
* Can't use `renderChunk` b/c pre plugin crx:content-scripts uses
|
|
881
|
+
* `generateBundle` to emit loaders. Must come after "enforce: pre".
|
|
882
|
+
*/
|
|
791
883
|
generateBundle(options, bundle) {
|
|
792
884
|
for (const chunk of Object.values(bundle))
|
|
793
885
|
if (chunk.type === "chunk") {
|
|
@@ -817,29 +909,42 @@ const pluginDynamicContentScripts = () => {
|
|
|
817
909
|
];
|
|
818
910
|
};
|
|
819
911
|
|
|
912
|
+
const { remove } = fsx;
|
|
820
913
|
const logger = createLogger("error", { prefix: "crxjs" });
|
|
821
914
|
const pluginFileWriter = () => {
|
|
822
915
|
fileWriterError$.subscribe((error) => {
|
|
823
916
|
logger.error(error.err.message, { error: error.err });
|
|
824
917
|
});
|
|
825
|
-
return
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
console.error(error);
|
|
834
|
-
server.close();
|
|
918
|
+
return [
|
|
919
|
+
{
|
|
920
|
+
name: "crx:file-writer-empty-out-dir",
|
|
921
|
+
apply: "serve",
|
|
922
|
+
enforce: "pre",
|
|
923
|
+
async configResolved(config) {
|
|
924
|
+
if (config.build.emptyOutDir) {
|
|
925
|
+
await remove(config.build.outDir);
|
|
835
926
|
}
|
|
836
|
-
}
|
|
837
|
-
server.httpServer?.on("close", () => close());
|
|
927
|
+
}
|
|
838
928
|
},
|
|
839
|
-
|
|
840
|
-
|
|
929
|
+
{
|
|
930
|
+
name: "crx:file-writer",
|
|
931
|
+
apply: "serve",
|
|
932
|
+
configureServer(server) {
|
|
933
|
+
server.httpServer?.on("listening", async () => {
|
|
934
|
+
try {
|
|
935
|
+
await start({ server });
|
|
936
|
+
} catch (error) {
|
|
937
|
+
console.error(error);
|
|
938
|
+
server.close();
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
server.httpServer?.on("close", () => close());
|
|
942
|
+
},
|
|
943
|
+
closeBundle() {
|
|
944
|
+
outputFiles.clear();
|
|
945
|
+
}
|
|
841
946
|
}
|
|
842
|
-
|
|
947
|
+
];
|
|
843
948
|
};
|
|
844
949
|
|
|
845
950
|
const _require = typeof require === "undefined" ? createRequire(import.meta.url) : require;
|
|
@@ -884,7 +989,9 @@ async function manifestFiles(manifest, options = {}) {
|
|
|
884
989
|
) ?? [];
|
|
885
990
|
const contentScripts = manifest.content_scripts?.flatMap(({ js }) => js) ?? [];
|
|
886
991
|
const contentStyles = manifest.content_scripts?.flatMap(({ css }) => css);
|
|
887
|
-
const serviceWorker = manifest.background
|
|
992
|
+
const serviceWorker = manifest.background && "service_worker" in manifest.background ? manifest.background.service_worker : void 0;
|
|
993
|
+
const backgroundScripts = manifest.background && "scripts" in manifest.background ? manifest.background.scripts : void 0;
|
|
994
|
+
const background = serviceWorker ? [serviceWorker].filter(isString) : backgroundScripts ? backgroundScripts.filter(isString) : [];
|
|
888
995
|
const htmlPages = htmlFiles(manifest);
|
|
889
996
|
const icons = [
|
|
890
997
|
Object.values(
|
|
@@ -905,7 +1012,7 @@ async function manifestFiles(manifest, options = {}) {
|
|
|
905
1012
|
return r;
|
|
906
1013
|
})
|
|
907
1014
|
);
|
|
908
|
-
webAccessibleResources = resources.flat().filter(isString);
|
|
1015
|
+
webAccessibleResources = [...new Set(resources.flat())].filter(isString);
|
|
909
1016
|
}
|
|
910
1017
|
return {
|
|
911
1018
|
contentScripts: [...new Set(contentScripts)].filter(isString),
|
|
@@ -914,12 +1021,12 @@ async function manifestFiles(manifest, options = {}) {
|
|
|
914
1021
|
icons: [...new Set(icons)].filter(isString),
|
|
915
1022
|
locales: [...new Set(locales)].filter(isString),
|
|
916
1023
|
rulesets: [...new Set(rulesets)].filter(isString),
|
|
917
|
-
background
|
|
1024
|
+
background,
|
|
918
1025
|
webAccessibleResources
|
|
919
1026
|
};
|
|
920
1027
|
}
|
|
921
1028
|
async function dirFiles(dir) {
|
|
922
|
-
const files = await fg(
|
|
1029
|
+
const files = await fg(join(dir, "**", "*"));
|
|
923
1030
|
return files;
|
|
924
1031
|
}
|
|
925
1032
|
function htmlFiles(manifest) {
|
|
@@ -929,7 +1036,8 @@ function htmlFiles(manifest) {
|
|
|
929
1036
|
manifest.devtools_page,
|
|
930
1037
|
manifest.options_page,
|
|
931
1038
|
manifest.options_ui?.page,
|
|
932
|
-
manifest.sandbox?.pages
|
|
1039
|
+
manifest.sandbox?.pages,
|
|
1040
|
+
manifest.side_panel?.default_path
|
|
933
1041
|
].flat().filter(isString).map((s) => s.split("#")[0]).sort();
|
|
934
1042
|
return [...new Set(files)];
|
|
935
1043
|
}
|
|
@@ -954,11 +1062,13 @@ const pluginFileWriterPublic = () => {
|
|
|
954
1062
|
};
|
|
955
1063
|
};
|
|
956
1064
|
|
|
957
|
-
_debug("file-writer").extend("hmr");
|
|
958
|
-
const
|
|
1065
|
+
const debug$2 = _debug("file-writer").extend("hmr");
|
|
1066
|
+
const isCustomPayload = (p) => {
|
|
1067
|
+
return p.type === "custom";
|
|
1068
|
+
};
|
|
959
1069
|
const hmrPayload$ = new Subject();
|
|
960
1070
|
const crxHMRPayload$ = hmrPayload$.pipe(
|
|
961
|
-
filter((p) => !
|
|
1071
|
+
filter((p) => !isCustomPayload(p)),
|
|
962
1072
|
buffer(allFilesReady$),
|
|
963
1073
|
mergeMap((pps) => {
|
|
964
1074
|
let fullReload;
|
|
@@ -1017,6 +1127,7 @@ const crxHMRPayload$ = hmrPayload$.pipe(
|
|
|
1017
1127
|
}
|
|
1018
1128
|
}),
|
|
1019
1129
|
map((data) => {
|
|
1130
|
+
debug$2(`hmr payload`, data);
|
|
1020
1131
|
return {
|
|
1021
1132
|
type: "custom",
|
|
1022
1133
|
event: "crx:content-script-payload",
|
|
@@ -1056,6 +1167,7 @@ const pluginHMR = () => {
|
|
|
1056
1167
|
name: "crx:hmr",
|
|
1057
1168
|
apply: "serve",
|
|
1058
1169
|
enforce: "pre",
|
|
1170
|
+
// server hmr host should be localhost
|
|
1059
1171
|
async config({ server = {}, ...config2 }) {
|
|
1060
1172
|
if (server.hmr === false)
|
|
1061
1173
|
return;
|
|
@@ -1065,6 +1177,7 @@ const pluginHMR = () => {
|
|
|
1065
1177
|
server.hmr.host = "localhost";
|
|
1066
1178
|
return { server, ...config2 };
|
|
1067
1179
|
},
|
|
1180
|
+
// server should ignore outdir
|
|
1068
1181
|
configResolved(_config) {
|
|
1069
1182
|
config = _config;
|
|
1070
1183
|
const { watch = {} } = config.server;
|
|
@@ -1102,19 +1215,24 @@ const pluginHMR = () => {
|
|
|
1102
1215
|
closeBundle() {
|
|
1103
1216
|
subs.unsubscribe();
|
|
1104
1217
|
},
|
|
1218
|
+
// background changes require a full extension reload
|
|
1105
1219
|
handleHotUpdate({ modules, server }) {
|
|
1106
1220
|
const { root } = server.config;
|
|
1107
1221
|
const relFiles = /* @__PURE__ */ new Set();
|
|
1108
|
-
|
|
1222
|
+
const fsFiles = /* @__PURE__ */ new Set();
|
|
1223
|
+
for (const m of modules) {
|
|
1109
1224
|
if (m.id?.startsWith(root)) {
|
|
1110
1225
|
relFiles.add(m.id.slice(server.config.root.length));
|
|
1226
|
+
} else if (m.url?.startsWith("/@fs")) {
|
|
1227
|
+
fsFiles.add(m.url);
|
|
1111
1228
|
}
|
|
1229
|
+
}
|
|
1230
|
+
fsFiles.forEach((file) => update(file));
|
|
1112
1231
|
if (inputManifestFiles.background.length) {
|
|
1113
1232
|
const background = prefix$1("/", inputManifestFiles.background[0]);
|
|
1114
1233
|
if (relFiles.has(background) || modules.some(isImporter(join(server.config.root, background)))) {
|
|
1115
1234
|
debug$1("sending runtime reload");
|
|
1116
1235
|
server.ws.send(crxRuntimeReload);
|
|
1117
|
-
return [];
|
|
1118
1236
|
}
|
|
1119
1237
|
}
|
|
1120
1238
|
for (const [key, script] of contentScripts)
|
|
@@ -1129,6 +1247,7 @@ const pluginHMR = () => {
|
|
|
1129
1247
|
name: "crx:hmr",
|
|
1130
1248
|
apply: "serve",
|
|
1131
1249
|
enforce: "post",
|
|
1250
|
+
// get final output manifest for handleHotUpdate 👆
|
|
1132
1251
|
async transformCrxManifest(manifest) {
|
|
1133
1252
|
inputManifestFiles = await manifestFiles(manifest, { cwd: config.root });
|
|
1134
1253
|
return null;
|
|
@@ -1151,6 +1270,31 @@ const pluginHMR = () => {
|
|
|
1151
1270
|
];
|
|
1152
1271
|
};
|
|
1153
1272
|
|
|
1273
|
+
function printStr(dir) {
|
|
1274
|
+
return ` ${pc.magentaBright("B R O W S E R")}
|
|
1275
|
+
${pc.greenBright("E X T E N S I O N")}
|
|
1276
|
+
${pc.blueBright("T O O L S")}
|
|
1277
|
+
|
|
1278
|
+
${pc.green("\u279C")} ${pc.bold("CRXJS")}: ${pc.green(`Load ${pc.cyan(dir)} as unpacked extension`)}`;
|
|
1279
|
+
}
|
|
1280
|
+
const pluginPrint = () => {
|
|
1281
|
+
let outDir = "dist";
|
|
1282
|
+
return [
|
|
1283
|
+
{
|
|
1284
|
+
name: "crx:print",
|
|
1285
|
+
enforce: "pre",
|
|
1286
|
+
configResolved(resolvedConfig) {
|
|
1287
|
+
outDir = resolvedConfig.build.outDir;
|
|
1288
|
+
},
|
|
1289
|
+
configureServer(server) {
|
|
1290
|
+
server.printUrls = () => {
|
|
1291
|
+
console.log(printStr(outDir));
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
];
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1154
1298
|
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";
|
|
1155
1299
|
|
|
1156
1300
|
const pluginName = "crx:html-inline-scripts";
|
|
@@ -1219,6 +1363,7 @@ const pluginHtmlInlineScripts = () => {
|
|
|
1219
1363
|
};
|
|
1220
1364
|
const postPlugin = {
|
|
1221
1365
|
name: "crx:html-auditor-post",
|
|
1366
|
+
// this hook isn't audited b/c we add it after we set up the auditors
|
|
1222
1367
|
transformIndexHtml(html, ctx) {
|
|
1223
1368
|
const key = toKey(ctx);
|
|
1224
1369
|
const p = pages.get(key);
|
|
@@ -1284,9 +1429,9 @@ const pluginHtmlInlineScripts = () => {
|
|
|
1284
1429
|
};
|
|
1285
1430
|
};
|
|
1286
1431
|
|
|
1287
|
-
var
|
|
1432
|
+
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";
|
|
1288
1433
|
|
|
1289
|
-
var
|
|
1434
|
+
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";
|
|
1290
1435
|
|
|
1291
1436
|
const { readFile } = promises;
|
|
1292
1437
|
const pluginManifest = () => {
|
|
@@ -1465,7 +1610,7 @@ const pluginManifest = () => {
|
|
|
1465
1610
|
})
|
|
1466
1611
|
);
|
|
1467
1612
|
}
|
|
1468
|
-
if (manifest2.background
|
|
1613
|
+
if (manifest2.background && "service_worker" in manifest2.background) {
|
|
1469
1614
|
const file = manifest2.background.service_worker;
|
|
1470
1615
|
const id2 = join(config.root, file);
|
|
1471
1616
|
const refId2 = this.emitFile({
|
|
@@ -1475,6 +1620,16 @@ const pluginManifest = () => {
|
|
|
1475
1620
|
});
|
|
1476
1621
|
manifest2.background.service_worker = refId2;
|
|
1477
1622
|
}
|
|
1623
|
+
if (manifest2.background && "scripts" in manifest2.background) {
|
|
1624
|
+
const file = manifest2.background.scripts[0];
|
|
1625
|
+
const id2 = join(config.root, file);
|
|
1626
|
+
const refId2 = this.emitFile({
|
|
1627
|
+
type: "chunk",
|
|
1628
|
+
id: id2,
|
|
1629
|
+
name: basename(file)
|
|
1630
|
+
});
|
|
1631
|
+
manifest2.background.scripts = [refId2];
|
|
1632
|
+
}
|
|
1478
1633
|
for (const file of htmlFiles(manifest2)) {
|
|
1479
1634
|
const id2 = join(config.root, file);
|
|
1480
1635
|
this.emitFile({
|
|
@@ -1485,7 +1640,7 @@ const pluginManifest = () => {
|
|
|
1485
1640
|
}
|
|
1486
1641
|
}
|
|
1487
1642
|
const encoded = encodeManifest(manifest2);
|
|
1488
|
-
return encoded;
|
|
1643
|
+
return { code: encoded, map: null };
|
|
1489
1644
|
},
|
|
1490
1645
|
async generateBundle(options, bundle) {
|
|
1491
1646
|
const manifestName = this.getFileName(refId);
|
|
@@ -1499,11 +1654,16 @@ const pluginManifest = () => {
|
|
|
1499
1654
|
);
|
|
1500
1655
|
}
|
|
1501
1656
|
} else {
|
|
1502
|
-
if (manifest2.background
|
|
1657
|
+
if (manifest2.background && "service_worker" in manifest2.background) {
|
|
1503
1658
|
const ref = manifest2.background.service_worker;
|
|
1504
1659
|
const name = this.getFileName(ref);
|
|
1505
1660
|
manifest2.background.service_worker = name;
|
|
1506
1661
|
}
|
|
1662
|
+
if (manifest2.background && "scripts" in manifest2.background) {
|
|
1663
|
+
const ref = manifest2.background.scripts[0];
|
|
1664
|
+
const name = this.getFileName(ref);
|
|
1665
|
+
manifest2.background.scripts = [name];
|
|
1666
|
+
}
|
|
1507
1667
|
manifest2.content_scripts = manifest2.content_scripts?.map(
|
|
1508
1668
|
({ js = [], ...rest }) => {
|
|
1509
1669
|
return {
|
|
@@ -1530,11 +1690,11 @@ const pluginManifest = () => {
|
|
|
1530
1690
|
const name = `[${plugin.name}]`;
|
|
1531
1691
|
let message = error;
|
|
1532
1692
|
if (error instanceof Error) {
|
|
1533
|
-
message =
|
|
1693
|
+
message = pc.red(
|
|
1534
1694
|
`${name} ${error.stack ? error.stack : error.message}`
|
|
1535
1695
|
);
|
|
1536
1696
|
} else if (typeof error === "string") {
|
|
1537
|
-
message =
|
|
1697
|
+
message = pc.red(`${name} ${error}`);
|
|
1538
1698
|
}
|
|
1539
1699
|
console.log(message);
|
|
1540
1700
|
throw new Error(`Error in ${plugin.name}.renderCrxManifest`);
|
|
@@ -1563,6 +1723,7 @@ Public dir: "${config.publicDir}"`
|
|
|
1563
1723
|
this.emitFile({
|
|
1564
1724
|
type: "asset",
|
|
1565
1725
|
fileName: f,
|
|
1726
|
+
// TODO: cache source buffer
|
|
1566
1727
|
source: await readFile(filename)
|
|
1567
1728
|
});
|
|
1568
1729
|
}
|
|
@@ -1571,17 +1732,20 @@ Public dir: "${config.publicDir}"`
|
|
|
1571
1732
|
if (config.command === "serve" && files.html.length) {
|
|
1572
1733
|
const refId2 = this.emitFile({
|
|
1573
1734
|
type: "asset",
|
|
1574
|
-
name: "
|
|
1575
|
-
source:
|
|
1735
|
+
name: "loading-page.js",
|
|
1736
|
+
source: loadingPageScript.replace(
|
|
1737
|
+
"%PORT%",
|
|
1738
|
+
`${config.server.port ?? 0}`
|
|
1739
|
+
)
|
|
1576
1740
|
});
|
|
1577
|
-
const
|
|
1741
|
+
const loadingPageScriptName = this.getFileName(refId2);
|
|
1578
1742
|
files.html.map(
|
|
1579
1743
|
(f) => this.emitFile({
|
|
1580
1744
|
type: "asset",
|
|
1581
1745
|
fileName: f,
|
|
1582
|
-
source:
|
|
1746
|
+
source: loadingPageHtml.replace(
|
|
1583
1747
|
"%SCRIPT%",
|
|
1584
|
-
`/${
|
|
1748
|
+
`/${loadingPageScriptName}`
|
|
1585
1749
|
)
|
|
1586
1750
|
})
|
|
1587
1751
|
);
|
|
@@ -1591,10 +1755,10 @@ Public dir: "${config.publicDir}"`
|
|
|
1591
1755
|
this.emitFile({
|
|
1592
1756
|
type: "asset",
|
|
1593
1757
|
fileName: "manifest.json",
|
|
1594
|
-
source: JSON.stringify(manifest2, null, 2)
|
|
1758
|
+
source: JSON.stringify(manifest2, null, 2) + "\n"
|
|
1595
1759
|
});
|
|
1596
1760
|
} else {
|
|
1597
|
-
manifestJson.source = JSON.stringify(manifest2, null, 2);
|
|
1761
|
+
manifestJson.source = JSON.stringify(manifest2, null, 2) + "\n";
|
|
1598
1762
|
}
|
|
1599
1763
|
delete bundle[manifestName];
|
|
1600
1764
|
}
|
|
@@ -1610,7 +1774,11 @@ function compileFileResources(fileName, {
|
|
|
1610
1774
|
assets: /* @__PURE__ */ new Set(),
|
|
1611
1775
|
css: /* @__PURE__ */ new Set(),
|
|
1612
1776
|
imports: /* @__PURE__ */ new Set()
|
|
1613
|
-
}) {
|
|
1777
|
+
}, processedFiles = /* @__PURE__ */ new Set()) {
|
|
1778
|
+
if (processedFiles.has(fileName)) {
|
|
1779
|
+
return resources;
|
|
1780
|
+
}
|
|
1781
|
+
processedFiles.add(fileName);
|
|
1614
1782
|
const chunk = chunks.get(fileName);
|
|
1615
1783
|
if (chunk) {
|
|
1616
1784
|
const { modules, facadeModuleId, imports, dynamicImports } = chunk;
|
|
@@ -1619,7 +1787,7 @@ function compileFileResources(fileName, {
|
|
|
1619
1787
|
for (const x of dynamicImports)
|
|
1620
1788
|
resources.imports.add(x);
|
|
1621
1789
|
for (const x of [...imports, ...dynamicImports])
|
|
1622
|
-
compileFileResources(x, { chunks, files, config }, resources);
|
|
1790
|
+
compileFileResources(x, { chunks, files, config }, resources, processedFiles);
|
|
1623
1791
|
for (const m of Object.keys(modules))
|
|
1624
1792
|
if (m !== facadeModuleId) {
|
|
1625
1793
|
const key = prefix$1("/", relative(config.root, m.split("?")[0]));
|
|
@@ -1632,7 +1800,8 @@ function compileFileResources(fileName, {
|
|
|
1632
1800
|
compileFileResources(
|
|
1633
1801
|
script.fileName,
|
|
1634
1802
|
{ chunks, files, config },
|
|
1635
|
-
resources
|
|
1803
|
+
resources,
|
|
1804
|
+
processedFiles
|
|
1636
1805
|
);
|
|
1637
1806
|
}
|
|
1638
1807
|
}
|
|
@@ -1651,7 +1820,7 @@ function compileFileResources(fileName, {
|
|
|
1651
1820
|
const defineManifest = (manifest) => manifest;
|
|
1652
1821
|
const defineDynamicResource = ({
|
|
1653
1822
|
matches = ["http://*/*", "https://*/*"],
|
|
1654
|
-
use_dynamic_url =
|
|
1823
|
+
use_dynamic_url = false
|
|
1655
1824
|
}) => ({
|
|
1656
1825
|
matches,
|
|
1657
1826
|
resources: [DYNAMIC_RESOURCE],
|
|
@@ -1663,22 +1832,34 @@ _debug("web-acc-res");
|
|
|
1663
1832
|
const pluginWebAccessibleResources = () => {
|
|
1664
1833
|
let config;
|
|
1665
1834
|
let injectCss;
|
|
1835
|
+
let browser;
|
|
1666
1836
|
return [
|
|
1667
1837
|
{
|
|
1668
1838
|
name: "crx:web-accessible-resources",
|
|
1669
1839
|
apply: "serve",
|
|
1670
1840
|
enforce: "post",
|
|
1841
|
+
async config(config2) {
|
|
1842
|
+
const opts = await getOptions(config2);
|
|
1843
|
+
browser = opts.browser || "chrome";
|
|
1844
|
+
},
|
|
1671
1845
|
renderCrxManifest(manifest) {
|
|
1672
1846
|
manifest.web_accessible_resources = manifest.web_accessible_resources ?? [];
|
|
1673
1847
|
manifest.web_accessible_resources = manifest.web_accessible_resources.map(({ resources, ...rest }) => ({
|
|
1674
1848
|
resources: resources.filter((r) => r !== DYNAMIC_RESOURCE),
|
|
1675
1849
|
...rest
|
|
1676
1850
|
})).filter(({ resources }) => resources.length);
|
|
1677
|
-
|
|
1678
|
-
|
|
1851
|
+
const war = {
|
|
1852
|
+
// all web origins can access
|
|
1679
1853
|
matches: ["<all_urls>"],
|
|
1680
|
-
resources
|
|
1681
|
-
|
|
1854
|
+
// all resources are web accessible
|
|
1855
|
+
resources: ["**/*", "*"],
|
|
1856
|
+
// change the extension origin on every reload
|
|
1857
|
+
use_dynamic_url: false
|
|
1858
|
+
};
|
|
1859
|
+
if (browser === "firefox") {
|
|
1860
|
+
delete war.use_dynamic_url;
|
|
1861
|
+
}
|
|
1862
|
+
manifest.web_accessible_resources.push(war);
|
|
1682
1863
|
return manifest;
|
|
1683
1864
|
}
|
|
1684
1865
|
},
|
|
@@ -1687,7 +1868,9 @@ const pluginWebAccessibleResources = () => {
|
|
|
1687
1868
|
apply: "build",
|
|
1688
1869
|
enforce: "post",
|
|
1689
1870
|
async config({ build, ...config2 }, { command }) {
|
|
1690
|
-
const
|
|
1871
|
+
const opts = await getOptions(config2);
|
|
1872
|
+
const contentScripts2 = opts.contentScripts || {};
|
|
1873
|
+
browser = opts.browser || "chrome";
|
|
1691
1874
|
injectCss = contentScripts2.injectCss ?? true;
|
|
1692
1875
|
return { ...config2, build: { ...build, manifest: command === "build" } };
|
|
1693
1876
|
},
|
|
@@ -1716,9 +1899,11 @@ const pluginWebAccessibleResources = () => {
|
|
|
1716
1899
|
dynamicScriptMatches.add("https://*/*");
|
|
1717
1900
|
}
|
|
1718
1901
|
if (contentScripts.size > 0) {
|
|
1902
|
+
const viteMajorVersion = parseInt(version.split(".")[0]);
|
|
1903
|
+
const manifestPath = viteMajorVersion > 4 ? ".vite/manifest.json" : "manifest.json";
|
|
1719
1904
|
const viteManifest = parseJsonAsset(
|
|
1720
1905
|
bundle,
|
|
1721
|
-
|
|
1906
|
+
manifestPath
|
|
1722
1907
|
);
|
|
1723
1908
|
const viteFiles = /* @__PURE__ */ new Map();
|
|
1724
1909
|
for (const [, file] of Object.entries(viteManifest))
|
|
@@ -1746,12 +1931,12 @@ const pluginWebAccessibleResources = () => {
|
|
|
1746
1931
|
{ chunks: bundleChunks, files: viteFiles, config }
|
|
1747
1932
|
);
|
|
1748
1933
|
contentScripts.get(key).css = [...css];
|
|
1749
|
-
if (type === "loader")
|
|
1934
|
+
if (type === "loader" || isDynamicScript)
|
|
1750
1935
|
imports.add(fileName);
|
|
1751
1936
|
const resource = {
|
|
1752
1937
|
matches: isDynamicScript ? [...dynamicScriptMatches] : matches,
|
|
1753
1938
|
resources: [...assets, ...imports],
|
|
1754
|
-
use_dynamic_url: isDynamicScript ? dynamicScriptDynamicUrl :
|
|
1939
|
+
use_dynamic_url: isDynamicScript ? dynamicScriptDynamicUrl : false
|
|
1755
1940
|
};
|
|
1756
1941
|
if (isDynamicScript || !injectCss) {
|
|
1757
1942
|
resource.resources.push(...css);
|
|
@@ -1795,6 +1980,11 @@ const pluginWebAccessibleResources = () => {
|
|
|
1795
1980
|
use_dynamic_url
|
|
1796
1981
|
});
|
|
1797
1982
|
}
|
|
1983
|
+
if (browser === "firefox") {
|
|
1984
|
+
for (const war of combinedResources) {
|
|
1985
|
+
delete war.use_dynamic_url;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1798
1988
|
if (combinedResources.length === 0)
|
|
1799
1989
|
delete manifest.web_accessible_resources;
|
|
1800
1990
|
else
|
|
@@ -1806,6 +1996,7 @@ const pluginWebAccessibleResources = () => {
|
|
|
1806
1996
|
};
|
|
1807
1997
|
|
|
1808
1998
|
const crx = (options) => {
|
|
1999
|
+
contentScripts.clear();
|
|
1809
2000
|
return [
|
|
1810
2001
|
pluginOptionsProvider(options),
|
|
1811
2002
|
pluginBackground(),
|
|
@@ -1819,7 +2010,8 @@ const crx = (options) => {
|
|
|
1819
2010
|
pluginWebAccessibleResources(),
|
|
1820
2011
|
pluginContentScriptsCss(),
|
|
1821
2012
|
pluginHMR(),
|
|
1822
|
-
pluginManifest()
|
|
2013
|
+
pluginManifest(),
|
|
2014
|
+
pluginPrint()
|
|
1823
2015
|
].flat();
|
|
1824
2016
|
};
|
|
1825
2017
|
const chromeExtension = crx;
|
package/index.cjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Object.assign(module.exports, require('./dist/index.cjs'))
|
|
2
|
+
|
|
3
|
+
// async functions, can be redirect from ESM build
|
|
4
|
+
const asyncFunctions = ['crx', 'chromeExtension', 'allFilesReady', 'filesReady']
|
|
5
|
+
asyncFunctions.forEach((name) => {
|
|
6
|
+
module.exports[name] = (...args) =>
|
|
7
|
+
import('./dist/index.mjs').then((i) => i[name](...args))
|
|
8
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crxjs/vite-plugin",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Build Chrome Extensions with this Vite plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rollup-plugin",
|
|
@@ -35,60 +35,45 @@
|
|
|
35
35
|
"types": "./client.d.ts"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
-
"main": "
|
|
38
|
+
"main": "index.cjs",
|
|
39
39
|
"module": "dist/index.mjs",
|
|
40
40
|
"types": "dist/index.d.ts",
|
|
41
41
|
"files": [
|
|
42
42
|
"dist",
|
|
43
43
|
"types",
|
|
44
44
|
"manifest.schema.json",
|
|
45
|
-
"
|
|
45
|
+
"index.cjs",
|
|
46
46
|
"client.d.ts"
|
|
47
47
|
],
|
|
48
|
-
"scripts": {
|
|
49
|
-
"format": "prettier -w -c ../../.prettierrc.yaml",
|
|
50
|
-
"build": "run-s build:clean build:js",
|
|
51
|
-
"build:clean": "rimraf dist",
|
|
52
|
-
"build:js": "rollup -c rollup.config.ts --configPlugin esbuild",
|
|
53
|
-
"dev:js": "npm run build:js -- -w",
|
|
54
|
-
"dev:lint": "tsc --noEmit --watch",
|
|
55
|
-
"lint": "run-s lint:eslint lint:types",
|
|
56
|
-
"lint:eslint": "eslint \"{src,test}/**/*.ts\"",
|
|
57
|
-
"lint:types": "tsc --noEmit",
|
|
58
|
-
"test": "vitest --mode unit",
|
|
59
|
-
"test:e2e": "vitest --mode e2e",
|
|
60
|
-
"test:run": "run-s test:run:*",
|
|
61
|
-
"test:run:out": "vitest --run --mode out",
|
|
62
|
-
"test:run:e2e": "vitest --run --mode e2e",
|
|
63
|
-
"test:update": "run-s \"test:run:out --update\" \"test:run:e2e --update\""
|
|
64
|
-
},
|
|
65
48
|
"dependencies": {
|
|
66
49
|
"@rollup/pluginutils": "^4.1.2",
|
|
67
50
|
"@webcomponents/custom-elements": "^1.5.0",
|
|
68
51
|
"acorn-walk": "^8.2.0",
|
|
69
52
|
"cheerio": "^1.0.0-rc.10",
|
|
70
|
-
"
|
|
53
|
+
"convert-source-map": "^1.7.0",
|
|
71
54
|
"debug": "^4.3.3",
|
|
72
55
|
"es-module-lexer": "^0.10.0",
|
|
73
56
|
"fast-glob": "^3.2.11",
|
|
74
57
|
"fs-extra": "^10.0.1",
|
|
75
58
|
"jsesc": "^3.0.2",
|
|
76
|
-
"magic-string": "^0.
|
|
59
|
+
"magic-string": "^0.30.12",
|
|
60
|
+
"pathe": "^2.0.1",
|
|
77
61
|
"picocolors": "^1.0.0",
|
|
78
62
|
"react-refresh": "^0.13.0",
|
|
79
|
-
"rollup": "2.
|
|
63
|
+
"rollup": "2.79.2",
|
|
80
64
|
"rxjs": "7.5.7"
|
|
81
65
|
},
|
|
82
66
|
"devDependencies": {
|
|
83
67
|
"@extend-chrome/messages": "1.2.2",
|
|
84
68
|
"@extend-chrome/storage": "1.5.0",
|
|
85
|
-
"@rollup/plugin-alias": "4.0.
|
|
69
|
+
"@rollup/plugin-alias": "4.0.4",
|
|
86
70
|
"@rollup/plugin-commonjs": "21.1.0",
|
|
87
71
|
"@rollup/plugin-json": "^5.0.0",
|
|
88
72
|
"@rollup/plugin-node-resolve": "13.2.0",
|
|
89
|
-
"@sveltejs/vite-plugin-svelte": "1.
|
|
73
|
+
"@sveltejs/vite-plugin-svelte": "1.4.0",
|
|
90
74
|
"@types/acorn": "4.0.6",
|
|
91
|
-
"@types/chrome": "0.0.
|
|
75
|
+
"@types/chrome": "0.0.237",
|
|
76
|
+
"@types/convert-source-map": "^2.0.0",
|
|
92
77
|
"@types/debug": "4.1.7",
|
|
93
78
|
"@types/fs-extra": "9.0.13",
|
|
94
79
|
"@types/jest-image-snapshot": "^5.1.0",
|
|
@@ -98,26 +83,43 @@
|
|
|
98
83
|
"@types/react-dom": "17.0.18",
|
|
99
84
|
"@typescript-eslint/eslint-plugin": "5.41.0",
|
|
100
85
|
"@typescript-eslint/parser": "5.41.0",
|
|
101
|
-
"@vitejs/plugin-react": "^2.
|
|
86
|
+
"@vitejs/plugin-react": "^2.2.0",
|
|
102
87
|
"@vitejs/plugin-vue": "3.2.0",
|
|
103
88
|
"chokidar": "^3.5.3",
|
|
104
|
-
"esbuild": "0.
|
|
89
|
+
"esbuild": "0.17.14",
|
|
105
90
|
"esbuild-runner": "2.2.2",
|
|
106
|
-
"eslint": "8.
|
|
91
|
+
"eslint": "8.43.0",
|
|
107
92
|
"eslint-plugin-react": "^7.29.4",
|
|
108
93
|
"jest-image-snapshot": "^5.2.0",
|
|
109
94
|
"npm-run-all": "^4.1.5",
|
|
110
|
-
"playwright-chromium": "1.
|
|
95
|
+
"playwright-chromium": "1.52.0",
|
|
111
96
|
"react": "17.0.2",
|
|
112
97
|
"react-dom": "17.0.2",
|
|
113
98
|
"rimraf": "3.0.2",
|
|
114
99
|
"rollup-plugin-dts": "^4.2.0",
|
|
115
|
-
"rollup-plugin-esbuild": "4.10.
|
|
100
|
+
"rollup-plugin-esbuild": "4.10.3",
|
|
116
101
|
"svelte": "^3.48.0",
|
|
117
102
|
"typescript": "^4.6.4",
|
|
118
|
-
"vite": "^3.
|
|
119
|
-
"vite-plugin-inspect": "0.7.
|
|
120
|
-
"vitest": "0.
|
|
121
|
-
"vue": "3.2.
|
|
103
|
+
"vite": "^3.2.11",
|
|
104
|
+
"vite-plugin-inspect": "0.7.25",
|
|
105
|
+
"vitest": "0.28.5",
|
|
106
|
+
"vue": "3.2.47"
|
|
107
|
+
},
|
|
108
|
+
"scripts": {
|
|
109
|
+
"format": "prettier -w -c ../../.prettierrc.yaml",
|
|
110
|
+
"build": "run-s build:clean build:js",
|
|
111
|
+
"build:clean": "rimraf dist",
|
|
112
|
+
"build:js": "rollup -c rollup.config.ts --configPlugin esbuild",
|
|
113
|
+
"dev:js": "npm run build:js -- -w",
|
|
114
|
+
"dev:lint": "tsc --noEmit --watch",
|
|
115
|
+
"lint": "run-s lint:eslint lint:types",
|
|
116
|
+
"lint:eslint": "eslint \"{src,test}/**/*.ts\"",
|
|
117
|
+
"lint:types": "tsc --noEmit",
|
|
118
|
+
"test": "vitest --mode unit",
|
|
119
|
+
"test:e2e": "vitest --mode e2e",
|
|
120
|
+
"test:run": "run-s test:run:*",
|
|
121
|
+
"test:run:out": "vitest --run --mode out",
|
|
122
|
+
"test:run:e2e": "vitest --run --mode e2e",
|
|
123
|
+
"test:update": "run-s \"test:run:out --update\" \"test:run:e2e --update\""
|
|
122
124
|
}
|
|
123
|
-
}
|
|
125
|
+
}
|