传统模块化在利于开发的同时,存在诸多不便,例如:
- 以后端多页面工程场景中应用的组件库更新时,须要编译并上线所有应用到的页面,进步了上线老本,存在局部页面漏发或回滚时漏发带来的危险;
- 当应用 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 模块扩大已有一年多的工夫,外部反应比拟侧面,阐明绝对比激进大家更违心节约工夫老本和尝试新能力。