Build
This module provides the capability to compile and package plugins, with built-in bundlers such as "copy," "replace," and "bundling" for quickly configuring your plugin's build process.
It also offers a set of hooks for customizing the build process.
Information of Plugin
export default ({
: "Your Plugin Name",
: "Your Plugin ID",
: "Your Plugin Namespace",
});Built-in Builders
The built-in builders run sequentially in the following order.
Make Directory
This step creates a new build storage folder.
Configured via the dist option:
export default ({
: ".scaffold/build",
});If the target folder already exists, it will be cleared before creating the new one.
The file structure of dist
addoncontains the plugin code after the build process but before packaging.*.xpirepresents the packaged plugin files.update*.jsonare update manifest.
.
|-- .scaffold
| |-- build
| | |-- addon
| | | |-- bootstrap.js
| | | |-- content
| | | |-- locale
| | | |-- manifest.json
| | | `-- prefs.js
| | |-- linter-for-zotero.xpi
| | |-- update-beta.json
| | `-- update.json
| `-- cache
`-- zotero-plugin.config.tsCopy Assets
This step copies static assets from the source directory to the build directory.
Configure the assets to be copied using build.assets:
export default ({
: {
: ["addon"],
},
});This is a glob list that supports negation patterns using !. For more details, refer to tinyglobby.
Define
This feature allows you to replace global identifiers with constant expressions.
Configurable via the build.define option:
export default ({
: {
: {
: "placeholderValue",
},
},
});WARNING
Replacement occurs immediately after copying assets and applies only to all assets in config.dist under the current state.
For non-asset files such as README.md, use the Scaffold utility replaceInFile (see: Utilities).
For JavaScript constant replacement, use esbuild.define (see: Script Bundling).
During replacement, the placeholder placeholder is converted into the regular expression /__placeholder__/g for replacement (instead of /placeholder/g).
This option provides built-in placeholders such as version and buildTime. See Context.templateData for details.
Manifest Generation
Automatically updates fields in manifest.json, including version, id, update_url, and more.
This feature is enabled by default and can be disabled by setting makeManifest to false.
The version is sourced from package.json, while other values can be configured in the configuration file:
export default ({
: "Your Plugin Name",
: "Your Plugin ID",
: "Your update.json Path",
: {
: {
: true,
},
},
});When manifest.json already exists in dist/addon, the values will always be deeply merged with the existing content, with priority given to the existing entries.
Locale File Handling
Handles localization files to prevent conflicts.
Configured via build.fluent.
Add Prefix to FTL File Names
export default ({
: "Your Plugin Namespace",
: {
: {
: true,
},
},
});Add Prefix to FTL Messages
Processes Fluent .ftl files by adding a namespace prefix and ensuring HTML references (data-l10n-id) align with Fluent messages.
export default ({
: "Your Plugin Namespace",
: {
: {
: true,
},
},
});Generate Type Definitions for FTL Messages
In development.
Preference Management
- Supports prefixing preference keys in
prefs.js. - Generates TypeScript declaration files (
.d.ts) for preferences.
Configure via build.prefs:
export default ({
: {
: {
: true,
: "extensions.myPlugin",
: "typings/prefs.d.ts"
}
}
});Adding Prefixes
When build.prefs.prefixPrefKeys is enabled, preferences should be written as follows:
pref("lintOnAdded", true);<vbox>
<groupbox>
<checkbox preference="lintOnAdded" data-l10n-id="linter-lint-on-item-added" native="true" />
</groupbox>
</vbox>pref("extensions.myPlugin.lintOnAdded", true);<vbox>
<groupbox>
<checkbox preference="extensions.myPlugin.lintOnAdded" data-l10n-id="linter-lint-on-item-added" native="true" />
</groupbox>
</vbox>Generating DTS Files
Relies on the zotero-types package to provide type declarations for Zotero.Prefs.
You can also use the following helper to get or set preferences while omitting the prefix, simplifying your code.
const PREF_PREFIX = "extensions.myPlugin";
type PluginPrefsMap = _ZoteroTypes.Prefs["PluginPrefsMap"];
export function getPref<K extends keyof PluginPrefsMap>(key: K) {
return Zotero.Prefs.get(`${PREF_PREFIX}.${key}`, true) as PluginPrefsMap[K];
}
export function setPref<K extends keyof PluginPrefsMap>(key: K, value: PluginPrefsMap[K]) {
return Zotero.Prefs.set(`${PREF_PREFIX}.${key}`, value, true);
}Script Bundling
Uses esbuild to compile and bundle your JavaScript/TypeScript code.
Configure it using build.esbuild:
export default ({
: {
: [],
},
});Since esbuild only compiles and bundles code without type checking, you need to run tsc manually for type checking.
Plugin Packing
Creates a .xpi archive for the plugin using AdmZip.
export default ({
: "Your Plugin Built XPI Name",
});This step executes only in the production environment.
Update Manifest
Generates update.json and update-beta.json with versioning and compatibility information for Zotero plugin updates.
Configured via build.makeUpdateJson:
export default ({
: {
: {
: [
{
: "0.9.9",
: "https://example.com/plugin-for-older-zotero.xpi",
: {
: {
: "5.9.9",
: "6.9.9",
},
},
},
],
: true,
},
},
});This step executes only in the production environment.
When the version number includes a - (pre-release), only update-beta.json is generated. Otherwise, both update.json and update-beta.json are generated. After installing a pre-release version, users will automatically update to the next pre-release version until the official release. Installing the next pre-release version still requires manual installation.
For different plugin versions targeting different Zotero versions, specify the Zotero version and corresponding plugin version in build.makeUpdateJson.updates. Refer to: Zotero 7 for developers.
Hooks
Documentation in progress.
Utils
Scaffold exports utilities and third-party dependencies for use. Import them from zotero-plugin-scaffold/vendor.
replaceInFile
import { replaceInFile } from "zotero-plugin-scaffold/vendor";
replaceInFile({
files: ["README.md", "**/README.md"],
from: [/from/g],
to: ["to"],
});fs-extra
Node.js: Extra methods for the
fsobject likecopy(),remove(),mkdirs().
Refer to the fs-extra documentation.
import { fse } from "zotero-plugin-scaffold/vendor";
fse.copy("a.txt", "b.txt");es-toolkit
es-toolkit: State-of-the-art JavaScript utility library
Refer to the es-toolkit documentation.
import { esToolkit } from "zotero-plugin-scaffold/vendor";
esToolkit.isNotNil(null);