项目背景

业务的快速发展,越来越多的接入渠道(百度、快应用等等),人员增加,开发成本与管理成本都上升,效率反而越来越低,团队的人员重复造轮子,毫无挑战,当然市面上也有多端解决方案,但是不太适用目前的业务,所以前端聚合成“微前端”的概念。

单体应用与「微前端」架构

在传统的软件开发当中,大多数软件都是单体式应用架构的。为了适应我们这个时代的不确定性。快速试验,快速失败。更快地推出新产品和有效地改进当前产品,从而为客户提供有意义的数字体验。

而单体应用这种软件架构对于企业来说的致命缺点就是,对于市场的响应速度变慢。由于依赖关系,其响应周期往往会变得非常漫长。此时前端工程化越来越复杂,每次的整站编译耗时严重,根据用户漏斗原则,有一部分无效的消耗。

「微前端」的好处

  • 安全高效:服务分离,降低整体风险与测试等成本;

  • 灵活扩展:为每一个服务选择最合适的技术和基础架构;

  • 独立敏捷:每一个服务可以独立开发,测试和部署。

「微前端」的四种可选实践方案

使用后端模板引擎插入 HTML (方案A)

方案会增加后端复杂度,并且又将前端的渲染控制权交回了后端服务器。作为一个前端开发人员,一般不会选择该方案,但并不是完全没用,需要看使用场景,如果只是纯展示的,可以适当考虑。

客户端 JavaScript 异步加载 (方案B)

这种方式可以通过前端模块化方式在开发整个「微前端」方案(AMD,CMD等),对开发效率有一定影响。

WebComponents 整合所有功能模块 (方案C)

使用了较新的技术方案,在较老的浏览器上,可能兼容性欠缺。我们需要在整个 Web 应用程序上做出改变,把它们全部转换成 Web Components。

使用 iframe 隔离运行 (方案D)

优点

  • 最强大的是隔离了组件和应用程序部分的运行时环境,因为每个模块都可以独立开发,并且可以与其他部分的技术无关;

  • 因为每个模块都可以独立开发,我们可以使用我们最熟悉的框架开发「微前端」模块;

  • 可以各自使用完全不同的前端框架,可以在 React 中开发一部分,在 Vue 中开发一部分,然后使用原生 JavaScript 开发其他部分或任何其他技术;

  • 消息传递也就相当强大。(Window.postMessageAPI)。

缺点

  • Bundle的大小非常明显,因为应用程序是分开的,所以在构建时也不能提取公共依赖关系;

  • 考虑到浏览器性能问题,尽量避免iframe的多层调用;

  • 处理移动端中的iframe时,将变得相当痛苦。

「微前端」的技术选型

需要接入的「微前端」的应用

「微前端」开发要求

  • 准:快速找出当前应用的痛点,给出「微前端」解决方案;

  • 快:快速迭代开发上线;

  • 稳:保证线上代码兼容性以及稳定运行。

「微前端」的演变过程

前端单体应用痛点

  • 每个站点中,都有一个通用的模块《常旅》;

  • 这么多站点也不是一次性完成,每次需要开发新的站点,都通过Copy的方式,将《常旅》复制一份;

  • 当站点积累到一定程度时,突然《常旅》有个新的需求需要开发;

  • 此时,我们的开发量就成倍增加(1 x N),同时测试的工作量也一样。

单体应用到的「微前端」进化

「微前端」优劣

  • 前端单体应用中的常旅模块分离,增加通用的「微前端」服务模组;

  • 常旅模块独立为一个单独的「微前端」应用,为每个站点提供”常旅模块“服务;

  • 此时,如果需要做「常旅功能迭代」,工作量永远只需要一份就可以;

  • 我们需要保证「微前端」稳定运行,一旦奔溃,将影响所有引入的单体应用。

「微前端」架构方案

  • 主框架:vue + vue-router + vuex

  • 通讯方案:url入参 + postMessage + vue-unicom(内部广播机制)

  • 滚屏:iscroll

  • 布局方案:px2rem (750)布局

  • 承载方式:iframe + webview

  • 静态资源加载优化:asset-cache-webpack-plugin(h5离线缓存)

  • 宿主(iframe)优化方案 「微前端」预加载

「微前端」数据通讯方案

「微前端」数据通讯方案

「微前端」部分数据通讯代码

