Plugin system built through various hooks, inspired by tapable. it is very small, but it has fully-fledged and powerful TypeScript type hinting/type checking. If your project has a microkernel architecture, then this library will be very suitable for you.
SyncHook
SyncWaterfallHook
AsyncHook
AsyncWaterfallHook
AsyncParallelHook
plSys.use
plSys.useRefine
plSys.remove
plSys.create
plSys.isUsed
plSys.beforeEach
plSys.afterEach
plSys.lock
plSys.unlock
plSys.listenLock
plSys.listenError
plSys.getPluginApis
plSys.pickLifyCycle
plSys.clone
plSys.debug
plSys.performance
plSys.removeAllDebug
plSys.removeAllPerformance
import { SyncHook, PluginSystem } from "hooks-plugin";
// Create a plugin and declare hooks
const plSys = new PluginSystem({
a: new SyncHook<[string, number]>(),
});
// Register plugin
plSys.use({
name: "testPlugin",
hooks: {
a(a, b) {
console.log(a, b); // 'str', 1
},
},
});
// Register via function
plSys.use(function(plSys) {
return {
name: "testPlugin",
...
}
})
// If you want to simplify registering plugins
const plugin = plSys.useRefine({
a(a, b) {
console.log(a, b); // 'str', 1
},
})
console.log(plugin.name); // Plugin name is a uuid created automatically
// Trigger hook
plSys.lifecycle.a.emit("str", 1);
import { AsyncHook, PluginSystem } from "hooks-plugin";
const plSys = new PluginSystem({
// 1. The first generic is the parameter type received by the hook
// 2. The second generic is the `this`` type of the hook function
a: new AsyncHook<[number, number], string>("context"),
// The parameter type of `AsyncWaterfallHook` and `SyncWaterfallHook` must be an object
b: new AsyncWaterfallHook<{ value: number }, string>("context"),
});
plSys.use({
name: "testPlugin",
version: "1.0.0", // Optional
hooks: {
async a(a, b) {
console.log(this); // 'context'
console.log(a, b); // 1, 2
},
async b(data) {
console.log(this); // 'context'
console.log(data); // { value: 1 }
return data; // Must return values of the same type
},
},
// The order is after `hooks` and will only be called once
onceHooks: {
async a(a, b) {
console.log(this); // 'context'
console.log(a, b); // 1, 2
},
}
});
plSys.lifecycle.a.emit(1, 2);
plSys.lifecycle.b.emit({ value: 1 });
import { SyncHook, PluginSystem } from "hooks-plugin";
// Declare your plugin `api` type
declare module "hooks-plugin" {
export interface PluginApis {
testApis: (typeof plugin)["apis"];
}
}
const plSys = new PluginSystem({});
const plugin = plSys.use({
name: "testApis",
apis: {
get(key: string) {},
set(key: string, value: unknown) {},
},
});
const apis = plSys.getPluginApis("testApis");
apis.get("a");
apis.set("a", 1);
import { SyncHook, PluginSystem } from "hooks-plugin";
const plSys = new PluginSystem({
a: new SyncHook(),
});
plSys.use({
name: "test",
hooks: {
a(data) {},
},
});
// Registers a (sync) callback to be called before each hook is being called.
// `id`` is an arbitrary value, used to maintain consistency with `afterEach`
const unsubscribeBefore = plSys.beforeEach((e) => {
console.log("id:", e.id);
console.log("name:", e.name);
console.log("type:", e.type);
console.log("args:", e.args);
console.log("context:", e.context);
});
// Registers a (sync) callback to be called after each hook is being called.
const unsubscribeAfter = plSys.afterEach((e) => {
console.log("id:", e.id);
console.log("name:", e.name);
console.log("type:", e.type);
console.log("args:", e.args);
console.log("context:", e.context);
console.log("pluginExecTime:", e.pluginExecTime);
});
plSys.lifecycle.a.emit(1);
unsubscribeBefore();
unsubscribeAfter();
// Listening will no longer be triggered
plSys.lifecycle.a.emit(2);
import { SyncHook, PluginSystem } from "hooks-plugin";
const plSys = new PluginSystem({
a: new AsyncParallelHook("ctx"),
});
plSys.use({
name: "test",
hooks: {
a() {
return new Promise((resolve) => {
setTimeout(resolve, 300);
});
},
},
});
const close = plSys.debug({ tag: "tag" });
plSys.lifecycle.a.emit(1, 2); // [tag]: a_1(t, args, ctx, pt): 309.36ms [1, 2] 'ctx' { test: 308.51ms }
// Close debug mode
close();
// You can also pass a `receiver` to handle log data yourself.
const close = plSys.debug({
tag: "tag",
receiver(data) {
console.log(data); // { e, tag, time }
},
// filter(data) { ... },
});
plSys.lifecycle.a.emit(1, 2);
import { SyncHook, PluginSystem } from "hooks-plugin";
const plSys = new PluginSystem({
a: new SyncHook(),
b: new AsyncHook(),
});
// Take the `name` prop from the `0` parameter for matching
const p = plSys.performance("[0].name");
p.monitor("a", "a").on((e) => console.log(e.time)); // 200.400
p.monitor("a", "b").on((e) => console.log(e.time)); // 0.199
plSys.lifecycle.a.emit({ name: "n" });
setTimeout(() => {
plSys.lifecycle.a.emit({ name: "n" });
plSys.lifecycle.b.emit({ name: "n" });
}, 200);
<!DOCTYPE html>
<html lang='en'>
<body>
<script src='https://unpkg.com/hooks-plugin/dist/hooks.umd.js'></script>
<script>
const {
PluginSystem,
SyncHook,
AsyncHook,
SyncWaterfallHook,
AsyncParallelHook,
AsyncWaterfallHook,
} = window.HooksPlugin;
// ...
</script>
</body>
</html>