mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 22:57:38 +00:00
117 lines
3.1 KiB
Markdown
117 lines
3.1 KiB
Markdown
---
|
|
order: 1
|
|
toc: menu
|
|
group:
|
|
title: Plugin Development
|
|
path: /guide/plugin-development
|
|
order: 5
|
|
---
|
|
|
|
# What is a Plugin?
|
|
|
|
Plugins are pluggable, standalone modules divided by function.
|
|
|
|
## Why Write Plugins?
|
|
|
|
NocoBase provides a rich API for application development and can be extended even without writing plugins. The reason for writing plugins is to reduce coupling and better reuse. To do a place to write, use anywhere. Of course, some business links are very close, there is no need to overly plug-in split.
|
|
|
|
## How to Write a Plugin?
|
|
|
|
For example, to add a ratelimit middleware, you can write it like this.
|
|
|
|
```ts
|
|
import ratelimit from 'koa-ratelimit';
|
|
|
|
app.use(ratelimit({
|
|
driver: 'memory',
|
|
db: new Map(),
|
|
duration: 60000,
|
|
errorMessage: 'Sometimes You Just Have to Slow Down.',
|
|
id: (ctx) => ctx.ip,
|
|
headers: {
|
|
remaining: 'Rate-Limit-Remaining',
|
|
reset: 'Rate-Limit-Reset',
|
|
total: 'Rate-Limit-Total'
|
|
},
|
|
max: 100,
|
|
disableHeader: false,
|
|
whitelist: (ctx) => {
|
|
// some logic that returns a boolean
|
|
},
|
|
blacklist: (ctx) => {
|
|
// some logic that returns a boolean
|
|
}
|
|
}));
|
|
```
|
|
|
|
But with this kind of writing, it can only be handled by development, not dynamically removed. For this reason, NocoBase provides a pluggable `app.plugin()` interface for adding and removing middleware. After the modification, the code is as follows.
|
|
|
|
```ts
|
|
import ratelimit from 'koa-ratelimit';
|
|
|
|
class RateLimitPlugin extends Plugin {
|
|
constructor(options) {
|
|
super(options);
|
|
this.ratelimit = ratelimit(options.options);
|
|
}
|
|
|
|
enable() {
|
|
this.app.use(this.ratelimit)
|
|
}
|
|
|
|
disable() {
|
|
this.app.unuse(this.ratelimit);
|
|
}
|
|
}
|
|
|
|
app.plugin(RateLimitPlugin, {
|
|
name: 'rate-limit',
|
|
version: '1.0.0',
|
|
options: {
|
|
driver: 'memory',
|
|
db: new Map(),
|
|
duration: 60000,
|
|
errorMessage: 'Sometimes You Just Have to Slow Down.',
|
|
id: (ctx) => ctx.ip,
|
|
headers: {
|
|
remaining: 'Rate-Limit-Remaining',
|
|
reset: 'Rate-Limit-Reset',
|
|
total: 'Rate-Limit-Total'
|
|
},
|
|
max: 100,
|
|
disableHeader: false,
|
|
whitelist: (ctx) => {
|
|
// some logic that returns a boolean
|
|
},
|
|
blacklist: (ctx) => {
|
|
// some logic that returns a boolean
|
|
}
|
|
}
|
|
});
|
|
```
|
|
|
|
- Distilling the parameters of ratelimit goes a step further by giving the parameter configuration to the plugin management panel
|
|
- When the plugin is active, execute plugin.enable() to add ratelimit to it
|
|
- When the plugin is disabled, execute plugin.disable() to remove ratelimit
|
|
|
|
The above is the core content of the plugin, any functional extension can be handled in this way. Just two steps.
|
|
|
|
- Implement the enable interface of the plugin for adding functionality.
|
|
- Then implement the disable interface for removing the function module.
|
|
|
|
```ts
|
|
class MyPlugin extends Plugin {
|
|
enable() {
|
|
// Logic for adding
|
|
}
|
|
|
|
disable() {
|
|
// Logic to remove
|
|
}
|
|
}
|
|
```
|
|
|
|
**Is it possible not to implement disable? **
|
|
|
|
The disable interface is designed to enable hot-plugging of plugins so that applications can activate and disable plugins without rebooting. If a plugin does not need to be disabled, you can also just implement the enable interface.
|