vite-userscript-plugin 0.5.0 → 0.6.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/dist/index.js CHANGED
@@ -1,130 +1,290 @@
1
- import { readFileSync, writeFileSync } from 'node:fs';
2
- import { createServer } from 'node:http';
3
- import { dirname, resolve } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import websocket from 'websocket';
6
- import { banner } from './banner.js';
7
- import { grants, regexpScripts, template } from './constants.js';
8
- import css from './css.js';
9
- import { defineGrants, removeDuplicates, transform } from './helpers.js';
10
- function UserscriptPlugin(config) {
11
- let pluginConfig;
12
- let isBuildWatch;
13
- let socketConnection = null;
14
- const port = config.server?.port || 8000;
15
- const server = createServer((_, res) => {
16
- // const index = resolve(
17
- // dirname(fileURLToPath(import.meta.url)), '..', 'src', 'index.html'
18
- // )
19
- // res.writeHead(200, { 'Content-Type': 'html' })
20
- // res.end(readFileSync(index))
21
- });
22
- server.listen(port);
23
- const WebSocketServer = websocket.server;
24
- const ws = new WebSocketServer({ httpServer: server });
25
- ws.on('request', (request) => {
26
- socketConnection = request.accept(null, request.origin);
1
+ // src/index.ts
2
+ import { readFileSync, writeFileSync } from "fs";
3
+ import { createServer } from "http";
4
+ import { dirname, resolve } from "path";
5
+ import { fileURLToPath } from "url";
6
+ import { server } from "websocket";
7
+
8
+ // src/banner.ts
9
+ function banner(config) {
10
+ const metadata = [];
11
+ const configKeys = Object.keys(config);
12
+ const maxKeyLength = Math.max(...configKeys.map((key) => key.length)) + 1;
13
+ const addSpaces = (str) => {
14
+ return " ".repeat(maxKeyLength - str.length);
15
+ };
16
+ const addMetadata = (key, value) => {
17
+ const isBoolean = typeof value === "boolean";
18
+ if (isBoolean && !value)
19
+ return;
20
+ value = !isBoolean ? addSpaces(key) + value.toString() : "";
21
+ metadata.push(`// @${key}${value}`);
22
+ };
23
+ for (const [key, value] of Object.entries(config)) {
24
+ if (Array.isArray(value)) {
25
+ value.forEach((value2) => addMetadata(key, value2));
26
+ } else {
27
+ if (value === void 0)
28
+ continue;
29
+ addMetadata(key, value);
30
+ }
31
+ }
32
+ return [
33
+ "// ==UserScript==",
34
+ ...metadata,
35
+ "// ==/UserScript=="
36
+ ].join("\n");
37
+ }
38
+
39
+ // src/constants.ts
40
+ var regexpScripts = new RegExp(/\.(tsx?|jsx?)$/);
41
+ var regexpStyles = new RegExp(/\.(s?css|sass)$/);
42
+ var template = `console.warn("__TEMPLATE__")`;
43
+ var grants = [
44
+ "unsafeWindow",
45
+ "window.onurlchange",
46
+ "window.focus",
47
+ "window.close",
48
+ "GM_setValue",
49
+ "GM_getValue",
50
+ "GM_deleteValue",
51
+ "GM_listValues",
52
+ "GM_setClipboard",
53
+ "GM_addStyle",
54
+ "GM_addElement",
55
+ "GM_addValueChangeListener",
56
+ "GM_removeValueChangeListener",
57
+ "GM_registerMenuCommand",
58
+ "GM_unregisterMenuCommand",
59
+ "GM_download",
60
+ "GM_getTab",
61
+ "GM_getTabs",
62
+ "GM_saveTab",
63
+ "GM_openInTab",
64
+ "GM_notification",
65
+ "GM_getResourceURL",
66
+ "GM_getResourceText",
67
+ "GM_xmlhttpRequest",
68
+ "GM_webRequest",
69
+ "GM_log",
70
+ "GM_info"
71
+ ];
72
+
73
+ // src/helpers.ts
74
+ import { transformWithEsbuild } from "vite";
75
+ function removeDuplicates(arr) {
76
+ return [...new Set(Array.isArray(arr) ? arr : arr ? [arr] : [])];
77
+ }
78
+ async function transform({
79
+ file,
80
+ name,
81
+ loader
82
+ }) {
83
+ const { code } = await transformWithEsbuild(file, name, {
84
+ loader,
85
+ minify: true
86
+ });
87
+ return code;
88
+ }
89
+ function defineGrants(code) {
90
+ const definedGrants = [];
91
+ for (const grant of grants) {
92
+ if (code.indexOf(grant) !== -1) {
93
+ definedGrants.push(grant);
94
+ }
95
+ }
96
+ return definedGrants;
97
+ }
98
+
99
+ // src/css.ts
100
+ var CSS = class {
101
+ styles = /* @__PURE__ */ new Map();
102
+ add(entry, code, path) {
103
+ if (regexpStyles.test(path)) {
104
+ this.styles.set(path, code);
105
+ return {
106
+ code: ""
107
+ };
108
+ }
109
+ if (path.includes(entry)) {
110
+ return {
111
+ code: code + template
112
+ };
113
+ }
114
+ return null;
115
+ }
116
+ async minify(file, name) {
117
+ return await transform({
118
+ file,
119
+ name,
120
+ loader: "css"
27
121
  });
28
- return {
29
- name: 'vite-userscript-plugin',
30
- apply: 'build',
31
- config() {
32
- return {
33
- build: {
34
- lib: {
35
- entry: config.entry,
36
- name: config.metadata.name,
37
- formats: ['iife'],
38
- fileName: () => `${config.metadata.name}.js`
39
- },
40
- rollupOptions: {
41
- output: {
42
- exports: 'none',
43
- extend: true
44
- }
45
- }
46
- }
47
- };
48
- },
49
- configResolved(cfg) {
50
- pluginConfig = cfg;
51
- isBuildWatch = (cfg.build.watch ?? false);
52
- const { match, require, include, exclude, resource, connect } = config.metadata;
53
- config.metadata.match = removeDuplicates(match);
54
- config.metadata.require = removeDuplicates(require);
55
- config.metadata.include = removeDuplicates(include);
56
- config.metadata.exclude = removeDuplicates(exclude);
57
- config.metadata.resource = removeDuplicates(resource);
58
- config.metadata.connect = removeDuplicates(connect);
59
- },
60
- async transform(code, path) {
61
- const style = await css.minify(code, path);
62
- return css.add(config.entry, style.replace('\n', ''), path);
63
- },
64
- generateBundle(_, bundle) {
65
- for (const [_, file] of Object.entries(bundle)) {
66
- const styleModules = Object.keys(file.modules);
67
- css.merge(styleModules);
68
- }
69
- },
70
- async writeBundle(_, bundle) {
71
- for (const [fileName] of Object.entries(bundle)) {
72
- if (regexpScripts.test(fileName)) {
73
- const rootDir = pluginConfig.root;
74
- const outDir = pluginConfig.build.outDir;
75
- const outPath = resolve(rootDir, outDir, fileName);
76
- const hmrPath = resolve(rootDir, outDir, 'hmr.js');
77
- const proxyFilePath = resolve(rootDir, outDir, `${config.metadata.name}.proxy.user.js`);
78
- const userFilePath = resolve(rootDir, outDir, `${config.metadata.name}.user.js`);
79
- try {
80
- let source = readFileSync(outPath, 'utf8');
81
- // prettier-ignore
82
- config.metadata.grant = removeDuplicates(isBuildWatch
83
- ? grants
84
- : config.autoGrants ?? true
85
- ? defineGrants(source)
86
- : [...(config.metadata.grant ?? []), 'GM_addStyle', 'GM_info']);
87
- // prettier-ignore-end
88
- if (isBuildWatch) {
89
- const hmrFile = readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), 'hmr.js'), 'utf8');
90
- const hmrScript = await transform({
91
- file: hmrFile.replace('__PORT__', port.toString()),
92
- name: hmrPath,
93
- loader: 'js'
94
- });
95
- writeFileSync(hmrPath, hmrScript);
96
- writeFileSync(proxyFilePath, banner({
97
- ...config.metadata,
98
- require: [
99
- ...config.metadata.require,
100
- 'file://' + hmrPath,
101
- 'file://' + outPath
102
- ]
103
- }));
104
- }
105
- source = source.replace(template, `${css.inject()}`);
106
- source = await transform({
107
- file: source,
108
- name: fileName,
109
- loader: 'js'
110
- });
111
- writeFileSync(outPath, source);
112
- writeFileSync(userFilePath, `${banner(config.metadata)}\n\n${source}`);
113
- }
114
- catch (err) {
115
- console.log(err);
116
- }
117
- }
122
+ }
123
+ inject() {
124
+ const styles = [...this.styles.values()].join("");
125
+ if (!styles)
126
+ return;
127
+ return `GM_addStyle(\`${styles}\`)`;
128
+ }
129
+ merge(modules) {
130
+ const styleModules = [];
131
+ for (const module of modules) {
132
+ const style = this.styles.get(module);
133
+ if (!style)
134
+ continue;
135
+ styleModules.push([module, style]);
136
+ }
137
+ this.styles.clear();
138
+ styleModules.forEach((value) => this.styles.set(...value));
139
+ }
140
+ };
141
+ var css_default = new CSS();
142
+
143
+ // src/index.ts
144
+ function UserscriptPlugin(config) {
145
+ var _a;
146
+ let pluginConfig;
147
+ let isBuildWatch;
148
+ let socketConnection = null;
149
+ const port = ((_a = config.server) == null ? void 0 : _a.port) || 8e3;
150
+ const httpServer = createServer();
151
+ httpServer.listen(port);
152
+ const WebSocketServer = server;
153
+ const ws = new WebSocketServer({ httpServer });
154
+ ws.on("request", (request) => {
155
+ socketConnection = request.accept(null, request.origin);
156
+ });
157
+ return {
158
+ name: "vite-userscript-plugin",
159
+ apply: "build",
160
+ config() {
161
+ return {
162
+ build: {
163
+ lib: {
164
+ entry: config.entry,
165
+ name: config.metadata.name,
166
+ formats: ["iife"],
167
+ fileName: () => `${config.metadata.name}.js`
168
+ },
169
+ rollupOptions: {
170
+ output: {
171
+ exports: "none",
172
+ extend: true
118
173
  }
119
- },
120
- buildEnd() {
121
- if (socketConnection) {
122
- socketConnection.sendUTF(JSON.stringify({
123
- message: 'reload'
124
- }));
174
+ }
175
+ }
176
+ };
177
+ },
178
+ configResolved(cfg) {
179
+ pluginConfig = cfg;
180
+ isBuildWatch = cfg.build.watch ?? false;
181
+ const { match, require: require2, include, exclude, resource, connect } = config.metadata;
182
+ config.metadata.match = removeDuplicates(match);
183
+ config.metadata.require = removeDuplicates(require2);
184
+ config.metadata.include = removeDuplicates(include);
185
+ config.metadata.exclude = removeDuplicates(exclude);
186
+ config.metadata.resource = removeDuplicates(resource);
187
+ config.metadata.connect = removeDuplicates(connect);
188
+ },
189
+ async transform(code, path) {
190
+ const style = await css_default.minify(code, path);
191
+ return css_default.add(config.entry, style.replace("\n", ""), path);
192
+ },
193
+ generateBundle(_, bundle) {
194
+ for (const [_2, file] of Object.entries(bundle)) {
195
+ const styleModules = Object.keys(
196
+ file.modules
197
+ );
198
+ css_default.merge(styleModules);
199
+ }
200
+ },
201
+ async writeBundle(_, bundle) {
202
+ for (const [fileName] of Object.entries(bundle)) {
203
+ if (regexpScripts.test(fileName)) {
204
+ const rootDir = pluginConfig.root;
205
+ const outDir = pluginConfig.build.outDir || "dist";
206
+ const outPath = resolve(rootDir, outDir, fileName);
207
+ const hotReloadPath = resolve(
208
+ dirname(fileURLToPath(import.meta.url)),
209
+ "__hot-reload__.js"
210
+ );
211
+ const proxyFilePath = resolve(
212
+ rootDir,
213
+ outDir,
214
+ `${config.metadata.name}.proxy.user.js`
215
+ );
216
+ const userFilePath = resolve(
217
+ rootDir,
218
+ outDir,
219
+ `${config.metadata.name}.user.js`
220
+ );
221
+ try {
222
+ let source = readFileSync(outPath, "utf8");
223
+ config.metadata.grant = removeDuplicates(
224
+ isBuildWatch ? grants : config.autoGrants ?? true ? defineGrants(source) : [...config.metadata.grant ?? [], "GM_addStyle", "GM_info"]
225
+ );
226
+ if (isBuildWatch) {
227
+ const hotReloadFile = readFileSync(
228
+ resolve(
229
+ dirname(fileURLToPath(import.meta.url)),
230
+ "hot-reload.js"
231
+ ),
232
+ "utf8"
233
+ );
234
+ const hotReloadScript = await transform({
235
+ file: hotReloadFile.replace("__PORT__", port.toString()),
236
+ name: hotReloadPath,
237
+ loader: "js"
238
+ });
239
+ writeFileSync(hotReloadPath, hotReloadScript);
240
+ writeFileSync(
241
+ proxyFilePath,
242
+ banner({
243
+ ...config.metadata,
244
+ require: [
245
+ ...config.metadata.require,
246
+ "file://" + hotReloadPath,
247
+ "file://" + outPath
248
+ ]
249
+ })
250
+ );
125
251
  }
252
+ source = source.replace(template, `${css_default.inject()}`);
253
+ source = await transform({
254
+ file: source,
255
+ name: fileName,
256
+ loader: "js"
257
+ });
258
+ writeFileSync(outPath, source);
259
+ writeFileSync(
260
+ userFilePath,
261
+ `${banner(config.metadata)}
262
+
263
+ ${source}`
264
+ );
265
+ } catch (err) {
266
+ console.log(err);
267
+ }
126
268
  }
127
- };
269
+ }
270
+ if (!isBuildWatch) {
271
+ httpServer.close();
272
+ process.exit(0);
273
+ }
274
+ },
275
+ buildEnd() {
276
+ if (socketConnection) {
277
+ socketConnection.sendUTF(
278
+ JSON.stringify({
279
+ message: "reload"
280
+ })
281
+ );
282
+ }
283
+ }
284
+ };
128
285
  }
129
- export { UserscriptPlugin };
130
- export default UserscriptPlugin;
286
+ var src_default = UserscriptPlugin;
287
+ export {
288
+ UserscriptPlugin,
289
+ src_default as default
290
+ };
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "vite-userscript-plugin",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
- "main": "./dist/index.js",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "exports": {
9
+ "require": "./dist/index.cjs",
10
+ "import": "./dist/index.js"
11
+ },
7
12
  "files": [
8
13
  "dist"
9
14
  ],
@@ -33,11 +38,10 @@
33
38
  "@types/websocket": "^1.0.5"
34
39
  },
35
40
  "peerDependencies": {
36
- "@types/tampermonkey": "latest"
41
+ "@types/tampermonkey": ">=4.0.0"
37
42
  },
38
43
  "scripts": {
39
- "dev": "tsc --build --watch",
40
- "build": "pnpm clean && tsc --build",
41
- "clean": "del-cli dist"
44
+ "dev": "tsup --watch",
45
+ "build": "tsup"
42
46
  }
43
47
  }
package/dist/banner.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import type { MetadataConfig } from './types.js';
2
- export declare function banner(config: MetadataConfig): string;
package/dist/banner.js DELETED
@@ -1,30 +0,0 @@
1
- export function banner(config) {
2
- const metadata = [];
3
- const configKeys = Object.keys(config);
4
- const maxKeyLength = Math.max(...configKeys.map((key) => key.length)) + 1;
5
- const addSpaces = (str) => {
6
- return ' '.repeat(maxKeyLength - str.length);
7
- };
8
- const addMetadata = (key, value) => {
9
- const isBoolean = typeof value === 'boolean';
10
- if (isBoolean && !value)
11
- return;
12
- value = !isBoolean ? addSpaces(key) + value.toString() : '';
13
- metadata.push(`// @${key}${value}`);
14
- };
15
- for (const [key, value] of Object.entries(config)) {
16
- if (Array.isArray(value)) {
17
- value.forEach((value) => addMetadata(key, value));
18
- }
19
- else {
20
- if (value === undefined)
21
- continue;
22
- addMetadata(key, value);
23
- }
24
- }
25
- return [
26
- '// ==UserScript==',
27
- ...metadata,
28
- '// ==/UserScript=='
29
- ].join('\n');
30
- }
@@ -1,4 +0,0 @@
1
- export declare const regexpScripts: RegExp;
2
- export declare const regexpStyles: RegExp;
3
- export declare const template = "console.warn(\"__TEMPLATE__\")";
4
- export declare const grants: readonly ["unsafeWindow", "window.onurlchange", "window.focus", "window.close", "GM_setValue", "GM_getValue", "GM_deleteValue", "GM_listValues", "GM_setClipboard", "GM_addStyle", "GM_addElement", "GM_addValueChangeListener", "GM_removeValueChangeListener", "GM_registerMenuCommand", "GM_unregisterMenuCommand", "GM_download", "GM_getTab", "GM_getTabs", "GM_saveTab", "GM_openInTab", "GM_notification", "GM_getResourceURL", "GM_getResourceText", "GM_xmlhttpRequest", "GM_webRequest", "GM_log", "GM_info"];
package/dist/constants.js DELETED
@@ -1,32 +0,0 @@
1
- export const regexpScripts = new RegExp(/\.js/);
2
- export const regexpStyles = new RegExp(/\.css|\.sass|\.scss|\.less/);
3
- export const template = `console.warn("__TEMPLATE__")`;
4
- export const grants = [
5
- 'unsafeWindow',
6
- 'window.onurlchange',
7
- 'window.focus',
8
- 'window.close',
9
- 'GM_setValue',
10
- 'GM_getValue',
11
- 'GM_deleteValue',
12
- 'GM_listValues',
13
- 'GM_setClipboard',
14
- 'GM_addStyle',
15
- 'GM_addElement',
16
- 'GM_addValueChangeListener',
17
- 'GM_removeValueChangeListener',
18
- 'GM_registerMenuCommand',
19
- 'GM_unregisterMenuCommand',
20
- 'GM_download',
21
- 'GM_getTab',
22
- 'GM_getTabs',
23
- 'GM_saveTab',
24
- 'GM_openInTab',
25
- 'GM_notification',
26
- 'GM_getResourceURL',
27
- 'GM_getResourceText',
28
- 'GM_xmlhttpRequest',
29
- 'GM_webRequest',
30
- 'GM_log',
31
- 'GM_info'
32
- ];
package/dist/css.d.ts DELETED
@@ -1,11 +0,0 @@
1
- declare class CSS {
2
- private readonly styles;
3
- add(entry: string, code: string, path: string): {
4
- code: string;
5
- } | null;
6
- minify(file: string, name: string): Promise<string>;
7
- inject(): string | void;
8
- merge(modules: string[]): void;
9
- }
10
- declare const _default: CSS;
11
- export default _default;
package/dist/css.js DELETED
@@ -1,51 +0,0 @@
1
- import { regexpStyles, template } from './constants.js';
2
- import { transform } from './helpers.js';
3
- class CSS {
4
- constructor() {
5
- Object.defineProperty(this, "styles", {
6
- enumerable: true,
7
- configurable: true,
8
- writable: true,
9
- value: new Map()
10
- });
11
- }
12
- add(entry, code, path) {
13
- if (regexpStyles.test(path)) {
14
- this.styles.set(path, code);
15
- return {
16
- code: ''
17
- };
18
- }
19
- if (path.includes(entry)) {
20
- return {
21
- code: code + template
22
- };
23
- }
24
- return null;
25
- }
26
- async minify(file, name) {
27
- return await transform({
28
- file,
29
- name,
30
- loader: 'css'
31
- });
32
- }
33
- inject() {
34
- const styles = [...this.styles.values()].join('');
35
- if (!styles)
36
- return;
37
- return `GM_addStyle(\`${styles}\`)`;
38
- }
39
- merge(modules) {
40
- const styleModules = [];
41
- for (const module of modules) {
42
- const style = this.styles.get(module);
43
- if (!style)
44
- continue;
45
- styleModules.push([module, style]);
46
- }
47
- this.styles.clear();
48
- styleModules.forEach((value) => this.styles.set(...value));
49
- }
50
- }
51
- export default new CSS();
package/dist/helpers.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { Grants, Transform } from './types.js';
2
- export declare function removeDuplicates(arr: string | string[] | readonly string[] | undefined): any[];
3
- export declare function transform({ file, name, loader }: Transform): Promise<string>;
4
- export declare function defineGrants(code: string): Grants[];
package/dist/helpers.js DELETED
@@ -1,21 +0,0 @@
1
- import { transformWithEsbuild } from 'vite';
2
- import { grants } from './constants.js';
3
- export function removeDuplicates(arr) {
4
- return [...new Set(Array.isArray(arr) ? arr : arr ? [arr] : [])];
5
- }
6
- export async function transform({ file, name, loader }) {
7
- const { code } = await transformWithEsbuild(file, name, {
8
- loader,
9
- minify: true
10
- });
11
- return code;
12
- }
13
- export function defineGrants(code) {
14
- const definedGrants = [];
15
- for (const grant of grants) {
16
- if (code.indexOf(grant) !== -1) {
17
- definedGrants.push(grant);
18
- }
19
- }
20
- return definedGrants;
21
- }
package/dist/hmr.d.ts DELETED
@@ -1 +0,0 @@
1
- declare function HRM(): void;
package/dist/hmr.js DELETED
@@ -1,22 +0,0 @@
1
- "use strict";
2
- function HRM() {
3
- const ws = new WebSocket('ws://localhost:__PORT__');
4
- ws.addEventListener('open', () => {
5
- console.clear();
6
- const { script } = GM_info;
7
- console.group(`${script.name}@${script.version}`);
8
- console.log(GM_info);
9
- console.groupEnd();
10
- });
11
- ws.addEventListener('close', (event) => {
12
- console.warn('Socket is closed. Reconnect will be attempted in 1 second.', event.reason);
13
- setTimeout(HRM, 1000);
14
- });
15
- ws.addEventListener('error', () => {
16
- ws.close();
17
- });
18
- ws.addEventListener('message', () => {
19
- location.reload();
20
- });
21
- }
22
- HRM();