From 3d1cf9ded3927aad63c004790ca872766c68e7c2 Mon Sep 17 00:00:00 2001 From: xiangyu <3170102889@zju.edu.cn> Date: Sat, 31 Dec 2022 12:27:01 +0800 Subject: [PATCH] add: build environment (dev/prod) change: locale filename --- README.md | 13 ++-- ...ontemplate.properties => addon.properties} | 0 ...ontemplate.properties => addon.properties} | 0 build.js | 18 ++++- package.json | 8 ++- src/addon.ts | 21 ++++-- src/events.ts | 67 +++++++++++-------- src/locale.ts | 25 ++++--- src/prefs.ts | 4 +- 9 files changed, 99 insertions(+), 57 deletions(-) rename addon/chrome/locale/en-US/{addontemplate.properties => addon.properties} (100%) rename addon/chrome/locale/zh-CN/{addontemplate.properties => addon.properties} (100%) diff --git a/README.md b/README.md index 71a6329..3f0fa0b 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ This is an addon/plugin template for [Zotero](https://www.zotero.org/). - TypeScript support; - Build addon settings and versions automatically; - Build and reload code in Zotero automatically; +- Development/production build environment; - Release to GitHub automatically(using [release-it](https://github.com/release-it/release-it)); - Extensive skeleton; - Some sample code of UI and lifecycle. @@ -42,9 +43,13 @@ This is an addon/plugin template for [Zotero](https://www.zotero.org/). > Be careful to set the addonID and addonRef to avoid confliction. - Run `npm install` to set up the plugin and install dependencies. If you don't have NodeJS installed, please download it [here](https://nodejs.org/en/); -- Run `npm run build` to build the plugin. The xpi for installation and the built code is under builds folder. +- Run `npm run build` to build the plugin in production mode. Run `npm run build-dev` to build the plugin in development mode. The xpi for installation and the built code is under builds folder. -### Plugin Life Cycle +> What the difference between dev & prod? +> - This environment variable is stored in `Zotero.AddonTemplate.env`. The outputs to console is disabled in prod mode. +> - You can decide what users cannot see/use based on this variable. + +### About Life Cycle 1. When install/enable/startup triggered from Zotero, `bootstrap.js` > `startup` is called - Wait for Zotero ready @@ -182,11 +187,11 @@ This section shows the directory structure of a template. │ └─locale # locale │ ├─en-US │ │ overlay.dtd -│ │ addontemplate.properties +│ │ addon.properties │ │ │ └─zh-CN │ | overlay.dtd -│ │ addontemplate.properties +│ │ addon.properties │ ├─builds # build dir │ └─.xpi diff --git a/addon/chrome/locale/en-US/addontemplate.properties b/addon/chrome/locale/en-US/addon.properties similarity index 100% rename from addon/chrome/locale/en-US/addontemplate.properties rename to addon/chrome/locale/en-US/addon.properties diff --git a/addon/chrome/locale/zh-CN/addontemplate.properties b/addon/chrome/locale/zh-CN/addon.properties similarity index 100% rename from addon/chrome/locale/zh-CN/addontemplate.properties rename to addon/chrome/locale/zh-CN/addon.properties diff --git a/build.js b/build.js index d840aeb..e5fe633 100644 --- a/build.js +++ b/build.js @@ -85,7 +85,9 @@ async function main() { const buildDir = "builds"; console.log( - `[Build] BUILD_DIR=${buildDir}, VERSION=${version}, BUILD_TIME=${buildTime}` + `[Build] BUILD_DIR=${buildDir}, VERSION=${version}, BUILD_TIME=${buildTime}, ENV=${[ + process.env.NODE_ENV, + ]}` ); clearFolder(buildDir); @@ -98,6 +100,9 @@ async function main() { await esbuild .build({ entryPoints: ["src/index.ts"], + define: { + __env__: process.env.NODE_ENV, + }, bundle: true, // Entry should be the same as addon/chrome/content/overlay.xul outfile: path.join(buildDir, "addon/chrome/content/scripts/index.js"), @@ -156,6 +161,17 @@ async function main() { ) ); + // _ = replace.sync({ + // files: [path.join(buildDir, "addon/chrome/content/scripts/index.js")], + // from: [/__env__/g] + // }); + // console.log( + // "[Build] Run replace in ", + // _.filter((f) => f.hasChanged).map( + // (f) => `${f.file} : ${f.numReplacements} / ${f.numMatches}` + // ) + // ); + console.log("[Build] Replace OK"); console.log("[Build] Addon prepare OK"); diff --git a/package.json b/package.json index d907594..efd4c69 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,11 @@ }, "main": "src/index.ts", "scripts": { - "build": "node build.js", + "build-dev": "cross-env NODE_ENV=development node build.js", + "build": "cross-env NODE_ENV=production node build.js", "start": "node start.js", "stop": "node stop.js", - "prerestart": "npm run build", + "prerestart": "npm run build-dev", "restart": "node restart.js", "release": "release-it", "test": "echo \"Error: no test specified\" && exit 1" @@ -30,11 +31,12 @@ }, "homepage": "https://github.com/windingwind/zotero-addon-template#readme", "dependencies": { - "zotero-plugin-toolkit": "^0.0.9" + "zotero-plugin-toolkit": "^0.0.10" }, "devDependencies": { "@types/node": "^18.11.17", "compressing": "^1.6.3", + "cross-env": "^7.0.3", "esbuild": "^0.16.10", "release-it": "^14.14.3", "replace-in-file": "^6.3.5", diff --git a/src/addon.ts b/src/addon.ts index 92980b1..23ece8b 100644 --- a/src/addon.ts +++ b/src/addon.ts @@ -4,17 +4,24 @@ import AddonViews from "./views"; import AddonLocale from "./locale"; import ZoteroToolkit from "zotero-plugin-toolkit"; -import Locale from "./locale"; class Addon { + // A global Zotero instance public Zotero!: _ZoteroConstructable; - public events: AddonEvents; - public views: AddonViews; - public prefs: AddonPrefs; - public locale: AddonLocale; - public toolkit: ZoteroToolkit; - // root path to access the resources + // Root path to access the resources public rootURI!: string; + // Env type, see build.js + public env!: "development" | "production"; + // Lifecycle events + public events: AddonEvents; + // UI operations + public views: AddonViews; + // Scripts for prefpane window + public prefs: AddonPrefs; + // Runtime locale with .properties + public locale: AddonLocale; + // A toolkit instance. See zotero-plugin-toolkit + public toolkit: ZoteroToolkit; constructor() { this.events = new AddonEvents(this); diff --git a/src/events.ts b/src/events.ts index 12bf68f..ff5345b 100644 --- a/src/events.ts +++ b/src/events.ts @@ -3,10 +3,46 @@ import AddonModule from "./module"; import { config } from "../package.json"; class AddonEvents extends AddonModule { - private notifierCallback: any; constructor(parent: Addon) { super(parent); - this.notifierCallback = { + } + + // This function is the setup code of the addon + public async onInit() { + this._Addon.Zotero = Zotero; + // @ts-ignore + this._Addon.rootURI = rootURI; + const development = "development"; + const production = "production"; + // The env will be replaced after esbuild + // @ts-ignore + this._Addon.env = __env__; + this._Addon.toolkit.Tool.logOptionsGlobal.prefix = `[${config.addonName}]`; + this._Addon.toolkit.Tool.logOptionsGlobal.disableConsole = + this._Addon.env === "production"; + this._Addon.toolkit.Tool.log("init called"); + + // Initialize locale provider + this._Addon.locale.initLocale(); + // Initialize preference window + this.initPrefs(); + // Initialize notifier callback + this.initNotifier(); + // Initialize UI elements + this._Addon.views.initViews(); + } + + public onUnInit(): void { + this._Addon.toolkit.Tool.log("uninit called"); + this.unInitPrefs(); + // Remove elements and do clean up + this._Addon.views.unInitViews(); + // Remove addon object + Zotero.AddonTemplate = undefined; + } + + private initNotifier() { + const callback = { notify: async ( event: string, type: string, @@ -26,17 +62,9 @@ class AddonEvents extends AddonModule { } }, }; - } - - public async onInit() { - this._Addon.Zotero = Zotero; - // @ts-ignore - this._Addon.rootURI = rootURI; - // This function is the setup code of the addon - this._Addon.toolkit.Tool.log(`${config.addonName}: init called`); // Register the callback in Zotero as an item observer - let notifierID = Zotero.Notifier.registerObserver(this.notifierCallback, [ + let notifierID = Zotero.Notifier.registerObserver(callback, [ "tab", "item", "file", @@ -50,14 +78,9 @@ class AddonEvents extends AddonModule { }, false ); - - // Initialize preference window - this.initPrefs(); - this._Addon.views.initViews(); } - public initPrefs() { - this._Addon.toolkit.Tool.log(this._Addon.rootURI); + private initPrefs() { const prefOptions = { pluginID: config.addonID, src: this._Addon.rootURI + "chrome/content/preferences.xhtml", @@ -81,16 +104,6 @@ class AddonEvents extends AddonModule { this._Addon.toolkit.Compat.unregisterPrefPane(); } } - - public onUnInit(): void { - const Zotero = this._Addon.Zotero; - this._Addon.toolkit.Tool.log(`${config.addonName}: uninit called`); - this.unInitPrefs(); - // Remove elements and do clean up - this._Addon.views.unInitViews(); - // Remove addon object - Zotero.AddonTemplate = undefined; - } } export default AddonEvents; diff --git a/src/locale.ts b/src/locale.ts index 9166476..e21bb2e 100644 --- a/src/locale.ts +++ b/src/locale.ts @@ -1,19 +1,18 @@ -import Addon from "./addon"; import AddonModule from "./module"; - +import { config } from "../package.json"; class AddonLocale extends AddonModule { - private stringBundle: any; - constructor(parent: Addon) { - super(parent); - this.stringBundle = Components.classes['@mozilla.org/intl/stringbundle;1'] - .getService(Components.interfaces.nsIStringBundleService) - .createBundle('chrome://addontemplate/locale/addontemplate.properties'); - } + private stringBundle: any; - public getString(localString: string): string { - return this.stringBundle.GetStringFromName(localString); - } + public initLocale() { + this.stringBundle = Components.classes["@mozilla.org/intl/stringbundle;1"] + .getService(Components.interfaces.nsIStringBundleService) + .createBundle(`chrome://${config.addonRef}/locale/addon.properties`); + } + + public getString(localString: string): string { + return this.stringBundle.GetStringFromName(localString); + } } -export default AddonLocale; \ No newline at end of file +export default AddonLocale; diff --git a/src/prefs.ts b/src/prefs.ts index 577ad2e..b8be02e 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -11,7 +11,7 @@ class AddonPrefs extends AddonModule { // This function is called when the prefs window is opened // See addon/chrome/content/preferences.xul onpaneload this._window = _window; - this._Addon.toolkit.Tool.log(`${config.addonName}: init preferences`); + this._Addon.toolkit.Tool.log("init preferences"); this.updatePrefsUI(); this.bindPrefEvents(); } @@ -20,7 +20,7 @@ class AddonPrefs extends AddonModule { // You can initialize some UI elements on prefs window // with this._window.document // Or bind some events to the elements - this._Addon.toolkit.Tool.log(`${config.addonName}: init preferences UI`); + this._Addon.toolkit.Tool.log("init preferences UI"); } private bindPrefEvents() {