This guide will walk you through creating a Duplicis plugin from scratch. If you’d prefer a head start, grab a plugin template instead.
Duplicis plugins are NPM packages. While you could create plugins completely by hand; This guide will assume you have a few things instaled:
# 1. create project
mkdir -p my-plugin/src
touch my-plugin/src/index.js
cd my-plugin
# 2. initialize package
npm init -y
git init # optional
# 3. install dependencies
npm i -D @duplicis/types @duplicis/config Your project should now look like this:
my-plugin/
├── src/
│ └── index.js
└── package.json You’ll also want to set up typing for IntelliSense and pick a build system.
Plugins must be browser compatible ES modules. @duplicis/config provides ready-made configs for the most common build tools.
import { defineConfig } from '@duplicis/config/rollup'
export default defineConfig({
input: './src/index.js',
output: {
file: './dist/index.js',
format: 'es',
},
/* ... */
})import duplicis from '@duplicis/config/vite'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
lib: {
entry: './src/index.js',
format: ['es'],
},
},
plugins: [duplicis()],
/* ... */
})Any runtime dependencies your plugin uses must be marked as external!
Plugins can depend on other plugins and patches, which are loaded and ordered automatically by Duplicis.
Install dependencies via npm and then exclude them from your build output:
{
"name": "my-plugin",
"version": "0.0.0",
+ "dependencies": {
+ "duplicis-plugin-xyz": "~0.0.0"
+ },
...
} export default {
+ external: ['duplicis-plugin-xyz'],
...
} Skipping external causes Uncaught SyntaxError: redeclaration of ... at runtime since the dependency ends up bundled twice.
import PluginXyz, { AppMixin } from 'duplicis-plugin-xyz'
import { Plugin } from '@duplicis/core'
export class MyPlugin extends Plugin {
async onLoad() {
// calling a method on another plugin
PluginXyz.instance.xyz()
// calling a method added by a patch
MyAppMixin.instance.method()
}
}
// extending an existing patch from another plugin
export const MyAppMixin = MyPlugin.patch('app', AppMixin, (AppMixin) => {
return class MyAppMixin extends AppMixin {
override method(...args: any[]) {
console.log('I run before!', args)
const result = super.method(...args)
console.log('I run after!', result)
return result
}
}
}) If you’re not using TypeScript, use a jsconfig.json instead.
Duplicis uses two tsconfig environments to keep browser and Node.js types separate:
tsconfig.app.json — runtime code (client & browser-compatible)tsconfig.node.json — build tooling (NodeJS, vite, tests, etc.)// tsconfig.app.json
{
"extends": ["@duplicis/config/tsconfig.app.json"],
"include": ["./src/**/*"]
}
// tsconfig.node.json
{
"extends": ["@duplicis/config/tsconfig.node.json"],
"include": "./vite*.ts"
} Finally, import the Duplicis client types in a declaration file so they’re globally available:
echo "import '@duplicis/types/client'" >> src/client.d.ts duplicis-plugin-* prefix.