微前端在Vue项目的实践

文章的参考:微前端在美团外卖的实践

我将讲解微前端如何在Vue项目中实践和应用,业务逻辑参考文中介绍的,文章中介绍的逻辑比较清晰,但是并没有提供过多的业务代码,对微前端如何应用到具体的项目我们就无从而知,为了介绍如何应用到项目中,我就写下了这篇文章,我们应用的工程是在Vue项目中。

  1. 如果你还不知道如何通过webpack配置Vue项目,请先参考这篇文章:自己搭建一个Vue项目工程

我的微前端项目是基于自己配置的webpack项目,不再使用Vue官方脚手架,因为生成出来的项目不服务我们的预期,比如有些要打包,有些不打包,等等。

如何使用

子工程:GitHub地址
基座工程:GitHub地址

基座工程和子工程启动命令都是yarn dev,两个工程必须都要启动,基座工程提供运行的环境,子工程负责打包自己的项目供外界访问,两个服务链接的桥梁是JSONP。
在这里插入图片描述

基座提供了一个注册子工程的入口文件:app.json

{
  "web": {
    "js": "http://localhost:9000/app.js"
  }
}

表示我们的子项目启动在http://localhost:9000/这个服务上,app.js表示子项目的入口文件,当访问到子工程的某个项目的时候,会发送一个JSONP请求到子工程服务器中,拿到对应的JS脚本执行即可,因为我们的微前端是基于路由划分的,(当然你也可以基于组件跟加细致的划分等等,但是对项目改动太大了,不适合已经开放了的项目),下面看加载子项目的代码

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import { handleRouter } from './generator'
import Store from '../store'
import jsonp from 'jsonp'
const subAppMapInfo = require('../../app.json')

Vue.use(VueRouter)

const routes = [
  {
    path: '/subapp',
    name: 'Home',
    component: Home
  },
  {
    path: '/',
    redirect: '/subapp'
  }
]

const router = new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes
})

const subAppRoutes = {}

router.beforeEach(function (to, from, next) {
  const { path } = to;
  const id = path.split('/')[2];
  const subAppModule = subAppMapInfo[id];
  if (subAppModule) {
    if (subAppRoutes[id]) {
      if (subAppRoutes[id].beforeEach) {
        let Route = router
        Route.handleRouter = handleRouter
        Route.cacheRouter = routes
        subAppRoutes[id].beforeEach(to, from, next, Store, Route)
      } else {
        next()
      }
    } else {
      jsonp(subAppMapInfo[id].js, { timeout: 500 }, function (err, date) {
        if (err) {
          console.log(`${id}项目加载失败:`, err)
          next('/subapp')
        } else {
          let result = date()
          console.log(`${id}项目加载成功:`, result)
          // 加载路由
          subAppRoutes[id] = result
          let children = routes[0].children
          if (children) {
            routes[0].children = children.concat(handleRouter({name: id, router: result.router}))
          } else {
            routes[0].children = handleRouter({name: id, router: result.router})
          }
          router.addRoutes(routes)
          // 加载状态
          Store.registerModule(id, result.store)
          next({...to, replace:true})
        }
      })
      next()
    }
  } else {
    next()
  }
})

export default router

JSONP获取之后会执行脚本,会传入一个registerApp函数,表示注册APP的函数,这个函数提供了当前APP需要的路由信息和状态容器,这个信息将会注册在基座工程里面,基座工程就会添加到基座工程的路由里面,就可以访问了。

import router from './router'
import store from './store'


function registerApp () {
  return {
    router, // 子项目的router
    store, // 子项目的store
    beforeEach (to, from, next) {
      next()
    }
  }
}

try {
  // eslint-disable-next-line no-undef
  __jp0(registerApp, '将注册函数返回让外界调用')
} catch (error) {
  console.log(error)
}

export default registerApp

在这里插入图片描述

大家还是参考代码实现把:

子工程:GitHub地址
基座工程:GitHub地址

发布了254 篇原创文章 · 获赞 200 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/wu_xianqiang/article/details/104620826