微前端

  • 微前端的好处

①团队自治,独立开发和部署
②技术灵活,可兼容老项目
③业务颗粒化

  • 目前微前端的方案
  1. iframe
    子应用可以通过iframe标签嵌入到父应用中,iframe具有天然隔离的属性,各个子应用之间及子应用和父应用之间可以做到互不影响。
    缺点:①刷新页面,iframe中的页面的路由会丢失
    ②全局上下文完全隔离,内存变量不共享
    ③弹框的遮罩不能覆盖整个浏览器
    ④慢,每次子应用进入都是一次浏览器上下文重建,资源重新加载的过程
  2. single-spa
    最早的微前端框架,也可以兼容很多技术。
    在基座中注册所有子应用的路由,当url改变时进行匹配,匹配到哪个子应用就会去加载对应的哪个子应用。
    相对于iframe的框架,不存在刷新,路由丢失问题
    缺点:①没有实现js和css隔离
    ②需要修改大量的配置,不能开箱即用
  3. qiankun
    基于single-spa封装,提供了开箱即用的API
    HTML Entry的方式接入,像使用iframe一样简单
    实现了single-spa不具备的样式隔离和js隔离
    资源预加载,在浏览器空闲时间预加载未打开的微前端应用,加速微应用打开速度。
  • qiankun介绍
  1. 基座
    第一步:安装
    首先npm i qiankun
    第二步:修改入口文件
    在入口应用处添加
import {start,registerMicroApps}from 'qiankun'
//要添加的子应用列表
const apps =[
  {
    name:'sub-react'//子应用名称
    entry:'//localhost:8080',//加载这个路径下的html,解析里面的js
    activeRule:'/sub-react',//匹配的路由
    container:'sub-app'//加载的容器(id的值)
  }
]
//注册子应用
registerMicroApps(apps,{
  beforeLoad: [async app => console.log('before Load',app.name)]
  beforeMount:[async app => console.log('before Mount',app.name)],
  afterMount:[async app => console.log('After Mount',app.name)]
})
//启动
start()
//子应用渲染区
  1. 子应用
react子应用

其中使用到react-app-rewired工具来改造webpack
入口文件改造

import '../public-path.js'
let root = null
function render(props){
  const {container}=props
  const dom =container?container.querySelector('#root'):document.getElementById('root')
  root = createRoot(doom)
  root.render(
    
  )
}
//判断是否在qiankun的环境下
if(!window._POWERED_BY_QIANKUN_){
    render({})
}
//生命周期
//bootstrap只会在微前端应用初始化的时候调用一次
export async function bootstrap(){
  
}
//应用每次进入都会调用mount方法
export async function mount(props){
  render(props)
}
//应用每次切出/卸载调用
export async function unmount(){
  root.unmount()
}

新增public-path.js文件(需要在入口文件引入)
publicPath
默认值: 空字符串。publicPath是非常有必要配置的,他是项目中引入静态资源(js、css)时的基础路径。
例如:outPut.publicPath = ‘/dist/’;

if(window._POWERED_BY_QIANKUN_){
    //动态设置webpack publicPath,防止资源加载出错
  _webpack_public_path_ =window._INJECTED_PUBLIC_BY_QIANKUN_
}

修改webpack配置使用react-app-rewired
npm i react-app-rewired
在根目录下新增config-overrides.js文件

const {name} = require('./package')

module.exports = {
  webpack:(config) => {
      config.output.library =`${name}-[name]`
      config.output.libraryTarget ='umd'
      config.output.chunkLoadingGlobal = `webpackJson_${name}`
      return config
  }
}
vue子应用

vue3+vite

  1. 安装:npm i vite-plugin-qiankun
  2. 修改vite.config.js文件
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
  base:'/sub-vue'//和基座中配置的activeRule一致
  server:{
    port:3002,
    cors:true,
    origin:'http://localhost:3002'
  },
  plugins:{
    vue(),
    qiankun('sub-vue',{useDevMode:true})
  }
})
  1. 修改main.ts入口文件
import  {renderWithQiankun,qiankunWindow} from 'vite-plugin-qiankun/dist/helper'
let app = null
if(!qiankunWindow._POWERED_BY_QIANKUN_){
  createApp(App).use(router).mount('#app')
}else{
  renderWithQiankun({
    mount(props){
        app = createApp(App)
        app.use(router).mount(props.container.querySelector('#app'))
    },
    bootstrap(){},
    update(){},
    unmount(){app.unmount()}
  })
}
umi框架的子应用
  1. npm i @umijs/plugins
  2. 配置.umirc.ts
export default {
  base:'/sub-umi',
  npmClient:'npm',
  plugins:['@umijs/plugins/dist/qiankun'],
  qiankun:{
    slave:{}
  }
}

如果想要在qiankun的生命周期做一些处理,在入口加入

export const qiankun ={
    async mount(){},
    async bootstrap(){},
    async afterMount(){}
}
补充
  1. 样式隔离:
    qiankun实现的是子应用之间的样式隔离,但是基座与子应用之间的样式隔离病没有实现,所以基座和子应用之间还是会存在样式的覆盖和冲突。
    解决办法:
  • 每个应用的样式使用固定格式
  • 通过css-module的方式给每个应用自动加上前缀
  1. 子应用之间的相互跳转
    (1)主应用和微应用都是hash模式,主应用根据hash来判断应用,则不用考虑这个
    问题。
    (2)history模式下微应用之间的跳转,或者微应用跳主应用页面,直接使用微应用的路由是不行的,原因是微应用的路由实例跳转都是基于路由的base。有两种方法可以跳转:
    ①history.pushState()
    ②将主应用的路由实例通过props传递给微应用,微应用这个路由实例跳转。
  2. 公共依赖加载
    主应用和子应用都是用了相同的库(antd,axios),就可以使用externals的方式引入,减少加载重复包,导致的资源浪费。一个项目使用后,另外一个项目不必再重复加载。
    方法:
    主应用:将所有公共依赖配置webpack的externals,并在index.html中使用外链引入这些公共依赖。
    子应用:和主应用一样配置webpack的externals,并且在index.html中引入这些公共依赖,还需要给子应用的公共依赖加上ignore属性(自定义属性,非标准属性),qiankun在解析时,如果发现ignore属性,就会自动忽略。
  3. 全局状态管理
    一般来说,各个子应用通过业务线划分,不同业务线应该降低耦合度,尽量避免通信,但是涉及到一些公共状态或者操作,qiankun也是支持的。
    qiankun提供了一个全局的GlobalState来共享数据,基座初始化之后,子应用可以监听到这个数据的变化,也能提交这个数据。
    基座:
//基座初始化
const state ={count:1}
import {initGlobalState} from 'qiankun'
const actions = initGlobalState(state)
actions.onGlobalStateChange((state,prev)=>{
  console.log(state,prev)
})
actions.setGlobalState(state)

子应用:

export function mount(props){
  props.onGlobalStateChange((state,prev)=>{
      console.log(state,prev)
  })
  props.setGlobalState(state)
}

【信息由网络或者个人提供,如有涉及版权请联系COOY资源网邮箱处理】

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容