Provides plug-in capabilities to your JavaScript library

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 Webpackexample: Babel, Hexo, , VuePressand 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:

  1. As a framework to develop the ability to install plug-ins, plug-in container
  2. Exposure to major life cycle node running method (slotted)
  3. 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:

  • plugin1You can not control render()the order of
  • main 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.jsthe function changes will be at risk, because they are fundamentally not see install.jsthe 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 nextmethod, 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

Guess you like

Origin blog.csdn.net/weixin_33978044/article/details/93172591