关于前端插件化的探索

1,779 阅读2分钟

关于前端插件化

什么是前端插件化

插件化是将软件应用的功能模块化,使各个单位模块都可以独立开发、部署和更新。通过将不同功能封装成插件,开发者可以灵活地添加或移除功能,而不影响主应用的整体结构。这种方式不仅提高了代码的可维护性和复用性,还使团队能够并行开发不同的功能模块。

Snipaste_2024-10-16_15-08-49.png 从上图中可以看出,主要由两部分组成:Core + plugin,也就是一个内核和多个插件。通常来说:

  • 内核主要负责一些基础功能、核心功能以及插件的管理;
  • 插件则是一个独立的功能模块,用来丰富和加强内核的能力。

常见的前端插件架构

常见的前端插件架构包括:

  1. Webpack:作为模块打包器,支持通过插件扩展功能,如代码压缩和热重载等。
  2. Vue插件:Vue.js支持通过插件系统来扩展功能,允许开发者添加全局方法、混入和自定义指令等。
  3. React HOCs(高阶组件) :通过函数式编程来实现组件的复用与功能扩展等。
  4. jQuery:通过扩展 jQuery 的原型,使开发者能够创建可重用的功能模块。
  5. 。。。。。

Demo

项目地址

项目截图 Snipaste_2024-10-16_15-43-18.png

  • 技术栈:electron + React + vite

Snipaste_2024-10-16_15-29-07.png 首先,先在 /public 文件夹下声明10个js插件(当然有条件的话可以放私服),这里图方便,每个插件都输出类似的对象。这里采用esmodule规范编写插件代码,最后导出定义好的方法变量。

// App.tsx
useEffect(() => {
    // 安装已下载插件
    const plugins = getDownloadPlugins();
    if (plugins && plugins.length) {
      plugins.forEach((e) => {
        importPlugin(e);
      });
    }
  }, []);

然后在入口处,项目初始化的时候,将缓存在electron缓存中的已下载目录依次导入

// /utils/index.tsx
/**
 * 导入插件至全局
 * @params id 插件id
 */
export const importPlugin = (id) => {
  const script = document.createElement("script");
  script.src = `pluginList/p${id}.js`;
  script.type = "module";
  document.body.appendChild(script);
  import(/* @vite-ignore */ `../../pluginList/p${id}.js`).then((res) => {
    window.$plugins[`P${id}`] = res.default;
  });
  notification.open({
    message: `插件${id}运行成功`,
    description: `插件${id}运行成功`,
    icon: <SmileOutlined style={{ color: "#108ee9" }} />,
  });
};

通过动态创建script标签,将模块插件注入到项目中,并且挂载到全局对象window.$plugins对象上 <script> 标签加上 type="module" 后,该脚本会变成异步加载的,不会阻塞浏览器的渲染,然后等到整个页面渲染完,再执行模块脚本,等同于打开了 <script> 标签的defer属性。如果网页有多个<script type="module">,它们会按照在页面出现的顺序依次执行

详细可见 JavaScript modules

插件安装后的效果: Snipaste_2024-10-16_15-42-58.png

安装完就可以直接使用插件里面暴露出来的内容:

Snipaste_2024-10-16_15-49-59.png

当然,对于其他没有安装的话,直接调用肯定会报错,为此这里借助Vue3响应式原理用到的Proxy特性进行拦截:

// App.tsx
window.$plugins = new Proxy(
  {},
  {
    get(target, key) {
      if (!Reflect.has(target, key)) {
        message.warning("请先至插件市场下载插件~~~");
        return false;
      }
      return Reflect.get(target, key);
    },
  }
);

Snipaste_2024-10-16_15-51-54.png

最后,灵活插拔作为插件化的一个亮点,为此这里还设计插件市场和插件管理两个页面,方便进行可插拔操作。

未完成清单

  • 借助webpack工作流程的思路,后续可以加入发布监听模式,扩展功能。
  • 目前仅支持js文件,后续可以研究一下其他类型语言接入的可行性。
  • 。。。。。。

欢迎各位道友指导!!!🤝