vite-userscript-plugin 2.1.1 → 2.2.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/README.md +6 -3
- package/dist/index.d.ts +3 -29
- package/dist/index.js +171 -118
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -133,13 +133,12 @@ See [examples/sourcemap](./examples/sourcemap).
|
|
|
133
133
|
| Option | Default | Description |
|
|
134
134
|
| --- | --- | --- |
|
|
135
135
|
| `entry` | — | Userscript entry. Required. |
|
|
136
|
-
| `header` | — | Metablock. Required: `name`, `version`, `match`. |
|
|
136
|
+
| `header` | — | Metablock. Required: `name`, `version`, `match`. Relative `icon` / `require` / `resource` / `supportURL` / `updateURL` / `downloadURL` join `homepage` (`homepageURL` / `website` / `source`). Absolute `http(s):` URLs stay as-is. |
|
|
137
137
|
| `fileName` | sanitized `header.name` | Output base name (`{fileName}.user.js`). |
|
|
138
138
|
| `server.open` | `false` | Open the install target when Vite starts. HMR: `.dev.user.js`. `file`: `.user.js` URL. |
|
|
139
139
|
| `server.prefix` | `'server:'` | Prefix for `@name` in serve mode. `false` disables it. |
|
|
140
140
|
| `server.file` | `false` | Watch-build `{fileName}.user.js` + `{fileName}.js` + `{fileName}.proxy.user.js`. Install `.user.js` (or the proxy if `file://` `@require` works). No HMR. |
|
|
141
|
-
| `
|
|
142
|
-
| `align` | `1` | Extra spaces after the longest `@key`. `false` — one space. |
|
|
141
|
+
| `headerAlign` | `1` | Extra spaces after the longest `@key`. `false` — one space. |
|
|
143
142
|
| `generate` | — | Rewrite the generated metablock. |
|
|
144
143
|
| `autoMetaUrls` | `false` | Fill empty `updateURL` / `downloadURL` from `homepage` / `homepageURL` / `website` / `source`. |
|
|
145
144
|
| `metaFile` | `true` | Emit `{fileName}.meta.js`. |
|
|
@@ -181,6 +180,8 @@ In serve mode the header lists every grant. In production the plugin scans the b
|
|
|
181
180
|
|
|
182
181
|
> [!NOTE]
|
|
183
182
|
> Userscripts run on someone else’s origin. Import the file so Vite inlines it. `public/` only works for the `index.html` app on the Vite origin.
|
|
183
|
+
>
|
|
184
|
+
> `@icon`, `@require`, and `@resource` are different: the manager fetches them from the metablock URL, not from the `match` site. Write `icon: 'greasify.svg'` plus `homepage` (GitHub Pages, etc.) — the plugin joins them. Leave `https://…` as-is.
|
|
184
185
|
|
|
185
186
|
### `@run-at document-start` feels late in dev
|
|
186
187
|
|
|
@@ -204,6 +205,8 @@ In serve mode the header lists every grant. In production the plugin scans the b
|
|
|
204
205
|
| Vite 3–7 | Vite 8 |
|
|
205
206
|
| `scripts` + shared `header` | `userscript([config, config, …])` |
|
|
206
207
|
| `ScriptOptions` | removed |
|
|
208
|
+
| `cssInject` | removed; imported CSS always appends a `<style>` node |
|
|
209
|
+
| `align` | `headerAlign` |
|
|
207
210
|
|
|
208
211
|
## License
|
|
209
212
|
|
package/dist/index.d.ts
CHANGED
|
@@ -173,7 +173,6 @@ interface HeaderGenerateContext {
|
|
|
173
173
|
userscript: string;
|
|
174
174
|
mode: HeaderMode;
|
|
175
175
|
}
|
|
176
|
-
type CssInject = 'auto' | string | ((css: string) => void);
|
|
177
176
|
/**
|
|
178
177
|
* One userscript. Pass an object, or an array of these, to {@link UserscriptPluginConfig}.
|
|
179
178
|
*/
|
|
@@ -196,18 +195,12 @@ interface UserscriptConfig {
|
|
|
196
195
|
* Serve-mode options.
|
|
197
196
|
*/
|
|
198
197
|
server?: ServerConfig;
|
|
199
|
-
/**
|
|
200
|
-
* How to inject collected CSS in production builds.
|
|
201
|
-
*
|
|
202
|
-
* @default 'auto'
|
|
203
|
-
*/
|
|
204
|
-
cssInject?: CssInject;
|
|
205
198
|
/**
|
|
206
199
|
* Extra spaces after the longest `@key`, or `false` for a single space.
|
|
207
200
|
*
|
|
208
201
|
* @default 1
|
|
209
202
|
*/
|
|
210
|
-
|
|
203
|
+
headerAlign?: number | false;
|
|
211
204
|
/**
|
|
212
205
|
* Rewrite the generated metablock.
|
|
213
206
|
*/
|
|
@@ -240,32 +233,13 @@ interface ResolvedScript {
|
|
|
240
233
|
prefix: string | false;
|
|
241
234
|
file: boolean;
|
|
242
235
|
};
|
|
243
|
-
|
|
244
|
-
align: number | false;
|
|
236
|
+
headerAlign: number | false;
|
|
245
237
|
generate?: (ctx: HeaderGenerateContext) => string;
|
|
246
238
|
autoMetaUrls: boolean;
|
|
247
239
|
metaFile: boolean;
|
|
248
240
|
}
|
|
249
241
|
//#endregion
|
|
250
|
-
//#region src/header.d.ts
|
|
251
|
-
interface HeaderOptions {
|
|
252
|
-
align?: number | false;
|
|
253
|
-
autoMetaUrls?: boolean;
|
|
254
|
-
fileName?: string;
|
|
255
|
-
generate?: (ctx: HeaderGenerateContext) => string;
|
|
256
|
-
mode?: HeaderMode;
|
|
257
|
-
}
|
|
258
|
-
declare function resolveHomePage(header: HeaderConfig): string | undefined;
|
|
259
|
-
declare function resolvePublicFileUrl(header: HeaderConfig, fileName: string): string | undefined;
|
|
260
|
-
declare function generateHeader(config: HeaderConfig, options?: HeaderOptions): string;
|
|
261
|
-
declare class Header {
|
|
262
|
-
private readonly config;
|
|
263
|
-
private readonly options;
|
|
264
|
-
constructor(config: HeaderConfig, options?: HeaderOptions);
|
|
265
|
-
generate(): string;
|
|
266
|
-
}
|
|
267
|
-
//#endregion
|
|
268
242
|
//#region src/plugin.d.ts
|
|
269
243
|
declare function UserscriptPlugin(config: UserscriptPluginConfig): Plugin[];
|
|
270
244
|
//#endregion
|
|
271
|
-
export { type
|
|
245
|
+
export { type HeaderConfig, type HeaderGenerateContext, type ResolvedScript, type ServerConfig, type UserscriptConfig, type UserscriptPluginConfig, UserscriptPlugin as default };
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,88 @@ import { pathToFileURL } from "node:url";
|
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
7
|
import openLink from "open";
|
|
8
|
+
//#region src/grants/catalog.ts
|
|
9
|
+
const GM = [
|
|
10
|
+
"setValue",
|
|
11
|
+
"getValue",
|
|
12
|
+
"deleteValue",
|
|
13
|
+
"listValues",
|
|
14
|
+
"setValues",
|
|
15
|
+
"getValues",
|
|
16
|
+
"deleteValues",
|
|
17
|
+
"setClipboard",
|
|
18
|
+
"addStyle",
|
|
19
|
+
"addElement",
|
|
20
|
+
"addValueChangeListener",
|
|
21
|
+
"removeValueChangeListener",
|
|
22
|
+
"registerMenuCommand",
|
|
23
|
+
"unregisterMenuCommand",
|
|
24
|
+
"download",
|
|
25
|
+
"getTab",
|
|
26
|
+
"getTabs",
|
|
27
|
+
"saveTab",
|
|
28
|
+
"openInTab",
|
|
29
|
+
"notification",
|
|
30
|
+
"getResourceURL",
|
|
31
|
+
"getResourceText",
|
|
32
|
+
"xmlhttpRequest",
|
|
33
|
+
"webRequest",
|
|
34
|
+
"cookie",
|
|
35
|
+
"audio",
|
|
36
|
+
"log",
|
|
37
|
+
"info"
|
|
38
|
+
];
|
|
39
|
+
const GMwindow = [
|
|
40
|
+
"unsafeWindow",
|
|
41
|
+
"window.onurlchange",
|
|
42
|
+
"window.focus",
|
|
43
|
+
"window.close"
|
|
44
|
+
];
|
|
45
|
+
const GM_DOT_ALIASES = ["GM.xmlHttpRequest", "GM.getResourceUrl"];
|
|
46
|
+
const grants = [
|
|
47
|
+
...GM.flatMap((grant) => [`GM_${grant}`, `GM.${grant}`]),
|
|
48
|
+
...GMwindow,
|
|
49
|
+
...GM_DOT_ALIASES
|
|
50
|
+
];
|
|
51
|
+
const gmIdentifiers = [
|
|
52
|
+
"GM",
|
|
53
|
+
"unsafeWindow",
|
|
54
|
+
...GM.map((grant) => `GM_${grant}`)
|
|
55
|
+
];
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/grants/scan.ts
|
|
58
|
+
const grantMatchers = grants.map((grant) => ({
|
|
59
|
+
grant,
|
|
60
|
+
pattern: new RegExp(`\\b${grant.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`)
|
|
61
|
+
}));
|
|
62
|
+
function removeDuplicates(arr) {
|
|
63
|
+
if (Array.isArray(arr)) return [...new Set(arr)];
|
|
64
|
+
return arr ? [arr] : [];
|
|
65
|
+
}
|
|
66
|
+
function defineGrants(code) {
|
|
67
|
+
return grantMatchers.filter(({ pattern }) => pattern.test(code)).map(({ grant }) => grant);
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/grants/policy.ts
|
|
71
|
+
function withServeGrants(header) {
|
|
72
|
+
if (header.grant === "none") return header;
|
|
73
|
+
return {
|
|
74
|
+
...header,
|
|
75
|
+
grant: [.../* @__PURE__ */ new Set([...header.grant ?? [], ...grants])]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function withBuildGrants(header, code, extraGrants = []) {
|
|
79
|
+
if (header.grant === "none") return header;
|
|
80
|
+
return {
|
|
81
|
+
...header,
|
|
82
|
+
grant: removeDuplicates([
|
|
83
|
+
...defineGrants(code),
|
|
84
|
+
...removeDuplicates(header.grant),
|
|
85
|
+
...extraGrants
|
|
86
|
+
])
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
8
90
|
//#region src/names.ts
|
|
9
91
|
function sanitizeFileName(name) {
|
|
10
92
|
return name.replace(/[<>:"/\\|?*\u0000-\u001F]+/g, "-").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "userscript";
|
|
@@ -16,6 +98,18 @@ function toIdentifier(name) {
|
|
|
16
98
|
}
|
|
17
99
|
//#endregion
|
|
18
100
|
//#region src/header.ts
|
|
101
|
+
const ABSOLUTE_URL_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
102
|
+
const HOMEPAGE_RELATIVE_FIELDS = [
|
|
103
|
+
"icon",
|
|
104
|
+
"iconURL",
|
|
105
|
+
"defaulticon",
|
|
106
|
+
"icon64",
|
|
107
|
+
"icon64URL",
|
|
108
|
+
"require",
|
|
109
|
+
"supportURL",
|
|
110
|
+
"updateURL",
|
|
111
|
+
"downloadURL"
|
|
112
|
+
];
|
|
19
113
|
function ensureTrailingSlash(url) {
|
|
20
114
|
return url.endsWith("/") ? url : `${url}/`;
|
|
21
115
|
}
|
|
@@ -25,6 +119,29 @@ function resolveHomePage(header) {
|
|
|
25
119
|
const trimmed = homePage.trim();
|
|
26
120
|
return trimmed === "" ? void 0 : trimmed;
|
|
27
121
|
}
|
|
122
|
+
function isResolvableHeaderPath(value) {
|
|
123
|
+
const trimmed = value.trim();
|
|
124
|
+
if (!trimmed) return false;
|
|
125
|
+
if (ABSOLUTE_URL_RE.test(trimmed) || trimmed.startsWith("//") || trimmed.startsWith("/")) return false;
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
function containsResolvableHeaderPath(value) {
|
|
129
|
+
if (typeof value === "string") return isResolvableHeaderPath(value);
|
|
130
|
+
if (!Array.isArray(value)) return false;
|
|
131
|
+
return value.some((item) => typeof item === "string" && isResolvableHeaderPath(item));
|
|
132
|
+
}
|
|
133
|
+
function containsResolvableResourcePath(resource) {
|
|
134
|
+
if (!Array.isArray(resource)) return false;
|
|
135
|
+
return resource.some((item) => {
|
|
136
|
+
return Array.isArray(item) && typeof item[1] === "string" && isResolvableHeaderPath(item[1]);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function listHomepageRelativeFields(header) {
|
|
140
|
+
const fields = [];
|
|
141
|
+
for (const key of HOMEPAGE_RELATIVE_FIELDS) if (containsResolvableHeaderPath(header[key])) fields.push(key);
|
|
142
|
+
if (containsResolvableResourcePath(header.resource)) fields.push("resource");
|
|
143
|
+
return fields;
|
|
144
|
+
}
|
|
28
145
|
function resolvePublicFileUrl(header, fileName) {
|
|
29
146
|
const homePage = resolveHomePage(header);
|
|
30
147
|
if (!homePage) return;
|
|
@@ -32,6 +149,31 @@ function resolvePublicFileUrl(header, fileName) {
|
|
|
32
149
|
return new URL(fileName, ensureTrailingSlash(homePage)).href;
|
|
33
150
|
} catch {}
|
|
34
151
|
}
|
|
152
|
+
function resolveHeaderUrlValue(header, value) {
|
|
153
|
+
if (typeof value === "string") {
|
|
154
|
+
if (!isResolvableHeaderPath(value)) return value;
|
|
155
|
+
return resolvePublicFileUrl(header, value.trim()) ?? value;
|
|
156
|
+
}
|
|
157
|
+
if (Array.isArray(value)) return value.map((item) => typeof item === "string" ? resolveHeaderUrlValue(header, item) : item);
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
function resolveResourceUrls(header, resource) {
|
|
161
|
+
if (!Array.isArray(resource)) return resource;
|
|
162
|
+
return resource.map((item) => {
|
|
163
|
+
if (!Array.isArray(item) || typeof item[1] !== "string") return item;
|
|
164
|
+
const [key, url] = item;
|
|
165
|
+
if (!isResolvableHeaderPath(url)) return item;
|
|
166
|
+
const resolved = resolvePublicFileUrl(header, url.trim());
|
|
167
|
+
return resolved ? [key, resolved] : item;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function applyHomepageRelativeUrls(header) {
|
|
171
|
+
if (!resolveHomePage(header)) return header;
|
|
172
|
+
const next = { ...header };
|
|
173
|
+
for (const key of HOMEPAGE_RELATIVE_FIELDS) if (next[key] != null) Object.assign(next, { [key]: resolveHeaderUrlValue(next, next[key]) });
|
|
174
|
+
if (next.resource != null) next.resource = resolveResourceUrls(next, next.resource);
|
|
175
|
+
return next;
|
|
176
|
+
}
|
|
35
177
|
function applyAutoMetaUrls(header, fileName) {
|
|
36
178
|
const updateURL = header.updateURL ?? resolvePublicFileUrl(header, `${fileName}.meta.js`);
|
|
37
179
|
const downloadURL = header.downloadURL ?? resolvePublicFileUrl(header, `${fileName}.user.js`);
|
|
@@ -53,7 +195,8 @@ function formatValue(value) {
|
|
|
53
195
|
}
|
|
54
196
|
function generateHeader(config, options = {}) {
|
|
55
197
|
const fileName = options.fileName ?? sanitizeFileName(config.name);
|
|
56
|
-
const
|
|
198
|
+
const withRelativeUrls = applyHomepageRelativeUrls({ ...config });
|
|
199
|
+
const header = options.autoMetaUrls ? applyAutoMetaUrls(withRelativeUrls, fileName) : withRelativeUrls;
|
|
57
200
|
const keys = Object.keys(header).filter((key) => {
|
|
58
201
|
const value = header[key];
|
|
59
202
|
return value !== void 0 && value !== null && value !== false;
|
|
@@ -88,99 +231,6 @@ function generateHeader(config, options = {}) {
|
|
|
88
231
|
mode: options.mode ?? "build"
|
|
89
232
|
});
|
|
90
233
|
}
|
|
91
|
-
var Header = class {
|
|
92
|
-
config;
|
|
93
|
-
options;
|
|
94
|
-
constructor(config, options = {}) {
|
|
95
|
-
this.config = config;
|
|
96
|
-
this.options = options;
|
|
97
|
-
}
|
|
98
|
-
generate() {
|
|
99
|
-
return generateHeader(this.config, this.options);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
//#endregion
|
|
103
|
-
//#region src/grants/catalog.ts
|
|
104
|
-
const GM = [
|
|
105
|
-
"setValue",
|
|
106
|
-
"getValue",
|
|
107
|
-
"deleteValue",
|
|
108
|
-
"listValues",
|
|
109
|
-
"setValues",
|
|
110
|
-
"getValues",
|
|
111
|
-
"deleteValues",
|
|
112
|
-
"setClipboard",
|
|
113
|
-
"addStyle",
|
|
114
|
-
"addElement",
|
|
115
|
-
"addValueChangeListener",
|
|
116
|
-
"removeValueChangeListener",
|
|
117
|
-
"registerMenuCommand",
|
|
118
|
-
"unregisterMenuCommand",
|
|
119
|
-
"download",
|
|
120
|
-
"getTab",
|
|
121
|
-
"getTabs",
|
|
122
|
-
"saveTab",
|
|
123
|
-
"openInTab",
|
|
124
|
-
"notification",
|
|
125
|
-
"getResourceURL",
|
|
126
|
-
"getResourceText",
|
|
127
|
-
"xmlhttpRequest",
|
|
128
|
-
"webRequest",
|
|
129
|
-
"cookie",
|
|
130
|
-
"audio",
|
|
131
|
-
"log",
|
|
132
|
-
"info"
|
|
133
|
-
];
|
|
134
|
-
const GMwindow = [
|
|
135
|
-
"unsafeWindow",
|
|
136
|
-
"window.onurlchange",
|
|
137
|
-
"window.focus",
|
|
138
|
-
"window.close"
|
|
139
|
-
];
|
|
140
|
-
const GM_DOT_ALIASES = ["GM.xmlHttpRequest", "GM.getResourceUrl"];
|
|
141
|
-
const grants = [
|
|
142
|
-
...GM.flatMap((grant) => [`GM_${grant}`, `GM.${grant}`]),
|
|
143
|
-
...GMwindow,
|
|
144
|
-
...GM_DOT_ALIASES
|
|
145
|
-
];
|
|
146
|
-
const gmIdentifiers = [
|
|
147
|
-
"GM",
|
|
148
|
-
"unsafeWindow",
|
|
149
|
-
...GM.map((grant) => `GM_${grant}`)
|
|
150
|
-
];
|
|
151
|
-
//#endregion
|
|
152
|
-
//#region src/grants/scan.ts
|
|
153
|
-
const grantMatchers = grants.map((grant) => ({
|
|
154
|
-
grant,
|
|
155
|
-
pattern: new RegExp(`\\b${grant.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`)
|
|
156
|
-
}));
|
|
157
|
-
function removeDuplicates(arr) {
|
|
158
|
-
if (Array.isArray(arr)) return [...new Set(arr)];
|
|
159
|
-
return arr ? [arr] : [];
|
|
160
|
-
}
|
|
161
|
-
function defineGrants(code) {
|
|
162
|
-
return grantMatchers.filter(({ pattern }) => pattern.test(code)).map(({ grant }) => grant);
|
|
163
|
-
}
|
|
164
|
-
//#endregion
|
|
165
|
-
//#region src/grants/policy.ts
|
|
166
|
-
function withServeGrants(header) {
|
|
167
|
-
if (header.grant === "none") return header;
|
|
168
|
-
return {
|
|
169
|
-
...header,
|
|
170
|
-
grant: [.../* @__PURE__ */ new Set([...header.grant ?? [], ...grants])]
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
function withBuildGrants(header, code, extraGrants = []) {
|
|
174
|
-
if (header.grant === "none") return header;
|
|
175
|
-
return {
|
|
176
|
-
...header,
|
|
177
|
-
grant: removeDuplicates([
|
|
178
|
-
...defineGrants(code),
|
|
179
|
-
...removeDuplicates(header.grant),
|
|
180
|
-
...extraGrants
|
|
181
|
-
])
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
234
|
//#endregion
|
|
185
235
|
//#region src/sourcemap.ts
|
|
186
236
|
function countHeaderLines(prefix) {
|
|
@@ -264,13 +314,9 @@ function isAsset(item) {
|
|
|
264
314
|
//#endregion
|
|
265
315
|
//#region src/build/css.ts
|
|
266
316
|
const defaultCssInjector = `(function (css) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
var style = document.createElement('style')
|
|
271
|
-
style.textContent = css
|
|
272
|
-
;(document.head || document.documentElement).appendChild(style)
|
|
273
|
-
}
|
|
317
|
+
var style = document.createElement('style')
|
|
318
|
+
style.textContent = css
|
|
319
|
+
;(document.head || document.documentElement).appendChild(style)
|
|
274
320
|
})`;
|
|
275
321
|
function collectImportedCss(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
|
|
276
322
|
const files = [...chunk.viteMetadata?.importedCss ?? []];
|
|
@@ -297,11 +343,8 @@ function collectCss(chunk, bundle) {
|
|
|
297
343
|
files
|
|
298
344
|
};
|
|
299
345
|
}
|
|
300
|
-
function createCssInject(css
|
|
301
|
-
|
|
302
|
-
if (cssInject === "auto") return `${defaultCssInjector}(${payload});\n`;
|
|
303
|
-
if (typeof cssInject === "function") return `(${cssInject.toString()})(${payload});\n`;
|
|
304
|
-
return `(${cssInject})(${payload});\n`;
|
|
346
|
+
function createCssInject(css) {
|
|
347
|
+
return `${defaultCssInjector}(${JSON.stringify(css)});\n`;
|
|
305
348
|
}
|
|
306
349
|
//#endregion
|
|
307
350
|
//#region src/build/iife.ts
|
|
@@ -345,7 +388,7 @@ function createWatchProxyHeader(script, jsAbsPath) {
|
|
|
345
388
|
}
|
|
346
389
|
function generateWatchProxy(script, jsAbsPath) {
|
|
347
390
|
return generateHeader(createWatchProxyHeader(script, jsAbsPath), {
|
|
348
|
-
align: script.
|
|
391
|
+
align: script.headerAlign,
|
|
349
392
|
autoMetaUrls: false,
|
|
350
393
|
fileName: script.fileName,
|
|
351
394
|
generate: script.generate,
|
|
@@ -407,9 +450,9 @@ function findScriptForChunk(chunk, fileName, scripts) {
|
|
|
407
450
|
return scripts.find((script) => chunk.name === script.fileName || fileName === `${script.fileName}.js` || fileName === `${script.fileName}.user.js`);
|
|
408
451
|
}
|
|
409
452
|
function createHeadedUserscript(script, options) {
|
|
410
|
-
const headerConfig = withBuildGrants(script.header, options.wrapped
|
|
453
|
+
const headerConfig = withBuildGrants(script.header, options.wrapped);
|
|
411
454
|
const prefix = `${generateHeader(headerConfig, {
|
|
412
|
-
align: script.
|
|
455
|
+
align: script.headerAlign,
|
|
413
456
|
autoMetaUrls: script.autoMetaUrls,
|
|
414
457
|
fileName: script.fileName,
|
|
415
458
|
generate: script.generate,
|
|
@@ -457,10 +500,9 @@ function applyUserscriptBundle(bundle, config, context) {
|
|
|
457
500
|
const inlined = stripSourceMappingUrl(inlineImportedChunks(chunk, bundle));
|
|
458
501
|
const { css, files: cssFiles } = collectCss(chunk, bundle);
|
|
459
502
|
for (const cssFile of cssFiles) if (!keptCss.has(cssFile)) leftoverAssets.push(...withSourceMaps([cssFile]));
|
|
460
|
-
const cssPrelude = css ? createCssInject(css
|
|
503
|
+
const cssPrelude = css ? createCssInject(css) : "";
|
|
461
504
|
const body = `${inlined}${chunk.code}`;
|
|
462
505
|
const wrapped = ensureIife(body);
|
|
463
|
-
const extraGrants = css && script.cssInject === "auto" ? ["GM_addStyle"] : [];
|
|
464
506
|
const code = `${cssPrelude}${wrapped}`;
|
|
465
507
|
const emitFileProxy = Boolean(context.emitProxy && context.outDir && script.server.file);
|
|
466
508
|
leftoverAssets.push(`${fileName}.map`);
|
|
@@ -468,7 +510,6 @@ function applyUserscriptBundle(bundle, config, context) {
|
|
|
468
510
|
body,
|
|
469
511
|
code,
|
|
470
512
|
cssPrelude,
|
|
471
|
-
extraGrants,
|
|
472
513
|
inlined,
|
|
473
514
|
map: chunk.map,
|
|
474
515
|
wrapped
|
|
@@ -491,7 +532,7 @@ function applyUserscriptBundle(bundle, config, context) {
|
|
|
491
532
|
chunk.code = headed.code;
|
|
492
533
|
chunk.fileName = `${script.fileName}.user.js`;
|
|
493
534
|
if (script.metaFile) emitFile(`${script.fileName}.meta.js`, generateHeader(headed.headerConfig, {
|
|
494
|
-
align: script.
|
|
535
|
+
align: script.headerAlign,
|
|
495
536
|
autoMetaUrls: script.autoMetaUrls,
|
|
496
537
|
fileName: script.fileName,
|
|
497
538
|
generate: script.generate,
|
|
@@ -612,8 +653,7 @@ function toResolvedScript(config) {
|
|
|
612
653
|
prefix: config.server?.prefix ?? "server:",
|
|
613
654
|
file: config.server?.file ?? false
|
|
614
655
|
},
|
|
615
|
-
|
|
616
|
-
align: config.align ?? 1,
|
|
656
|
+
headerAlign: config.headerAlign ?? 1,
|
|
617
657
|
generate: config.generate,
|
|
618
658
|
autoMetaUrls: config.autoMetaUrls ?? false,
|
|
619
659
|
metaFile: config.metaFile ?? true
|
|
@@ -628,6 +668,19 @@ function collectAutoMetaUrlsWarnings(config) {
|
|
|
628
668
|
}
|
|
629
669
|
return warnings;
|
|
630
670
|
}
|
|
671
|
+
function collectHomepageRelativeUrlWarnings(config) {
|
|
672
|
+
const warnings = [];
|
|
673
|
+
for (const script of config.scripts) {
|
|
674
|
+
if (resolveHomePage(script.header)) continue;
|
|
675
|
+
const fields = listHomepageRelativeFields(script.header);
|
|
676
|
+
if (!fields.length) continue;
|
|
677
|
+
warnings.push(`[${PLUGIN_NAME}] "${script.fileName}" has relative header URLs (${fields.join(", ")}) but no homepage, homepageURL, website, or source`);
|
|
678
|
+
}
|
|
679
|
+
return warnings;
|
|
680
|
+
}
|
|
681
|
+
function collectConfigWarnings(config) {
|
|
682
|
+
return [...collectAutoMetaUrlsWarnings(config), ...collectHomepageRelativeUrlWarnings(config)];
|
|
683
|
+
}
|
|
631
684
|
function resolvePluginConfig(config) {
|
|
632
685
|
const items = Array.isArray(config) ? config : [config];
|
|
633
686
|
if (!items.length) throw new Error(`[${PLUGIN_NAME}] Provide a userscript config or a non-empty array`);
|
|
@@ -813,7 +866,7 @@ function createDevUserscript(options) {
|
|
|
813
866
|
root: options.root,
|
|
814
867
|
prefix: options.script.server.prefix,
|
|
815
868
|
headerOptions: {
|
|
816
|
-
align: options.script.
|
|
869
|
+
align: options.script.headerAlign,
|
|
817
870
|
autoMetaUrls: options.script.autoMetaUrls,
|
|
818
871
|
generate: options.script.generate
|
|
819
872
|
},
|
|
@@ -1029,7 +1082,7 @@ function UserscriptPlugin(config) {
|
|
|
1029
1082
|
command = viteConfig.command;
|
|
1030
1083
|
resolved = absolutizeEntries(resolved, viteConfig.root);
|
|
1031
1084
|
reactPreamble = hasReactRefreshPlugin(viteConfig.plugins);
|
|
1032
|
-
for (const message of
|
|
1085
|
+
for (const message of collectConfigWarnings(resolved)) viteConfig.logger.warn(message);
|
|
1033
1086
|
}
|
|
1034
1087
|
},
|
|
1035
1088
|
{
|
|
@@ -1087,4 +1140,4 @@ function UserscriptPlugin(config) {
|
|
|
1087
1140
|
];
|
|
1088
1141
|
}
|
|
1089
1142
|
//#endregion
|
|
1090
|
-
export {
|
|
1143
|
+
export { UserscriptPlugin as default };
|