This guide will walk you through creating a Duplicis plugin. 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 installed:
# 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 probably 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.
Any runtime dependencies your plugin uses must be marked as external!
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()],
/* ... */
})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 built 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.