Electron 应用旁载插件框架,提供类似 Tampermonkey 的体验。
通过 asar-patch 技术将插件系统注入到已发布的 Electron 应用中,支持多插件管理、URL 匹配、GM_* API、CSS/JS 注入,且不破坏原始应用文件(可一键还原)。
- 零破坏部署 — 原始 asar 完整保存为
*-em-backup.asar,随时可还原 - 多插件架构 — 每个插件独立目录,含
manifest.json描述;同时支持 Tampermonkey.user.js单文件脚本 - URL 匹配 — 支持 Chrome 扩展 match pattern 语法(
*://*.example.com/*) - GM_* API —
GM_getValue、GM_setValue、GM_addStyle、GM_notification、GM_xmlhttpRequest等 - 运行时机控制 —
document-start、document-end、document-idle - 主进程插件 — 支持
main入口,可访问 Electron 主进程 API - 自动降级 — BrowserWindow 补丁失败时自动切换到
web-contents-created注入 - 双模式架构 — 开发模式(需 Node.js)与发布模式(免安装,运行 PowerShell 脚本即可)
无需 Node.js,无需命令行。
- 从 Releases 下载最新的
electromonkey-x.x.x.zip - 解压到任意位置
- 右键
install.ps1→ 选择「使用 PowerShell 运行」,按提示输入目标 asar 文件路径(如app.asar) - 正常启动目标应用即可
也可在 PowerShell 中直接运行:
.\install.ps1 "C:\Users\你的用户名\AppData\Local\SomeApp\1.0.0\resources\app.asar"卸载:右键 uninstall.ps1 → 选择「使用 PowerShell 运行」,应用恢复为原始状态。
插件目录:安装后插件存放在
%LOCALAPPDATA%\ElectroMonkey\plugins\,将.user.js脚本或插件文件夹放入即可生效。
git clone https://github.com/abevol/electromonkey.git
cd electromonkey
npm install复制 .env.example 为 .env,设置目标 Electron 应用的 asar 文件路径:
cp .env.example .env编辑 .env 文件:
TARGET_APP=../target-app/resources/app.asarnpm run deploy # 部署插件框架(开发模式)
npm run undeploy # 还原原始应用也可以通过 --target 参数指定目标:
node scripts/deploy.js --target /path/to/electron-app/resources/app.asar路径解析优先级:
--target参数 >.env中的TARGET_APP
部署后直接启动目标应用即可,无需特殊启动器。控制面板标题会显示 DEV 标签以区分开发模式。
开发模式下,除了 git 仓库内的 plugins/ 目录,还会扫描以下目录:
%LOCALAPPDATA%\ElectroMonkeyDev\plugins\
此目录不受 Git 管控,适合放置开发测试用的插件。
npm run build # 构建到 dist/electromonkey/生成的 dist/electromonkey/ 包含 install.ps1、uninstall.ps1、预构建的 bootstrap.asar 及所有运行时文件,可直接打包为 zip 发布。
ElectroMonkey 支持两种插件格式:
plugins/
├── my-plugin/ # 格式一:目录插件(manifest.json)
│ ├── manifest.json
│ ├── renderer.js
│ └── style.css
└── my-script.user.js # 格式二:Tampermonkey .user.js 单文件脚本
{
"name": "我的插件",
"version": "1.0.0",
"description": "插件描述",
"author": "作者",
"match": ["*://*.example.com/*"],
"exclude": [],
"runAt": "document-idle",
"renderer": "renderer.js",
"css": "style.css",
"main": null,
"grant": ["GM_addStyle", "GM_setValue", "GM_getValue"],
"enabled": true
}| 字段 | 说明 |
|---|---|
match |
URL 匹配规则,支持 * 通配符(Chrome 扩展语法) |
exclude |
URL 排除规则 |
runAt |
运行时机:document-start | document-end | document-idle |
renderer |
渲染器脚本文件名 |
css |
样式文件名 |
main |
主进程脚本(可选,需导出 activate(context) 函数) |
grant |
声明使用的 GM_* API |
enabled |
是否启用 |
| API | 说明 |
|---|---|
GM_info |
插件和框架元信息 |
GM_getValue(key, default) |
读取持久化存储 |
GM_setValue(key, value) |
写入持久化存储 |
GM_deleteValue(key) |
删除存储项 |
GM_listValues() |
列出所有存储键名 |
GM_addStyle(css) |
注入 CSS 样式 |
GM_log(...args) |
带插件名前缀的控制台日志 |
GM_notification(details) |
桌面通知 |
GM_setClipboard(text) |
写入剪贴板 |
GM_xmlhttpRequest(details) |
网络请求(基于 fetch) |
// ==ElectroMonkey==
// @name 我的插件
// @version 1.0.0
// @match *://*.example.com/*
// ==/ElectroMonkey==
GM_log('插件已加载', location.href);
GM_addStyle('body { border: 2px solid red; }');
var count = GM_getValue('visitCount', 0) + 1;
GM_setValue('visitCount', count);
GM_log('第', count, '次访问');直接将 .user.js 文件放入 plugins/ 目录即可,无需 manifest.json。元数据从 ==UserScript== 头部自动解析:
// ==UserScript==
// @name 我的脚本
// @version 1.0.0
// @description 脚本描述
// @author 作者
// @match *://*.*.com/*
// @run-at document-idle
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
GM_addStyle('body { border: 2px solid blue; }');
console.log('Hello from userscript!');支持的 @ 标签:
| 标签 | 说明 |
|---|---|
@name |
脚本名称 |
@version |
版本号 |
@description |
描述 |
@author |
作者 |
@match |
URL 匹配规则(可多次声明) |
@include |
URL 匹配规则(@match 的兼容别名) |
@exclude / @exclude-match |
URL 排除规则 |
@run-at |
运行时机:document-start | document-end | document-idle |
@grant |
声明使用的 GM_* API(none 表示不需要) |
@namespace |
命名空间(保留字段) |
@noframes |
不在 iframe 中运行(保留字段) |
兼容性说明:从 Tampermonkey / Greasemonkey 导出的
.user.js脚本可直接放入plugins/目录使用,只要脚本使用的 GM_* API 在上方「可用 GM_* API」列表中即可。
目标应用启动
→ 加载 app.asar(极简引导,~1KB)
→ index.js:
1. 扫描同级目录,找到 *-em-backup.asar(原始应用备份)
2. 从备份 asar 读取 package.json,恢复 app.name 和 version
3. 设置 ELECTROMONKEY_MODE + ELECTROMONKEY_ROOT(release 模式)
4. require(loader.js) ← ElectroMonkey 注入
5. require(*-em-backup.asar) ← 原始应用正常启动
- loader.js 在主进程中执行,尝试 monkey-patch
BrowserWindow(替换 preload) - 如果 BrowserWindow 为 non-configurable(如 tt_electron),自动降级到
web-contents-created钩子 - 在
dom-ready事件中,通过executeJavaScript和insertCSS注入匹配当前 URL 的插件
| 开发模式 | 发布模式 | |
|---|---|---|
| 触发方式 | npm run deploy |
install.ps1 |
| 依赖 | Node.js + npm | 无 |
| 运行时位置 | git 仓库 src/patch/ |
%LOCALAPPDATA%\ElectroMonkey\runtime\ |
| 插件目录 | 仓库 plugins/ + %LOCALAPPDATA%\ElectroMonkeyDev\plugins\ |
%LOCALAPPDATA%\ElectroMonkey\plugins\ |
| 控制面板标识 | 显示 DEV 标签 | 无标签 |
electromonkey/
├── src/patch/
│ ├── loader.js # 主进程注入器(模式感知路径解析)
│ ├── plugin-manager.js # 插件管理(多目录发现、匹配、GM_* API 构建)
│ ├── preload-inject.js # 渲染器 preload 链式注入
│ └── package.json
├── scripts/
│ ├── deploy.js # 开发模式部署脚本
│ ├── undeploy.js # 开发模式卸载脚本
│ ├── build.js # 构建发布包
│ ├── install.ps1 # 发布模式安装脚本 (PowerShell)
│ └── uninstall.ps1 # 发布模式卸载脚本 (PowerShell)
├── assets/
│ └── icon.png # 应用图标
├── plugins/
│ ├── control-panel/ # ElectroMonkey 控制面板
│ │ ├── manifest.json
│ │ ├── renderer.js
│ │ └── style.css
│ └── *.user.js # 示例脚本
└── package.json
MIT