UNPKG

vite-plugin-monkey

Version:

A vite plugin server and build your.user.js for userscript engine like Tampermonkey and Violentmonkey and Greasemonkey

780 lines (766 loc) 27.5 kB
import { Plugin } from 'vite'; declare const gmIdentifiers: readonly ["GM_addElement", "GM_addStyle", "GM_addValueChangeListener", "GM_cookie", "GM_deleteValue", "GM_deleteValues", "GM_download", "GM_getResourceText", "GM_getResourceURL", "GM_getTab", "GM_getTabs", "GM_getValue", "GM_getValues", "GM_info", "GM_listValues", "GM_log", "GM_notification", "GM_openInTab", "GM_registerMenuCommand", "GM_removeValueChangeListener", "GM_saveTab", "GM_setClipboard", "GM_setValue", "GM_setValues", "GM_unregisterMenuCommand", "GM_webRequest", "GM_xmlhttpRequest", "GM_audio"]; declare const gmMembers: readonly ["GM.addElement", "GM.addStyle", "GM.addValueChangeListener", "GM.cookie", "GM.deleteValue", "GM.deleteValues", "GM.download", "GM.getResourceText", "GM.getResourceUrl", "GM.getTab", "GM.getTabs", "GM.getValue", "GM.getValues", "GM.info", "GM.listValues", "GM.log", "GM.notification", "GM.openInTab", "GM.registerMenuCommand", "GM.removeValueChangeListener", "GM.saveTab", "GM.setClipboard", "GM.setValue", "GM.setValues", "GM.unregisterMenuCommand", "GM.webRequest", "GM.xmlHttpRequest", "GM.audio"]; declare const othersGrantNames: readonly ["unsafeWindow", "window.close", "window.focus", "window.onurlchange"]; type GrantType = (typeof gmIdentifiers)[number] | (typeof gmMembers)[number] | (typeof othersGrantNames)[number]; type GreaseRunAt = 'document-start' | 'document-end' | 'document-idle'; /** * @see https://wiki.greasespot.net/Metadata_Block */ interface GreasemonkeyUserScript { /** * @see https://wiki.greasespot.net/Metadata_Block#.40name * */ name?: string | LocaleType<string>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40namespace */ namespace?: string; /** * @see https://wiki.greasespot.net/Metadata_Block#.40version * */ version?: string; /** * @see https://wiki.greasespot.net/Metadata_Block#.40description * */ description?: string | LocaleType<string>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40icon */ icon?: string; /** * @see https://wiki.greasespot.net/Metadata_Block#.40include */ include?: IArray<string | RegExp>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40match */ match?: IArray<string | RegExp>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40exclude */ exclude?: IArray<string | RegExp>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40require */ require?: IArray<string>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40resource */ resource?: Record<string, string>; /** * @see https://wiki.greasespot.net/Metadata_Block#.40noframes */ noframes?: boolean; } /** * @see https://www.tampermonkey.net/documentation.php#api:GM_webRequest */ interface GmWebRequestRule { selector: string | { include?: string | string[]; match?: string | string[]; exclude?: string | string[]; }; action: string | { cancel?: boolean; redirect?: string | { url: string; from?: string; to?: string; }; }; } type TamperRunAt = 'document-start' | 'document-body' | 'document-end' | 'document-idle' | 'context-menu'; interface AntifeatureType { tag?: string; type: 'ads' | 'tracking' | 'miner'; description: string; } /** * @see https://www.tampermonkey.net/documentation.php */ interface TampermonkeyUserScript { /** * @see https://www.tampermonkey.net/documentation.php#meta:name * */ name?: string | LocaleType<string>; /** * @see https://www.tampermonkey.net/documentation.php#meta:namespace */ namespace?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:copyright */ copyright?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:version * */ version?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:author * */ author?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:description * */ description?: string | LocaleType<string>; /** * @see https://www.tampermonkey.net/documentation.php#meta:homepage * */ homepage?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:homepage * */ homepageURL?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:homepage */ website?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:homepage */ source?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:icon */ icon?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:icon */ iconURL?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:icon */ defaulticon?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:icon64 */ icon64?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:icon64 */ icon64URL?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:updateURL */ updateURL?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:downloadURL */ downloadURL?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:supportURL */ supportURL?: string; /** * @see https://www.tampermonkey.net/documentation.php#meta:include */ include?: IArray<string | RegExp>; /** * @see https://www.tampermonkey.net/documentation.php#meta:match */ match?: IArray<string | RegExp>; /** * @see https://www.tampermonkey.net/documentation.php#meta:exclude */ exclude?: IArray<string | RegExp>; /** * @see https://www.tampermonkey.net/documentation.php#meta:require */ require?: IArray<string>; /** * @see https://www.tampermonkey.net/documentation.php#meta:resource */ resource?: Record<string, string>; /** * @see https://www.tampermonkey.net/documentation.php#meta:connect */ connect?: IArray<string>; /** * @see https://www.tampermonkey.net/documentation.php#meta:tag */ tag?: IArray<string>; /** * @see https://www.tampermonkey.net/documentation.php?locale=en#meta:run_in */ 'run-in'?: IArray<string>; /** * @see https://www.tampermonkey.net/documentation.php#meta:sandbox */ sandbox?: 'raw' | 'JavaScript' | 'DOM'; /** * @see https://www.tampermonkey.net/documentation.php#meta:antifeature */ antifeature?: IArray<AntifeatureType>; /** * @see https://www.tampermonkey.net/documentation.php#meta:noframes */ noframes?: boolean; /** * @see https://www.tampermonkey.net/documentation.php#meta:webRequest */ webRequest?: IArray<GmWebRequestRule>; /** * @see https://www.tampermonkey.net/documentation.php#meta:unwrap */ unwrap?: boolean; } type ViolentRunAt = 'document-end' | 'document-start' | 'document-idle'; type ViolentInjectInto = 'page' | 'content' | 'auto'; /** * @see https://violentmonkey.github.io/api/metadata-block/ */ interface ViolentmonkeyUserScript { /** * @see https://violentmonkey.github.io/api/metadata-block/#name * */ name?: string | LocaleType<string>; /** * @see https://violentmonkey.github.io/api/metadata-block/#namespace */ namespace?: string; /** * @see https://violentmonkey.github.io/api/metadata-block/#version * */ version?: string; /** * @see https://violentmonkey.github.io/api/metadata-block/#description * */ description?: string | LocaleType<string>; /** * @see https://violentmonkey.github.io/api/metadata-block/#icon */ icon?: string; /** * @see https://violentmonkey.github.io/api/metadata-block/#downloadurl */ downloadURL?: string; /** * @see https://violentmonkey.github.io/api/metadata-block/#supporturl */ supportURL?: string; /** * @see https://violentmonkey.github.io/api/metadata-block/#homepageurl * */ homepageURL?: string; /** * @see https://violentmonkey.github.io/api/metadata-block/#include--exclude * @see https://violentmonkey.github.io/api/matching/#include--exclude */ include?: IArray<string | RegExp>; /** * @see https://violentmonkey.github.io/api/metadata-block/#match--exclude-match * @see https://violentmonkey.github.io/api/matching/#match--exclude-match */ match?: IArray<string | RegExp>; /** * @see https://violentmonkey.github.io/api/metadata-block/#match--exclude-match * @see https://violentmonkey.github.io/api/matching/#match--exclude-match */ 'exclude-match'?: IArray<string | RegExp>; /** * @see https://violentmonkey.github.io/api/metadata-block/#include--exclude * @see https://violentmonkey.github.io/api/matching/#include--exclude */ exclude?: IArray<string | RegExp>; /** * @see https://violentmonkey.github.io/api/metadata-block/#require */ require?: IArray<string>; /** * @see https://violentmonkey.github.io/api/metadata-block/#resource */ resource?: Record<string, string>; /** * @see https://violentmonkey.github.io/api/metadata-block/#noframes */ noframes?: boolean; /** * @see https://violentmonkey.github.io/api/metadata-block/#inject-into */ 'inject-into'?: ViolentInjectInto; /** * @see https://violentmonkey.github.io/api/metadata-block/#unwrap */ unwrap?: boolean; } /** * @see https://greasyfork.org/help/meta-keys */ interface GreasyforkUserScript { /** * @see https://greasyfork.org/help/meta-keys * @default package.json.license */ license?: string; /** * @see https://greasyfork.org/help/meta-keys */ contributionURL?: string; /** * @see https://greasyfork.org/help/meta-keys */ contributionAmount?: string; /** * @see https://greasyfork.org/help/meta-keys */ compatible?: string; /** * @see https://greasyfork.org/help/meta-keys */ incompatible?: string; } interface MergemonkeyUserScript { /** * @default package.json.name??'monkey' * @default {...{'':package.json.name??'monkey'},...name} // if name is object */ name?: string | LocaleType<string>; namespace?: string; /** * @default package.json.version */ version?: string; /** * @default package.json.description * @default {...{'':package.json.description},...description} // if description is object */ description?: string | LocaleType<string>; /** * @default package.json.author */ author?: string; /** * @default package.json.homepage */ homepage?: string; /** * @default package.json.homepage */ homepageURL?: string; /** * @default package.json.repository */ source?: string; /** * @default package.json.bugs */ supportURL?: string; /** * @see https://wiki.greasespot.net/Metadata_Block#.40run-at * * @see https://www.tampermonkey.net/documentation.php#meta:run_at * * @see https://violentmonkey.github.io/api/metadata-block/#run-at * */ 'run-at'?: GreaseRunAt | TamperRunAt | ViolentRunAt; /** * @see https://wiki.greasespot.net/Metadata_Block#.40grant * * @see https://www.tampermonkey.net/documentation.php#meta:grant * * @see https://violentmonkey.github.io/api/metadata-block/#grant * * if set '\*', will add all GM_* to UserScript */ grant?: IArray<GrantType> | 'none' | '*'; /** * custom extra meta * @example * [['antifeature', ['miner', 'hello233']]] * // --> * // \@antifeature miner hello233 */ $extra?: [string, IArray<string>][] | Record<string, IArray<string>>; } /** * UserScript, merge metadata from Greasemonkey, Tampermonkey, Violentmonkey, Greasyfork */ type MonkeyUserScript = GreasemonkeyUserScript & TampermonkeyUserScript & ViolentmonkeyUserScript & GreasyforkUserScript & MergemonkeyUserScript; type Thenable<T> = T | Promise<T>; type IArray<T = unknown> = T | T[]; /** * key is language code or '' * @see https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry * @example * { * '':'default_name', * 'zh-CN':'名字', * ja: '名前' * } */ type LocaleType<T = unknown> = Record<string, T>; interface PkgOptions { name: string; version: string; dynamic: boolean; importName: string; resolveName: string; resourceUrl: string; resourceName: string; } interface Pkg2UrlFn { (pkg: { name: string; version: string; importName: string; resolveName: string; }): Thenable<string>; } /** * @param importName 'name/subname' in example * @returns url or exportVarName * @example * const mod = await import('name/subname') */ interface Mod2UrlFn { (version: string, name: string, importName: string): Thenable<string>; } interface ModuleToUrlFc { (version: string, name: string, importName?: string, resolveName?: string): string; } type ExternalGlobals = Record<string, IArray<string | Mod2UrlFn>> | [string, IArray<string | Mod2UrlFn>][]; type ExternalResource = Record<string, string | Pkg2UrlFn | { resourceUrl: Pkg2UrlFn | string; /** * @default importName */ resourceName?: Pkg2UrlFn | string; loader?: (pkgOptions: PkgOptions) => unknown; nodeLoader?: string | ((pkgOptions: PkgOptions) => Thenable<string>); } | Array<string | ((version: string, name: string, importName: string, resolveName: string) => Thenable<string>)>>; interface MonkeyOption { /** * userscript entry file path */ entry: string; /** * userscript comment */ userscript?: MonkeyUserScript; /** * @deprecated use {@link align} or {@link generate} instead */ format?: { /** * @deprecated use {@link align} instead */ align?: unknown; /** * @deprecated use {@link generate} instead */ generate?: unknown; }; /** * align userscript comment * @default 2 */ align?: number | false; /** * custom generate userscript comment */ generate?: (options: { userscript: string; mode: `serve` | `build` | `meta`; }) => Thenable<string>; /** * alias of vite-plugin-monkey/dist/client * @default '$' * @example * // vite-env.d.ts for type hint * * // if you use default value `$` * /// <reference types="vite-plugin-monkey/client" /> * * // if you use other_alias * declare module other_alias { * export * from 'vite-plugin-monkey/dist/client'; * } */ clientAlias?: string; /** * handle CSS imports as style nodes([HTMLStyleElement](https://developer.mozilla.org/docs/Web/API/HTMLStyleElement)) * * If you use [Shadow DOM](https://developer.mozilla.org/docs/Web/API/Web_components/Using_shadow_DOM) (style isolation) to place your interface application, this is very useful. * * Support `.css?style`, `.less?style`, `.sass?style`, `.scss?style`, `.styl?style`, `.stylus?style`, `.pcss?style`, `.postcss?style` and `.sss?style` imports * * add `/// <reference types="vite-plugin-monkey/style" />` to vite-env.d.ts for type hint * * @example * import style1 from './style1.css?style': * import style2 from 'normalize.css?style'; * const container = document.createElement('div').attachShadow({ mode: 'open' }); * container.append(style1, style2); // with hmr when change style1.css * const style3 = style1.cloneNode(true); // it will still have hmr * * @default * true */ styleImport?: boolean; server?: { /** * auto open install url in default browser when userscript comment change * * and set `viteConfig.server.open ??= monkeyConfig.server.open` * @default * process.platform == 'win32' || process.platform == 'darwin' // if platform is Win/Mac */ 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 'server:' */ prefix?: string | ((name: string) => string) | false; /** * mount GM_api to unsafeWindow, not recommend it, you should use GM_api by ESM import, or use [unplugin-auto-import](https://github.com/antfu/unplugin-auto-import) * @default false * @example * // if set true, you can use `vite-plugin-monkey/global` for type hint * // vite-env.d.ts * /// <reference types="vite-plugin-monkey/global" /> */ 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 | ((fileName: string) => string); /** * this config can be array or object, array=Object.entries(object) * * if value is string or function, it or its return value is exportVarName * * if value is Array, the first [item or its return value] is exportVarName, the items after it all are url that is [require url] * * if module is unimported, plugin will not add require url to userscript * * @example * { // map structure * vue:'Vue', * // if set this * // you need manually set userscript.require = ['https://unpkg.com/vue@3.0.0/dist/vue.global.js'], when `vite build` * * vuex:['Vuex', (version, name)=>`https://unpkg.com/${name}@${version}/dist/vuex.global.js`], * // plugin will auto add this url to userscript.require * * 'prettier/parser-babel': [ * 'prettierPlugins.babel', * (version, name, importName) => { * // name == `prettier` * // importName == `prettier/parser-babel` * const subpath = `${importName.split('/').at(-1)}.js`; * return `https://cdn.jsdelivr.net/npm/${name}@${version}/${subpath}`; * }, * ], * // sometimes importName deffers from package name * } * @example * [ // array structure, this example come from [playground/ex-vue-demi](https://github.com/lisonge/vite-plugin-monkey/tree/main/playground/ex-vue-demi) * [ * 'vue', * cdn * .jsdelivr('Vue', 'dist/vue.global.prod.js') * .concat('https://unpkg.com/vue-demi@latest/lib/index.iife.js') * .concat(util.dataUrl('window.Vue=Vue')), * ], * ['pinia', cdn.jsdelivr('Pinia', 'dist/pinia.iife.prod.js')], * [ * 'element-plus', * cdn.jsdelivr('ElementPlus', 'dist/index.full.min.js'), * ], * ] */ externalGlobals?: ExternalGlobals; /** * according to final code bundle, auto inject GM_* or GM.* to userscript comment grant * * @default true */ autoGrant?: boolean; /** * @example * { // resourceName default value is pkg.importName * 'element-plus/dist/index.css': pkg=>`https://unpkg.com/${pkg.name}@${pkg.version}/${pkg.resolveName}`, * 'element-plus/dist/index.css': { * resourceName: pkg=>pkg.importName, * resourceUrl: pkg=>`https://unpkg.com/${pkg.name}@${pkg.version}/${pkg.resolveName}`, * loader: pkg=>{ // there are default loaders that support [css, json, the assets that vite support, ?url, ?raw] file/name suffix * const css = GM_getResourceText(pkg.resourceName); * GM_addStyle(css); * return css; * }, * nodeLoader: pkg=>{ * return [ * `export default (()=>{`, * `const css = GM_getResourceText(${JSON.stringify(pkg.resourceName)});`, * `GM_addStyle(css);`, * `return css;`, * `})();` * ].join(''); * }, * }, * 'element-plus/dist/index.css': [ * (version, name, importName, resolveName)=>importName, * (version, name, importName, resolveName)=>`https://unpkg.com/${name}@${version}/${resolveName}`, * // for compat externalGlobals cdn function, if (version/name/importName/resolveName) == '', plugin will use their own default values * ], * 'element-plus/dist/index.css': cdn.jsdelivr(), * } */ externalResource?: ExternalResource; /** * when use dynamic-import, plugin will use systemjs build your code * * `cdn.jsdelivr()[1]` example -> [dynamic-import.user.js](https://github.com/lisonge/vite-plugin-monkey/blob/7645b185605faf9b48c43116db5ea01726188e03/playground/dynamic-import/dist/dynamic-import.user.js) * * `'inline'` exmple -> [test-v3.user.js](https://github.com/lisonge/vite-plugin-monkey/blob/7645b185605faf9b48c43116db5ea01726188e03/playground/test-v3/dist/test-v3.user.js) * * @default * cdn.jsdelivr()[1] */ systemjs?: 'inline' | ModuleToUrlFc; /** * @default * const importCss = (css: string): void => { * if (typeof GM_addStyle === 'function') { * GM_addStyle(css); * } else { * document.head.appendChild(document.createElement('style')).append(css) * } * }; * @example * // example1 * importCss.toString() * * // example2 * `(a)=>GM_addStyle(a)` */ cssSideEffects?: string | ((css: string) => void); }; } /** * string -> javascript data url * @example * dataUrl('console.log("hello world")') * // => data:application/javascript,console.log(%22hello%20world%22) */ declare function dataUrl(code: string): string; /** * function and it parameters -> iife -> mini_iife -> javascript data url * * @example * dataUrl((a)=>{console.log(a)}, 'world') * // => data:application/javascript,((z)%3D%3E%7Bconsole.log(a)%7D)('world') */ declare function dataUrl<T extends (...args: any[]) => any>(fn: T, ...args: Parameters<T>): Promise<string>; /** * `https://cdn.jsdelivr.net/npm/${name}@${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName * @param pathname jsdelivr support file combine, normally you don't need set pathname * @see https://www.jsdelivr.com/features */ declare const jsdelivr: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://fastly.jsdelivr.net/npm/${name}@${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName * @param pathname jsdelivr support file combine, normally you don't need set pathname * @see https://www.jsdelivr.com/features */ declare const jsdelivrFastly: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://unpkg.com/${name}@${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName * @see https://unpkg.com/ */ declare const unpkg: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://fastly.jsdelivr.net/npm/${name}@${version}/${pathname}` * @deprecated bootcdn will return virus-infected code. Please stop using it and switch to other sources */ declare const bootcdn: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://fastly.jsdelivr.net/npm/${name}@${version}/${pathname}` * @deprecated staticfile will return virus-infected code. Please stop using it and switch to other sources */ declare const staticfile: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://cdnjs.cloudflare.com/ajax/libs/${name}/${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName * @see https://cdnjs.com/libraries */ declare const cdnjs: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://unpkg.zhimg.com/${name}/${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName * @link https://unpkg.zhimg.com/ */ declare const zhimg: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://npm.elemecdn.com/${name}@${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName */ declare const elemecdn: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://code.bdstatic.com/npm/${name}@${version}/${pathname}` * @param exportVarName cdn-exportVarName or resourceName */ declare const bdstatic: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; /** * `https://registry.npmmirror.com/${name}/${version}/files/${pathname}` * @param exportVarName cdn-exportVarName or resourceName */ declare const npmmirror: (exportVarName?: string, pathname?: string) => [string, ModuleToUrlFc]; declare const cdn_bdstatic: typeof bdstatic; declare const cdn_bootcdn: typeof bootcdn; declare const cdn_cdnjs: typeof cdnjs; declare const cdn_elemecdn: typeof elemecdn; declare const cdn_jsdelivr: typeof jsdelivr; declare const cdn_jsdelivrFastly: typeof jsdelivrFastly; declare const cdn_npmmirror: typeof npmmirror; declare const cdn_staticfile: typeof staticfile; declare const cdn_unpkg: typeof unpkg; declare const cdn_zhimg: typeof zhimg; declare namespace cdn { export { cdn_bdstatic as bdstatic, cdn_bootcdn as bootcdn, cdn_cdnjs as cdnjs, cdn_elemecdn as elemecdn, cdn_jsdelivr as jsdelivr, cdn_jsdelivrFastly as jsdelivrFastly, cdn_npmmirror as npmmirror, cdn_staticfile as staticfile, cdn_unpkg as unpkg, cdn_zhimg as zhimg }; } declare const _default: (pluginOption: MonkeyOption) => Plugin[]; declare const util: { dataUrl: typeof dataUrl; unimportPreset: { from: string; imports: string[]; }; }; export { type ExternalGlobals, type ExternalResource, type GreasemonkeyUserScript, type MonkeyOption, type MonkeyUserScript, type TampermonkeyUserScript, type ViolentmonkeyUserScript, cdn, _default as default, util };