背景
上图是我们的web项目在android平台的一个首屏渲染的时间平均值分布图,html加载600ms(蓝线),js资源加载400ms(橙线),公共逻辑和页面执行800ms(绿线),页面资源加载执行预估200ms。面对上面的问题,要优化,逃不过下面两种方案
1.优化资源加载时间
2.cdn,缓存,离线包,资源按需打包
3.优化逻辑执行时间
4.减少代码复杂度,提前执行公共逻辑
在资源方面权衡各种维护便利性,以及加载性能后,我们项目做了离线包,预加载等一些手段后,首页的打开速度可以控制在700-1000ms左右,在我们想进一步像200ms内打开页面迈进的时候,我们想到预加载页面以及公共库,预执行公共逻辑。最终效果如下
效果
1.一个是微前端方式打开(除了页面过渡,以及数据loading之外,页面基本150ms就打开)
2.一个是不使用微前端方式(明显能加载过程中的白屏,以及进度条,在页面缓存过后打开时间也差不多在1.2s左右)
技术方案
初步想法,让App提供一个webview预加载执行一个web项目,该web项目有运行一个有前端项目的所有依赖库。然后该项目分析访问的url,分析需要加载的业务页面逻辑js,然后加载js并创建渲染页面。 由于已经提前执行了公共逻辑。后续的业务页面加载执行其实非常快。
按这个想法我们需要进行web端项目和native项目进行改造
web端改造
上面是改造之前3个前端项目打包后的产物,包含html入口文件,公共的资源库,以及每个页面的js逻辑代码。如果一个公司里面按照公司的标准规范统一创建的项目,那么大多项目引入的公共资源库在每个项目里面都是一样的。 既然每个项目依赖的公共资源都一样,那我们是否可以想个办法把公共的东西当作一个项目,这个项目根据url的信息,动态加载对应url页面的js来运行,最终渲染页面,按这个想法我们调整了一下架构如下图。
可以看到我们把公共的依赖资源抽离成一个单独的项目,暂且叫做 微前端框架 。通过 static.ymm56.com/microweb 可以进行访问 。社区项目的某个页面可以通过如下链接进行访问 static.ymm56.com/microweb/#/…
可以看到我们把具体项目的路由信息放到hash后面(你完全可以定义自己的规则不使用hash)。 微前端框架通过获取hash值,分析出是social项目的D页面。然后通过动态加载D页面的逻辑js。执行并创建页面,最终渲染。
经过上面的调整,我们统一了所有前端项目的公共库,集中到了一个项目里面进行维护。这一步统一后我们就好去提前加载微前端框架项目并执行这些公共逻辑了。要知道基础框架初始化这个过程占了项目的90%
时间,这个时间节省下来了,那200ms
打开就不是问题了。
接下来需要app启动后预先加载一个webview。这个webview会直接加载微前端框架项目,当app被告知要打开一个h5页面。判断端该h5页面是否支持微前端,支持的话,就给预加载的这个微前端框架发一个消息告诉他加载这个页面,并让这个预加载的webview显示。
整个流程用户感知到的时间只有加载页面的js,直接执行。体验上是非常快的。
有想法了。接下来就是找客户端兄弟配合做细节完善了。走找客户端兄弟去。
客户端改造
1.如何区分一个链接是微前端的,还是非微前端的(可以自行通过url域名等信息定好规则) 非微前端的项目还是走老的流程直接打开页面,微前端的项目则是给预加载好的webview发消息,并显示出来。
2.如何判断一个微前端框架已经加载好了,因为微前端项目最终需要接受容器的消息去加载一个页面的js,如果发消息之前微前端的容器还没加载好,那么收到这个消息也是没用的,所以一定需要微前端基础框架加载好后通知客户端,容器已经准备好了。
3.如果加载一个微前端页面的时候,容器还没初始化好。那就直接打开该页面。不用走微前端的形式打开
4.可以自行做队列控制最大初始化微前端容器的数量,来提供微前端的命中率。
app启动就初始化一个微前端容器,容器的html加载完,并且js逻辑执行完后会告诉客户端该微前端容器可用了。这个时候如果app接收到打开一个微前端页面,那么客户端会进过一系列逻辑判断后,给微前端容器发送打开的url信息,并把该微前端容器显示出来。
该微前端框架项目收到客户端的url后,解析url里面的hash,判断是打开什么项目的什么页面,然后在配置里面去加载该页面的js,加载完后执行,并渲染页面,当一个微前端容器使用后又接着初始化一个微前端容器,方便下次使用。
核心问题思考
项目打包改造
微前端框架核心
微前端框架改造目标:
1.加载基础库,并适当暴露一些api到全局,方便业务调用
2.通过路由信息,加载业务js,执行并渲染页面
重点说一下路由信息加载业务js的逻辑。当访问一个微前端链接 static.ymm56.com/microweb/#/… 该路径会被处理成如下信息:
1.microweb 是微前端框架项目.
2.shop 是业务项目名称.
3.home是项目的页面.
microweb框架会根据shop项目加载shop项目下面的 micro.json 配置信息(micro.json内容参考下面的打包页面里的截图), 然后找到home页面对应的js。对应的js如下格式
我们可以通过简单的动态创建script的方式获取js并执行。这个时候在window对象上就有该页面的对象了。
提供一个基于vue项目加载js,并执行创建vue页面的例子。详细参考注释
loadPage () {// todo 判断路径是否符合规则let data = parseUrl()let key = data.pathlet startTime = new Date() - 0// 获取项目的配置, 就是micro.json 信息let config = await window.App.getConfig(data.project)if (!config) {console.log(`%c 页面加载失败`, 'color: red;font-size: 12px;')if (!data.project) {this.currPage = 'empty'return}this.currPage = pagePrex + '404'return}if (config.techType != 'vue') {return}console.log('使用vue路由处理页面', key)try {// Vue未注册过该组件才执行。ps:如果不加if判断,keep-alive就会失效if (!Vue.component(data.name)) {// 动态创建script,执行后window全局会有该页面对象await loadJs(`${getProjectBaseUrl()}/${config.pages[key].js}`)window.App.setCurrentProject(config)console.log(`%c页面资源加载时间${new Date() - startTime}ms`, 'color: #43bb88;font-size: 12px;')let module = window[`${config.name}_${key}`].default// 有些页面存在项目整个生命周期相关信息try {await window.App.onLaunch()} catch (error) {console.log(error)}let APP = window[`${config.name}_${key}`].Appif (APP && !window.App.ProjectInfo[window.App._currentProject]) {// 调用app启动的生命周期方法try {APP.onLaunch && await APP.onLaunch()} catch (error) {console.log(error)}window.App.ProjectInfo[window.App._currentProject] = APP}// 动态创建页面对象,并注册到全局。然后通过动态组件进行显示var tempModule = Vue.extend(module)tempModule = tempModule.extend({mixins: [BasePage],name: data.name,data: function () {return {_startTime: startTime,_projectName: config.name,}}})Vue.component(data.name, tempModule)}this.currPage = data.namewindow.App.setCurrentProject(config)} catch (error) {console.log(`%c ${key} 页面配置信息加载失败`, 'color: red;font-size: 12px;')this.currPage = pagePrex + '404'}}
业务项目改造
1.业务项目能打包每个页面的js
,这是基本能力
2.要提供完整的开发体验
,由于业务项目不再依赖基础公共库,所以这些资源都没在业务项目里面,我们需要找到一种办法,让业务项目在开发过程中可以使用微前端框架项目来运行页面。
打包页面
以前的项目,都是按照标准的vue–cli工具,整体打包。 改为微前端后,项目的打方式需要调整。 每个项目只需要打包出来每个页面为入口的js。最终打包出来的内容如下。主要包括每个页面的js,以及一个项目的描述文件micro.json
// 一个生成 micro.json 配置信息的插件
function MicroCache(options) { }
MicroCache.prototype.apply = function (compiler) {let cache = {};compiler.plugin("emit", function (compilation, callback) {// 在生成文件中,创建一个头部字符串:var filelist = "";let data = {name: pkg.name,techType: pkg.techType,version: pkg.version,pages: {},};// 遍历所有编译过的资源文件,// 对于每个文件名称,都添加一行内容。for (var filename in compilation.assets) {if (/-[a-z0-9]{8}.js$/gi.test(filename)) {let key = filename.replace(/-[a-z0-9]{8}.js$/gi, "");data.pages[key] = {js: `${filename}`,};}}// 将这个列表作为一个新的文件资源,插入到 webpack 构建中:filelist = JSON.stringify(data);compilation.assets[pkg.name + "/micro.json"] = {source: function () {return filelist;},size: function () {return filelist.length;},};callback();});
};
1.独立打包文件配置参考:核心是打包成umd模块。每个模块的名称按路径定义好唯一的规则,确定唯一性。 ${pkg.name}_[name]
输出的大概就是 shop_home_index
.这样当对应的js加载完后。就可以通过 window[‘shop_home_index’] 获取到.
output: {path: path.resolve(__dirname, "./dist/" + pkg.name),publicPath: `${BasePublicPath}/`,library: `${pkg.name}_[name]`,libraryTarget: "umd",filename: "[name]-[hash:8].js",},
独立运行
微前端业务项目在开发过程中为了方便调试。所有的页面都可以独立运行。比如开发过程访问 http://localhost:8000/microweb/#/microdemo-react/home/index ,我们不会在localhost本地部署微前端框架项目,而是通过webpack的代理服务器。把 http://localhost:8000/microweb 代理到线上的微前端框架项目上,这样进行解耦。具体webpack配置参考如下:
devServer: {contentBase: path.join(__dirname, "dist"),filename: '[name]-[hash:8].js',compress: true,hot: true,// 这里的配置主要是代理访问微前端的基础项目,然后对热更新的文件进行特殊处理proxy: {'/microweb/*.hot-update.js': {target: 'http://localhost:' + PORT, // 接口的域名changeOrigin: true,pathRewrite: { '^/microweb': '' }},'/microweb/*.hot-update.json': {target: 'http://localhost:' + PORT, // 接口的域名changeOrigin: true,pathRewrite: { '^/microweb': '' }},// 将'localhost:8080/microweb/xxx'代理到'https://devstatic.ymm56.com/microweb/xxx''/microweb': {target: 'http://devstatic.ymm56.com', // 接口的域名// target: 'http://localhost:8080', // 接口的域名changeOrigin: true,followRedirects: true,}},port: PORT},
最后
整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。
有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享
原文地址:https://blog.csdn.net/weixin_53312997/article/details/127310500
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_21436.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!