// routerimport router from '../../router'    // 获得一个唯一的值import getSole from 'rimjs/sole'// 全局unicom事件触发import { unicomEmit } from 'rimjs/vueUnicom'  // 当前环境的变量数据,这里主要是设置身份import { env } from '../env'let win = window// 默认为 iframe 需要兼容其他的,可以这里兼容function postMessage(data, source = window.parent) {source.postMessage(data, '*')}// 临时存放 Promise 的resolve的对象let postMessageResolveFns = {} // 信息输入数据let messageInData = null// 信息输出数据 暂存let messageOutData = {}let query = router.queryif (query._in != null) {      messageInData = {}}if (messageInData) {// 是否为类微信小程序内(webview和小程序无法实时双向通讯)// 传入的参数需要一次性输入try {Object.assign(messageInData, JSON.parse(query._in) || {})} catch (e) {}}// 用户同步用户身份信息的函数function setUser(inEnv) {if (!inEnv) {return}env.userId = inEnv.userId || ''}// 从宿主获取用户身份async function getUser() {let inEnv = await bridge.postMessage('env:get')setUser(inEnv)}// 接收消息// type:类型 fnKey:回调方法 insruct:指令 data:数据function onMessage({ type, insruct, data } = {}, source) {let backData = nullif (type == 'unicom') {        backData = data == null ? {} : data// 事件广播, 通过这个方法,宿主环境可以向「微前端」端发送广播消息unicomEmit(insruct, backData)return}if (type == 'system') {// 一些系统设置if (insruct == 'font') {// rem布局,根节点 字体大小// 「微前端」如果为预加载,无法正确计算出根节点字体大小,需要宿主通知document.documentElement.style.fontSize = datareturn}if (insruct == 'href') {setUser(data.env)// iframe 预加载,重新定位 当前路由if (data.replace) {window.location.replace(window.location.pathname + '#' + data.href)} else {window.location.href = window.location.pathname + '#' + data.href}return}if (insruct == 're_init') {// 重新初始化页面,一般在iframe中,返回宿主环境后使用window.location.replace(window.location.pathname + '#/init?re=1')return}return}if (type == 'back') {// 找到回调的Promiselet resolveFn = postMessageResolveFns[insruct]if (resolveFn) {// 运行 resolveFnresolveFn(data)// console.log("data", data)delete postMessageResolveFns[insruct]}return}if (fnKey) {// 数据回调postMessage({ type: 'back', from: 'microservice', insruct: fnKey, data: backData }, source)}}// 注册接收的消息// 如果需要兼容其他渠道,可以这里写不同的window.addEventListener('message', function (ev) {let opt = ev.data || {}let { from } = optif (from != 'microservice') {// 非目标,舍弃return}onMessage(opt, ev.source)})// 对象定义export let bridge = {// postMessage 发送消息// 可以通过 Promise 获取到宿主的回调函数的值// bridge.postMessage("xxx") 同 bridge.postMessage("unicom:xxx")// data 为发送的参数postMessage(opt, data) {if (typeof opt == 'string') {let x = opt.match(/^([^:]*):*(.*)$/)if (!x) {            x = [opt]}if (!x[2]) {// type 默认为 unicom            x[2] = x[1]            x[1] = 'unicom'}          opt = {            data,type: x[1],insruct: x[2]}}return new Promise(function (resolve) {// 回调唯一的keylet fnKey = 'ms:' + getSole()          postMessageResolveFns[fnKey] = resolveif (messageInData) {// 此处无法直接使用 postMessagelet key = opt.type + ':' + opt.insruct// 寄存需要发送出去的数据            messageOutData[key] = data// console.log(messageOutData, key, args)setTimeout(function () {// 模拟接收到 back 事件onMessage({type: 'back',insruct: fnKey,data: messageInData[key] || null})}, 0)return}// 发送下次postMessage(Object.assign({ from: 'microservice', fnKey }, opt))})},// 结束「微前端」endBack(opt, data) {if (opt) {// 如果在「微前端」中有对身份信息做一些修改,需要同步到宿主this.postMessage(opt, data)}// 退出「微前端」界面// 不同载体,需要不同的方法// 比如 微信小程序,就需要 win.wx.miniProgram.navigateBack()if (messageInData) {// 此处微信小程序内嵌webview处理// 微信返回win.wx.miniProgram.navigateBack()// 微信发送寄存的数据win.wx.miniProgram.postMessage({ data: messageOutData })return}// 历史记录后退window.history.back()}}// 初始化时,尝试获取用户身份信息getUser()

