【第2029期】PluginAnything:插件化改造工具

  • 最新
  • 精选
  • 区块链
  • 汽车
  • 创意科技
  • 媒体达人
  • 电影音乐
  • 娱乐休闲
  • 生活旅行
  • 学习工具
  • 历史读书
  • 金融理财
  • 美食菜谱

【第2029期】Plugin Anything:插件化改造工具

前端早读课 前端早读课 2020-08-10

前言

今日早读文章由微店@刘远洋投稿分享。

正文从这开始~~

前端团队在实现工程化的 Cli 套件、Node Server 等系统时,为了满足功能的开放性,通常有三种方式:配置化、插件化、配置与插件的结合。

三者均有各自的优劣势:

配置化

优势:顾名思义,用户在使用的时候,通过工具暴露出的配置文件进行各类快捷配置,实现对工具的影响。

劣势:而工具的核心功能,内置于工具模块内部,其逻辑外部无法干预。

插件化

优势:工具内部只维护一系列生命周期及任务调度,所有业务功能以插件的形式对接,用户可以在尽可能大的自由度下,订制自己需要的功能。

劣势:上手成本不会像配置文件那样开箱即用,需要用户理解插件开发规范。

配置与插件的结合

这种是现在主流的方式 Webpack、Babel 等工具均采用该方式,插件化将这类工具的生态极大完善。

Webpack 的插件化思路

Webpack 维护了一个生命周期,主要做两件事情:1. 核心代码运行;2. 暴露生命周期中的各个钩子。

用户引入插件的方式:

  1. webpackConfig: {

  2. plugins: [

  3. new PluginA(),

  4. new PluginB(),

  5. // ...

  6. ]

  7. }

开发插件的方式:

  1. class PluginA {

  2. constructor() {


  3. }

  4. apply(compiler) {

  5. compiler.hooks.someHook.tap(...);

  6. }

  7. }

在插件开发时,开发者拦截了 someHook 钩子,对 Webpack 在该时刻的生命周期进行干预。

上述代码中,出现了 compiler.hooks.someHook,背后的原因,是 Webpack 将暴露出的生命周期钩子(如 someHook 钩子)挂载到内部的 hooks 对象上,举例如下:

  1. hooks = {

  2. hookA: new WaterfallHook(),

  3. hookB: new BailHook(),

  4. }

WaterfallHook: 流水式事件集,注册的处理逻辑会串行执行 BailHook: 瀑布式事件级,注册的处理逻辑会并行执行 Webpack 的事件机制依赖 Tappable,其有众多类型的事件级,这里不赘述

总结而言:Webpack 内部执行核心逻辑的同时,暴露繁多的生命周期钩子,交给插件干预,实现灵活的功能。

Babel 的插件化思路

Babel 的插件化机制和 Webpack 的插件化又有一些不同。

Babel 本质上是 StringA -> AST -> AST change -> StringB 的转换器,其插件是为该核心功能服务的。

Babel 运行时,会先将 String 转为 AST,遍历 AST,并在遍历图中对 AST 节点进行改造,最终将 AST 转为新 String。

Babel 的插件机制主要影响的是上述中 “遍历 AST,并在遍历图中对 AST 节点进行改造” 过程。

开发 Babel 插件

开发 Babel 插件的方式,是提供 Vistor 对象,也就是针对各个 AST 节点的回调处理方法,拦截节点的遍历行为,并对节点进行改造。

  1. const Visitor = {

  2. ASTNode1() {

  3. // change node

  4. },

  5. ASTNode2() {

  6. // change node

  7. }

  8. }

使用 Babel 插件

这一点是值得借鉴的,Babel 接受众多的插件引入方式,如:

.babelrc.json / babel.config.json

  1. {

  2. "plugins": [

  3. "transform-runtime",

  4. "class-properties"

  5. ]

  6. }

