Foreword
Recently doing the design and development of a framework in Taiwan, after doing the basic capabilities of the main frame of thinking in the framework of the implementation of the real business needs of the process, the need for the main frame has a lot of features customized content exists. If you do even a little change in the main business framework, may be behind the scalability and flexibility are restricted.
To make the body frame made more flexible, scalable and more engaged, after the main frame with the basic skills, will no longer do business with any non-functional development ability of the main frame of the main frame.
To continue the main framework of "slotting"
In fact, many libraries have similar front-end design, to be able to allow more developers to get involved, to complete a variety of community-driven development. For Webpack
example: Babel
, Hexo
, , VuePress
and so on.
So how is your project slotting, plug it do?
Survey
In the understanding of many projects source code plug-in, I found that most achieve similar, divided into the following steps:
- As a framework to develop the ability to install plug-ins, plug-in container
- Exposure to major life cycle node running method (slotted)
- Write plugin code injection Business
These frameworks are to achieve their own set of such plug-in tools, and almost strong correlation in business, not detached. Or tools to do a rewrite methods. Overall relatively discrete, that is not directly used to use.
Also in the implementation, most of the plug-in implementation is a direct overwrite method, a Wrap for him to pay more at run-time, in order to run an external plug-in logic code.
// main.js
const main = {
loadData:()=>{},
render:()=>{}
}
// plugin1.js
const plugin1 = {
render:()=>{}
}
// install.js
const install = (main, plugin) => {
main.render = ()=>{
plugin1.render()
main.render()
}
}
复制代码
Plug in the above code has several obvious question:
plugin1
You can not controlrender()
the order ofmain
Unable to determine what function may be overridden plug, plug what function will not be overwritten- If you follow the module file splitting, team members do not know
main.js
the function changes will be at risk, because they are fundamentally not seeinstall.js
the code
Then later, in order to solve these problems, it may become like this:
const component = {
hooks:{
componentWillMounted(){},
componentDidMounted(){}
},
mounte(){
this.hooks.componentWillMounted();
//... main code
this.hooks.componentDidMounted();
}
}
const plugin = {
componentWillMounted(){
//...
},
componentDidMounted(){
//...
}
}
// install.js
const install = (main, plugin) => {
// 忽略实现细节。
main.hooks.componentWillMounted = ()=>{
plugin1.componentWillMounted()
main.hook.componentWillMounted()
}
main.hooks.componentDidMounted = ()=>{
plugin1.componentDidMounted()
main.hook.componentDidMounted()
}
}
复制代码
In addition, there is a solution, to give plug-in next
method, as follows:
// main.js
const main = {
loadData:()=>{},
render:()=>{}
}
// plugin1.js
const plugin1 = {
render:next=>{
// run some thing before
next();
// run some thing after
}
}
// install.js
const install = (main, plugin) => {
main.render = ()=>{
plugin1.render(main.render)
}
}
复制代码
As above, the structure of the investigation, although the corresponding functions are implemented, but the implementation point of view, there are several obvious problems:
- The original function too intrusive modification
- Excessive method rewrite operation, too hack
- Unfriendly to TypeScript
- Multi-member collaboration unfriendly
- The original function operation not flexible enough to modify the original function of a reference to the Senate
Open out
After a lot of research in the implementation of the framework, I hope that my own plug-in libraries can use a decorator to complete grooving, completed by injecting a decorator in the plug-in class, you can use and develop like this:
import { Hook, Inject, PluginTarget, Plugin } from 'plugin-decorator';
class DemoTarget extends PluginTarget {
@Hook
public method1() {
console.log('origin method');
}
}
class DemoPlugin extends Plugin {
@Inject
public method1(next) {
next();
console.log('plugin method');
}
}
const demoTarget = new DemoTarget();
demoTarget.install(new DemoPlugin());
demoTarget.method1();
// => origin method
// => plugin method
复制代码
Decorator
And may support changes to the reference decoration into a reference original function, as follows:
import { Hook, Inject, PluginTarget, Plugin } from 'plugin-decorator';
class DemoTarget extends PluginTarget {
@Hook
public method1(name:string) {
return `origin method ${name}`;
}
}
class DemoPlugin extends Plugin {
@Inject
public method1(next, name) {
return `plugin ${next(name)}`;
}
}
const demoTarget = new DemoTarget();
demoTarget.install(new DemoPlugin());
console.log(demoTarget.method1('cool'));
// => plugin origin method cool
复制代码
Promise
Of course, if the original function is a Promise, and that the plug should also support the Promise! as follows:
import { Hook, Inject, PluginTarget, Plugin } from 'plugin-decorator';
class DemoTarget extends PluginTarget {
@Hook
public methodPromise() {
return new Promise(resolve => {
setTimeout(() => resolve('origin method'), 1000);
});
}
}
class DemoPlugin extends Plugin {
@Inject
public async methodPromise(next) {
return `plugin ${await next()}`;
}
}
const demoTarget = new DemoTarget();
demoTarget.install(new DemoPlugin());
demoTarget.methodPromise().then(console.log);
// => Promise<plugin origin method>
复制代码
Duang!
Eventually, I completed the development of this library:plugin-decorator
GitHub: Address
Yes, I knew you would point Star, after all, you are so handsome, tall, mighty, cool, big brother!
to sum up
In this project, also worth mentioning is that the project is temporarily out of me in developing its own framework to set the stage of a tool library.
Using the tools in the library:
- TypeScript
- Ava Unit Test
- Nyc
- Typedoc
Overall development process is to write test cases, and then developed in accordance with the test, which is the legendary TDD (Test Drive Development).
Feel this way, at least in my library pulled out of the process of doing, great, overall development process is very efficient, clear purpose.
Was compiled library built in typescript-starter this library saves me a lot of time to build the project!
The original post address: yeee.wang/posts/dfa4....
Personal blog: yeee.wang
Reproduced in: https: //juejin.im/post/5d0096e5f265da1bb003b729