滚屏为什么要使用iscroll?

问题 iframe引入时,body上的滚屏失效。
解决方案: 引入 iscrollbar5.2 实现自定义滚动条。

"less">.cp-layout {position: fixed;left: 0;right: 0;top: 0;bottom: 0;z-index: 2;overflow: hidden;.iScrollVerticalScrollbar {position: absolute;z-index: 9999;width: 3px;bottom: 2px;top: 2px;right: 4px;overflow: hidden;pointer-events: none;      }.iScrollIndicator {box-sizing: border-box;position: absolute;border-radius: 3px;width: 100%;transition-duration: 0ms;transform: translate(0px, 0px);transition-timing-function: cubic-bezier(0.1, 0.57, 0.1, 1);background-color: rgba(0, 0, 0, 0.2);      }    }
class="cp-layout">

通讯方案使用了postMessage为什么还要使用url入参?

问题:小程序webview对postMessage受限。解决方案: 使用url传参一次性传入所有参数。完成后,通过postMessage将数据一次性全部发送到宿主。

布局中,为什么要使用px2rem?

问题:iframe引入时,viewport 设置布局模式无效。解决方案: 引入 px2rem ,用rem来做整体布局。

「微前端」优化

如何减少「微前端」加载白屏时间?

  • 通过骨架屏,减少白屏时间;

  • 通过引入 asset-cache-webpack-plugin 插件,为资源加载做离线缓存(减少或消除白屏时间);

  • iframe时,使用单列模式开发,避免同时初始化多个「微前端」,造成性能损耗;

  • iframe加载微服务时,对「微前端」预加载。当需要使用时,可以快速展现。

引入 px2rem 和 asset-cache-webpack-plugin

vue.config.js