babel.config.js

  1. module.exports = {

  2. plugins: [

  3. 'transform-runtime',

  4. 'class-properties'

  5. ]

  6. };

packge.json

  1. {

  2. "name": "my-package",

  3. "version": "1.0.0",

  4. "babel": {

  5. "presets": [ ... ],

  6. "plugins": [ ... ],

  7. }

  8. }

JS API

  1. const babel = require('babel-core');


  2. babel.transform(code, {

  3. plugins: [ ... ]

  4. });

最主要的,是它提供了 plugins 入口,读取这些入口,可以干预 Babel 的运行状态,满足众多的新功能需求。

总结而言,Babel 提供了众多的插件接入方式,涵盖了配置文件、命令行、JS API 等。

如何实现一个插件化工具

那么,如果我们要实现一个插件化的工具,如命令行、构建套件呢,怎么提供插件化机制,将该工具的功能尽可能开放呢?

工具本身
  • 工具在运行核心逻辑的过程中,暴露必要的生命周期钩子。

  • 工具内部需要维护一套事件处理逻辑,将插件拦截声明周期时提供的回调函数

插件开发者
  • 插件开发者可以拦截生命周期钩子,并为该钩子提供回调函数

  • 插件开发者可以自定义新钩子,为后续插件使用

插件使用者

插件使用者,也就是用户,需要尽可能简单的引入插件,并能够自由地开发插件。

我们可以借鉴 Babel 的插件引入方式,接收 plugins 选项,并提供多种多样的配置方式(配置文件 / JS API)。

反馈在代码上,就是三个主要步骤:

  • 初始化工具生命周期钩子

  • 执行用户提供的插件

  • 执行核心逻辑,并在某个时机执行某个生命周期钩子

以下是该工具的实现逻辑伪代码:

  1. class PluginedTool {

  2. constructor(options) {

  3. this.options = {

  4. plugins: options.plugins

  5. };


  6. // step1: init hooks


  7. this.hooks = {

  8. hookA: new WaterfallHook(),

  9. hookB: new WaterfallHook(),

  10. };


  11. // step2: run plugins


  12. for (let i = 0, len = this.options.plugins.length; i len; i++) {

  13. // find plugin function

  14. const pluginFunction = this.findPluginFunction(this.options.plugins[i]);


  15. // run plugin and supply context object

  16. pluginFunction({ ... });

  17. }


  18. // step3: run core code and flush hooks


  19. this.hooks.hookA.fire();

  20. // do something

  21. this.hooks.hookB.fire();

  22. }


  23. private options: {};

  24. }

这样,一个简单的插件化工具就实现了,我们可以在 step3 执行工具的核心逻辑时,尽可能地触发各类生命周期钩子,实现极致的灵活性。

这套机制可以应用在命令行、构建套件、Node Server 等各类形态上。

如何实现多个插件化工具

诚然,上文中提到,大部分的插件化工具的实现逻辑是类似的:

  • 初始化工具生命周期钩子

  • 执行用户提供的插件

  • 执行核心逻辑,并在某个时机执行某个生命周期钩子

而该工具需要维护:事件注册、消费机制、自己的生命周期等等。

很快,我们在用同样的逻辑将多个工具插件化时,发现上述通用逻辑是可以抽象出来的,不需要每个工具都重新实现一遍各个配套设施。

为此,一个插件化工厂被写了出来:plugin-anything。

用法如下:

  1. const { runPluginAnything } = require('plugin-anything');


  2. runPluginAnything(

  3. {

  4. // Array

  5. searchList: [

  6. // string: absolute folder path

  7. ],


  8. // Array >

  9. plugins: [

  10. // string: plugin name

  11. // FunctionContructor: Plugin Constructor

  12. // Array: [ string | FunctionContructor, options object ]

  13. ],

  14. },

  15. {

  16. // init something like: hooks, customs config

  17. async init({ hooks, Events, customs }) {

  18. hooks.done = new Events();

  19. customs.myConfig = {};

  20. },


  21. // run lifecycle

  22. async lifecycle({ hooks, Events, customs }) {

  23. // flush hooks

  24. await hooks.done.flush('waterfall');


  25. // do something

  26. // ...

  27. // console.log(customs.myConfig);

  28. }

  29. }

  30. );


