传统模块化在利于开发的同时,存在诸多不便,例如:

  • 以后端多页面工程场景中应用的组件库更新时,须要编译并上线所有应用到的页面,进步了上线老本,存在局部页面漏发或回滚时漏发带来的危险;
  • 当应用CDN资源管理组件库时,CDN资源更新能够实现浏览器端更新,然而服务器端渲染场景node端加载资源并执行无奈保障与浏览器端渲染中加载的CDN资源版本统一,会带来渲染差别导致从新渲染问题;
  • 当采纳打包工具提取公共资源时,打包工具的chunk提取局限于以后构建批次,若一个工程单次只构建局部页面,无奈实现工程内所有的公共资源被全副提取,因为各批次构建的公共资源hash值不同,会导致客户端渲染时加载CDN资源的效率大打折扣。

致力于解决以上问题,咱们开发了web模块的概念,从架构的层面解决困扰业务的问题。

愿景

基于已知问题,咱们的关注点有:

  • 实现web模块独自编译上线,亦可独自回滚;
  • web模块上线后所有应用模块的工程页面立刻失效;
  • 反对服务端渲染的同构工程。

在理论业务场景中,咱们心愿通过web模块扩大解决多页面我的项目外部UI组件库、工具库(lodash,moment)、申请库(axios)等的跨页面资源共享,全量上线一次,后续更新共享资源只须要独自构建公布web模块扩大即可,公布后通过咱们提供的能力达到多页面实时更新共享资源的成果。

另外咱们心愿业务方应用时援用web模块扩大与援用其它资源语法统一,采纳原生的import或require,不引入非凡语法,防止减少业务线的学习老本。

实现思路

此计划基于智联大前端Ada架构之上,能够到 《揭秘智联招聘的大前端架构Ada》理解,下文会间接应用Ada进行形容。

Ada从开发到构建应用的是清单服务进行解析渲染的,构建工具打包会生成一份清单文件,此文件蕴含本次打包的url及打包资源等信息。

利用清单的约定,咱们实现了微前端落地计划Widget,本次设计一样是针对清单进行一些约定实现运行时的动静加载。

首先咱们约定了一种新的工件类型,叫做“web模块扩大”,开发时须要写到固定的文件夹内,才会被脚手架辨认并编译。

同失常的入口文件一样,写到规定文件夹内的文件会被编译成独自的bundle文件,不便援用这里抉择只打包成一个bundle的形式,即js与css最多各只有一个文件。

到这里咱们就拿到了web公共模块,并写入到清单文件当中,拿axios举例如图:

接下来就是我的项目中的axios提取,既然是公共的web资源,所以须要将 import 略微批改一下,即:

import axios from 'axios' // 原援用import axios from 'extensions/web-modules/axios' // 新援用

此时须要做的就是把 'extensions/web-modules/axios' 这个门路变成一个动静加载的代码,各打包工具都提供了 Externals,利用这一个性能够自定义排除构建资源的加载形式。

拿webpack举例,简略实现如下:

{  externals: [    ({ request }, callback) => {      // ...      if (!matched) return callback() // 未match到web模块扩大门路间接返回      const url = path.posix.join(projectKey, WEB_MODULES_SCOPE, matched.name) // 实在URL门路      const name = target === 'node'        ? `ada.webModules.require('${url}')` // 由Ada server外部实现此办法        : url      return callback(null, name, scope)    }  ]}

将动态门路援用变成动静获取,浏览器端应用window全局变量的形式,node端应用自实现require的形式。

如图,编译后的web模块URL,别离对应清单内的web与node属性内的资源,下一步只须要将资源挂载到服务当中就实现闭环了。

浏览器端咱们实现了template的模版占位符,咱们将web相干的资源挂载到以后申请上下文的ctx当中,应用时:

async function GET (ctx) {  const html = `    ...    <script src="${ctx.template.placeholders.webModules.axios.js}"></script>    ...  `  ctx.response.set(html, 200)}

服务端有公布模块提供监听器,当监听到web模块扩大上线时,会拉取最新的清单并将资源文件更新至本地缓存中,这样下次申请拿到的 ctx.template.placeholders.webModules.axios.js 就是替换后的最新资源。

同理,ada.webModules.require 办法是一个node端暴漏到全局的工具办法,外面对服务端的web扩大模块进行了资源加载代理,当资源更新的时候会革除require缓存,从新require最新的js bundle。

这里不深刻介绍公布注册及发现的机制,因为更偏差于服务端同步散发的内容,与本文中心想表白的设计思维无关。

到这里web模块扩大机制就实现了,达成了咱们设计之初的愿景。

总结

模块化和动态化带来开发便当的同时,也减少了上线带来的影响和危险,毕竟上线会影响所有应用的页面,对开发者的危险把控能力也有肯定的门槛。

智联大前端团队公布web模块扩大已有一年多的工夫,外部反应比拟侧面,阐明绝对比激进大家更违心节约工夫老本和尝试新能力。