const AssetCachePlugin = require('asset-cache-webpack-plugin')module.exports = {devServer: {port: 9001    },// 样式配置css: {// css不单独一个文件编译extract: false,loaderOptions: {postcss: {plugins: [require('postcss-plugin-px2rem')({rootValue: 100, //换算基数, 默认100  ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。exclude: /(node_module)/,mediaQuery: false, //(布尔值)允许在媒体查询中转换px。minPixelValue: 0 //设置要替换的最小像素值(3px会被转rem)。默认 0    })  ]conf.plugin('asset-cache').use(AssetCachePlugin, [

总结与思考:「微前端」的优缺点

优点

  • 敏捷性 - 独立开发和更快的部署周期;

  • 快捷测试 - 每一个小的变化不必再触碰整个应用程序的回归测试;

  • 有助于持续集成、持续部署以及持续交付;

  • 维护简单,每个团队都熟悉所维护特定的区域。

缺点

  • 复杂的集成,「微前端」需要面对的多种环境,需要做多种兼容性验证;

  • 第三方模块重叠,依赖冗余增加了管理的复杂性。在团队之间共享公共资源的机制;

  • 避免影响最终用户的体验,「微前端」初始化可能会增加不必要的等待时间。

使用场景

  • 在单体应用中那些重复试用的模块可以抽取为「微前端」;

  • 这些模块也较稳定,代码迭代相对较少;

  • 在单体应用中的那些主流程,不适用于「微前端」。

postmessage 游戏窗口内无效_前端的微前端在交通项目内的应用实践相关推荐

  1. 前端怎么使用jsessionid_前端搞微前端 | 侑夕 - 如何落地微前端一体化运营工作台...

    下期预告 前端早早聊大会目标成为用得上.听得懂.抄得走的技术大会,计划 2020 年办 >= 15 期,由前端早早聊与掘金联合举办,前端早早聊大会行程动态.录播视频/PPT/讲稿资料下载请关注 ...

  2. 闲庭信步聊前端 - 见微知著微前端

    笔者初次接触微前端在2020年7月,是从同事的口中听说的.虽然不算是一个早期接触者,但是也确实的推动和跟进了内部某大型项目的开发和落地.也希望能把一些走过的坑和一些思考分享给大家.文内所指应用均为PC ...

  3. web 折线图大数据量拉取展示方案_对比多种微前端方案

    转自原文:帮你对比多种微前端方案 一.写在前面 在之前的文章中,我们已经深入剖析了微前端究竟是什么,可以带来什么收益,现在让我们复习一下微前端的概念: Techniques, strategies a ...

  4. qiankun 传统项目配置_飞猪微前端实践:统一运营工作台的解决方案-阿里云开发者社区...

    作者:侑夕 飞猪一体化运营工作台一期工作经过 3 个月的开发终于内部开始使用,期间我们面向运营场景,基于微前端与 SDK 化的一体化集成方案,完成 4 大场景 10 余个平台的接入和配置打通,并对数百 ...

  5. 前端 - 用微前端前应该了解的一些知识点

    一.微前端 微前端(Micro-Frontends)是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用.微前端不是单纯的前 ...

  6. qiankun 微前端_qiankun 微前端应用实践与部署(二)

    下面是两种方案的简要描述. 传统部署 方式 通过配置 nginx 端口到目录的转发. 具体可查看上一篇文章 特点 需要对外开放子应用对应的端口,将编译好的应用文件放到对应的配置目录. docker 部 ...

  7. gg修改器修改内购_如何用GG修改器修改应用内文字

    首先说明 这里修改不是用的mt管理器查看这个应用的安装包 因为这样会被支付宝检测禁止交易 我们选用GG修改器 示例应用-支付宝 我们进入GG修改器 选择目标应用支付宝 应用内存范围不需要动 我们进入搜 ...

  8. qiankun 微前端_微前端方案 qiankun(实践及总结)

    ❝ 作者:沉末_ 链接:https://juejin.im/post/5ed73b73e51d4578724e3fa4 ❞ 什么是微前端? 我们先来看两个实际的场景: 1. 复用别的的项目页面 通常, ...

  9. bootstrap跟vue冲突吗_知道微服务,但你知道微前端吗?

    在 toB 的前端开发工作中,我们往往就会遇到如下困境: 工程越来越大,打包越来越慢 团队人员多,产品功能复杂,代码冲突频繁.影响面大 内心想做 SaaS 产品,但客户总是要做定制化 不同的团队可能有 ...

最新文章

  1. adb.exe: more than one device/emulator
  2. 发表国外期刊注意事项
  3. HBase与时空索引技术
  4. 第12讲:Ajax 的原理和解析
  5. 2017一季度JAVA面试题锦集
  6. Alictf 2015决赛题目设计和解题思路
  7. linux view查看日志命令,【Linux】linux查看日志文件内容命令tail、cat、tac、head、echo...
  8. IOS开发中的弹框综述
  9. mysql重置密码报错,吐血整理
  10. 文件太大打不开,可以使用LogViewer
  11. SVN和git的优缺点比较
  12. c语言简单计算器减编程,C语言实现简单的计算器(加、减、乘、除)
  13. QQ聊天记录统计可视化分析
  14. java 项目中遇到的问题 和解决方案_java开发常见的问题及解决办法 - java开发中遇到的难点有哪些_java开发常见的问题及解决办法...
  15. 在微软工作365天,还你一个我眼中更加真实的微软
  16. 雷石 扩展文件服务器,雷石发布KTV软硬件新品:智能手表可点歌
  17. 鸿蒙系统运行内存为啥只有8g,明明8G内存,系统却显示只有4G!为啥会这样?
  18. Activiti bpmn流程图设计工具 分享
  19. 写论文的神仙网站推荐!
  20. 苹果电脑拷贝文件到u盘很慢_防病毒入侵防误删,爱国者这款U盘值得种草

热门文章

  1. metadata in OData and png
  2. SAP Fiori Launchpad里加载abap.js的具体代码位置
  3. Tomcat和搜索引擎网络爬虫的攻防
  4. 船体6自由度英文名称
  5. code block怎样导入整个文件夹_按需分配随时可用的在线开发环境:弹性容器+code-server踩坑记...
  6. mysql 5.5.39 安装_CentOS7.2安装mysql5.5.39
  7. 没有收到回复的同学注意了,用它一键查询!
  8. 大闹天竺里的机器人_在《大闹天竺》中哪一位演员是你喜欢的
  9. 美团flutter_ggtalk 聊聊跨平台:后起之秀 Flutter
  10. python 列表加入_加入python中的列表列表