add: auto hot reload support

This commit is contained in:
windingwind 2023-06-12 23:24:42 +08:00
parent c4fc2c44e7
commit 3ba1f9d40e
7 changed files with 81 additions and 26 deletions

7
.vscode/launch.json vendored
View File

@ -4,6 +4,13 @@
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "StartDev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start-watch"]
},
{
"type": "node",
"request": "launch",

View File

@ -42,6 +42,7 @@ If you are using this repo, I recommended that you put this badge ([![Using Zote
- Event-driven, functional programming, under extensive skeleton;
- Simple and user-friendly, works out-of-the-box.
- ⭐[New!]Auto hot reload! Whenever the source code is modified, automatically compile and reload. [See here→](#auto-hot-reload)
- Abundant examples in `src/modules/examples.ts`, covering most of the commonly used APIs in plugins(using [zotero-plugin-toolkit](https://github.com/windingwind/zotero-plugin-toolkit));
- TypeScript support:
- Full type definition support for the whole Zotero project, which is written in JavaScript(using [zotero-types](https://github.com/windingwind/zotero-types));
@ -50,7 +51,7 @@ If you are using this repo, I recommended that you put this badge ([![Using Zote
- Automatically generate/update plugin id/version, update configrations, and set environment variables(`development/production`);
- Automatically build and reload code in Zotero;
- Automatically release to GitHub(using [release-it](https://github.com/release-it/release-it));
- ⭐[New!]Compatibilities for Zotero 6 & Zotero 7.(using [zotero-plugin-toolkit](https://github.com/windingwind/zotero-plugin-toolkit))
- Compatibilities for Zotero 6 & Zotero 7.(using [zotero-plugin-toolkit](https://github.com/windingwind/zotero-plugin-toolkit))
## Examples
@ -211,6 +212,29 @@ vim ./scripts/zotero-cmd.json
11. Click "Inspect Main Process"
### Auto Hot Reload
Tired of endless restarting? Forget about it!
1. Run `npm run start-watch`. (If Zotero is already running, use `npm run watch`)
2. Coding. (Yes, that's all)
When file changes are detected in `src` or `addon`, the plugin will do automatically compiled and reloaded.
<details style="text-indent: 2em">
<summary>💡 Steps to add this feature to an existing plugin</summary>
1. Add `if (reason == ADDON_DISABLE) {Services.obs.notifyObservers(null, "startupcache-invalidate", null);}` to `shutdown()` in the `addon/bootstrap.js`
2. Copy `scripts/reload.mjs`
3. Copy `reload`, `watch`, and `start-watch` commands in `package.json`
4. Run `npm install --save-dev chokidar-cli`
5. Done.
</details>
### Debug in Zotero
You can also:

3
addon/bootstrap.js vendored
View File

@ -106,6 +106,9 @@ function shutdown({ id, version, resourceURI, rootURI }, reason) {
if (reason === APP_SHUTDOWN) {
return;
}
if (reason == ADDON_DISABLE) {
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
}
if (typeof Zotero === "undefined") {
Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
Components.interfaces.nsISupports

View File

@ -17,13 +17,14 @@
"build-prod": "cross-env NODE_ENV=production node scripts/build.mjs",
"build": "concurrently -c auto npm:build-prod npm:tsc",
"tsc": "tsc --noEmit",
"start-z6": "node scripts/start.mjs --z 6",
"start-z7": "node scripts/start.mjs --z 7",
"start": "node scripts/start.mjs",
"start-watch": "concurrently -c auto npm:start npm:watch",
"stop": "node scripts/stop.mjs",
"restart-dev": "npm run build-dev && npm run stop && npm run start",
"restart-prod": "npm run build-prod && npm run stop && npm run start",
"restart": "npm run restart-dev",
"reload": "npm run build-dev && node scripts/reload.mjs",
"watch": "chokidar \"src/*.*\" \"addon/*.*\" -c \"npm run reload\"",
"release": "release-it",
"lint": "prettier --write . && eslint . --ext .ts --fix",
"test": "echo \"Error: no test specified\" && exit 1",
@ -46,6 +47,7 @@
"@types/node": "^20.1.1",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.2",
"chokidar-cli": "^3.0.0",
"compressing": "^1.9.0",
"concurrently": "^8.0.1",
"cross-env": "^7.0.3",

42
scripts/reload.mjs Normal file
View File

@ -0,0 +1,42 @@
import { exit, argv } from "process";
import minimist from "minimist";
import { execSync } from "child_process";
import details from "../package.json" assert { type: "json" };
const { addonID, addonName } = details.config;
const version = details.version;
import cmd from "./zotero-cmd.json" assert { type: "json" };
const { exec } = cmd;
// Run node reload.js -h for help
const args = minimist(argv.slice(2));
const zoteroPath = exec[args.zotero || args.z || Object.keys(exec)[0]];
const profile = args.profile || args.p;
const startZotero = `${zoteroPath} --debugger --purgecaches ${
profile ? `-p ${profile}` : ""
}`;
const script = `
(async () => {
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
const addon = await AddonManager.getAddonByID("${addonID}");
addon.disable();
await Zotero.Promise.delay(1000);
addon.enable();
const progressWindow = new Zotero.ProgressWindow({ closeOnClick: true });
progressWindow.changeHeadline("${addonName} Hot Reload");
progressWindow.progress = new progressWindow.ItemProgress(
"chrome://zotero/skin/tick.png",
"VERSION=${version}, BUILD=${new Date().toLocaleString()}. By zotero-plugin-toolkit"
);
progressWindow.progress.setProgress(100);
progressWindow.show();
progressWindow.startCloseTimer(5000);
})()`;
const url = `zotero://ztoolkit-debug/?run=${encodeURIComponent(script)}`;
const command = `${startZotero} -url "${url}"`;
execSync(command);
exit(0);

View File

@ -3,33 +3,11 @@ import { execSync } from "child_process";
import cmd from "./zotero-cmd.json" assert { type: "json" };
const { killZoteroWindows, killZoteroUnix } = cmd;
const MAX_WAIT_TIME = 10000;
const startTime = new Date().getTime();
try {
if (process.platform === "win32") {
execSync(killZoteroWindows);
// wait until zotero.exe is fully stopped. maximum wait for 10 seconds
while (new Date().getTime() - startTime <= MAX_WAIT_TIME) {
try {
execSync('tasklist | find /i "zotero.exe"');
} catch (e) {
break;
}
}
} else {
execSync(killZoteroUnix);
// wait until zotero is fully stopped. maximum wait for 10 seconds
while (new Date().getTime() - startTime <= MAX_WAIT_TIME) {
try {
execSync("ps aux | grep -i zotero");
} catch (e) {
break;
}
}
}
} catch (e) {
console.error(e);

View File

@ -3,7 +3,6 @@
"killZoteroWindows": "taskkill /f /im zotero.exe",
"killZoteroUnix": "kill -9 $(ps -x | grep zotero)",
"exec": {
"6": "/path/to/zotero6.exe",
"7": "/path/to/zotero7.exe"
}
}