vite-plugin-monkey
vite-plugin-monkey copied to clipboard
A vite plugin server and build your.user.js for userscript engine like Tampermonkey, Violentmonkey, Greasemonkey, ScriptCat
vite-plugin-monkey
README | 中文文档
vite plugin server and build *.user.js for Tampermonkey and Violentmonkey and Greasemonkey
feature
- support Tampermonkey and Violentmonkey and Greasemonkey
- inject userscript comment to build bundle
- auto open *.user.js in default browser when userscript change
- external cdn url inject to userscript @require
- use GM_api by ESM import with type hints
- when vite preview, auto open browser install dist.user.js
- full typescript support and vite feature
quick usage (recommend)
just like vite create
pnpm create monkey
# npm create monkey
# yarn create monkey
then you can choose the following template
JavaScript | TypeSript |
---|---|
empty (only js) | empty-ts (only ts) |
vanilla (js + css) | vanilla-ts (ts + css) |
vue | vue-ts |
react | react-ts |
preact | preact-ts |
svelte | svelte-ts |
Sample: Initializing a Template
Sample: Hot Module Replacement
Sample: Build & Preview
installation
pnpm add -D vite-plugin-monkey
# npm i -D vite-plugin-monkey
# yarn add -D vite-plugin-monkey
config
MonkeyOption
export interface MonkeyOption {
/**
* userscript entry file path
*/
entry: string;
userscript: MonkeyUserScript;
format?: Format;
/**
* alias of vite-plugin-monkey/dist/client
* @default '$'
* @example
* // vite.config.ts, plugin will auto modify config
* resolve: {
* alias: {
* [clientAlias]: 'vite-plugin-monkey/dist/client',
* },
* }
* @example
* // vite-env.d.ts, you must manual modify .env file
* declare module clientAlias {
* export * from 'vite-plugin-monkey/dist/client';
* }
*/
clientAlias?: string;
server?: {
/**
* auto open *.user.js in default browser when userscript comment change or vite server first start
* @default true
*/
open?: boolean;
/**
* name prefix, distinguish server.user.js and build.user.js in monkey extension install list, if you not want prefix, set false
* @default 'dev:'
*/
prefix?: string | ((name: string) => string) | false;
/**
* mount GM_api to unsafeWindow, not recommend it, you should use GM_api by ESM import
* @default false
*/
mountGmApi?: boolean;
};
build?: {
/**
* build bundle userscript file name, it should end with '.user.js'
* @default (package.json.name||'monkey')+'.user.js'
*/
fileName?: string;
/**
* build bundle userscript comment file name, this file is only include comment
*
* it can be used by userscript.updateURL, when checking for updates, just download this small file instead of downloading the entire script
*
* it should end with '.meta.js', if set false, will not generate this file
*
* if set true, will equal to fileName.replace(/\\.user\\.js$/,'.meta.js')
* @default false
*/
metaFileName?: string | boolean;
/**
* @example
* {
* vue:'Vue',
* // need manually set userscript.require = ['https://unpkg.com/[email protected]/dist/vue.global.js']
* vuex:['Vuex', 'https://unpkg.com/[email protected]/dist/vuex.global.js'],
* // use fixed version, plugin will auto add this url to userscript.require
* vuex:['Vuex', (version, name)=>`https://unpkg.com/${name}@${version}/dist/vuex.global.js`],
* // best recommended this
* }
* // type Lib2Url = (version: string, name: string) => string
*/
externalGlobals?: Record<
string,
string | [string, ...(string | Lib2Url)[]]
>;
/**
* according to final code bundle, auto inject GM_* or GM.* to userscript comment grant
*
* the judgment is based on String.prototype.includes
* @default true
*/
autoGrant?: boolean;
/**
* check all require urls for availability, http code is 2xx
* @default false
*/
checkCDN?: boolean;
};
}
MonkeyUserScript
/**
* UserScript, merge metadata from Greasemonkey, Tampermonkey, Violentmonkey, Greasyfork
*/
export type MonkeyUserScript = GreasemonkeyUserScript &
TampermonkeyUserScript &
ViolentmonkeyUserScript &
GreasyforkUserScript &
MergemonkeyUserScript;
- GreasemonkeyUserScript
- TampermonkeyUserScript
- ViolentmonkeyUserScript
- GreasyforkUserScript
- MergemonkeyUserScript
Format
/**
* format userscript comment
*/
export type Format = {
/**
* @description note font_width/font_family, suggest fixed-width font
* @default 2, true
*/
align?: number | boolean | AlignFunc;
};
export type AlignFunc = (
p0: [string, ...string[]][],
) => [string, ...string[]][];
externalGlobals cdn util
// use example
import { cdn } from 'vite-plugin-monkey';
{
externalGlobals: {
'blueimp-md5': cdn.bytecdntp('md5', 'js/md5.min.js'),
},
}
there is the following cdn to use, full detail see cdn.ts
- jsdelivr https://www.jsdelivr.com/
- unpkg https://unpkg.com/
- bytecdntp https://cdn.bytedance.com/
- bootcdn https://www.bootcdn.cn/all/
- baomitu https://cdn.baomitu.com/
- staticfile https://staticfile.org/
- cdnjs https://cdnjs.com/libraries
- zhimg https://unpkg.zhimg.com/
if you want use other cdn, you can see external-scripts
ESM GM_api
we can use GM_api by esm module
import { GM_cookie, unsafeWindow, monkeyWindow, GM_addElement } from '$';
// $ is the alias of vite-plugin-monkey/dist/client, you can use others
// whatever it is serve or build mode, monkeyWindow is always the window of [UserScript Scope]
console.log(monkeyWindow);
GM_addElement(document.body, 'div', { innerHTML: 'hello' });
// whatever it is serve or build mode, unsafeWindow is always host window
if (unsafeWindow == window) {
console.log('scope->host, esm mode');
} else {
console.log('scope->monkey, iife mode');
}
GM_cookie.list({}, (cookies, error) => {
if (error) {
console.log(error);
} else {
const [cookie] = cookies;
if (cookie) {
console.log(cookie);
}
}
});
example
vite config is simple, see vite.config.ts, build file see example-project.user.js
and preact/react/svelte/vanilla/vue examples see create-monkey
some note
CSP
you can use Tampermonkey then open extension://iikmkjmpaadaobahmlepeloendndfphd/options.html#nav=settings
at Security
, set Modify existing content security policy (CSP) headers
to Remove entirely (possibly unsecure)
full detail see issues/1
and if you use Violentmonkey
/Greasemonkey
, you can solve it in the following ways
- chrome - Disable Content-Security-Policy
- edge - Disable Content-Security-Policy
- firefox - disable
security.csp.enable
in theabout:config
menu
Polyfill
because of vite/issues/1639, now you can not use @vitejs/plugin-legacy
the following is a feasible solution by @require cdn
import { defineConfig } from 'vite';
import monkeyPlugin from 'vite-plugin-monkey';
export default defineConfig({
plugins: [
monkeyPlugin({
userscript: {
require: [
// polyfill all
'https://cdn.jsdelivr.net/npm/core-js-bundle@latest/minified.js',
// or use polyfill.io
// https://polyfill.io/v3/polyfill.min.js
],
},
}),
],
});