开发者可以快速的创建一个插件化的工具,想想也是不错的。

plugin-anything项目Github:https://github.com/hoperyy/plugin-anything

关于本文 作者:@刘远洋 原文:https://juejin.im/post/6857401388864831495

为你推荐


【第2006期】开发 React 和 Rax 样式用这款 VS Code 插件就够了


【第1803期】如何在 Web 上构建一个插件系统


欢迎自荐投稿,前端早读课等你来

    阅读原文

    前往看一看

    看一看入口已关闭

    在“设置”-“通用”-“发现页管理”打开“看一看”入口

    我知道了

    已发送

    发送到看一看

    发送中

    微信扫一扫
    使用小程序

    取消 允许

    取消 允许

    微信版本过低

    当前微信版本不支持该功能,请升级至最新版本。

    我知道了 前往更新

    确定删除回复吗?

    取消 删除

      知道了

      长按识别前往小程序

      本站仅按申请收录文章,版权归原作者所有
      如若侵权,请联系本站删除

      微信QQ空间新浪微博腾讯微博人人Twitter豆瓣百度贴吧

      觉得不错,分享给更多人看到

      前端早读课 热门文章:

      【第806期】前端疲劳    阅读/点赞 : 7412/38

      【第821期】摩拜单车微信小程序开发技术总结    阅读/点赞 : 6945/39

      【第823期】理解Web路由    阅读/点赞 : 3967/38

      【第742期】新手向:Vue 2.0 的建议学习顺序    阅读/点赞 : 3472/34

      【活动、荐书】《HTML5与WebGL编程》    阅读/点赞 : 2867/171

      【同说】@小武:跨界的成长    阅读/点赞 : 2808/40

      【第770期】react+redux渲染性能优化原理    阅读/点赞 : 2523/46

      【第566期】关于前端的思考与感悟    阅读/点赞 : 2388/44

      2016,我做了什么?    阅读/点赞 : 2364/42

      专访|前端布道师@张克军    阅读/点赞 : 2178/43

      前端早读课 微信二维码

      前端早读课 微信二维码

      前端早读课 最新文章

      【第2029期】Plugin Anything:插件化改造工具  2020-08-10

      【招聘】北京猎聘多面中心招高级前端开发工程师  2020-08-10

      【第2028期】What I\'m thinking about: JS疲劳、招聘  2020-08-09

      【第2027期】图解CORS  2020-08-08

      【招聘】字节跳动广州EI团队招前端开发Leader以及高级前端工程师  2020-08-08

      【第2026期】「可视化搭建系统」——从设计到架构,探索前端领域技术和业务价值  2020-08-07

      【招聘】北京新浪微博招高级前端开发工程师(社招)  2020-08-07

      当HR跟你谈薪水时,如何回答能使收入最大化?  2020-08-06

      【第2025期】解读 Chrome 84 新特性,支持私有方法、用户空闲检测!  2020-08-06

      京东物流风格 NutUI 发布了  2020-08-06

      (adsbygoogle = window.adsbygoogle || []).push({});

      (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); (function(){ var src = (document.location.protocol == "http:") ? "http://js.passport.qihucdn.com/11.0.1.js?ba34c9f41d18b62312e960833b3cb4ae":"https://jspassport.ssl.qhimg.com/11.0.1.js?ba34c9f41d18b62312e960833b3cb4ae"; document.write(''); })();

       
      ®关于本站文章™ | 若非注明原创,默认 均为网友分享文章,如有侵权,请联系我们™
      ㊣ 本文永久链接: 【第2029期】PluginAnything:插件化改造工具