阅读 5240

vue-cli、ts + single-spa + systemJs 实现微前端

微前端架构是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将Web应用从单一的单体应用转变为由多个小型前端应用聚合为一的应用。 现阶段实现微前端的方式大致有以下六种:

  1. 使用 HTTP 服务器的路由来重定向多个应用
  2. 在不同的框架之上设计通讯、加载机制,诸如 MooaSingle-SPA
  3. 通过组合多个独立应用、组件来构建一个单体应用
  4. iFrame。使用 iFrame 及自定义消息传递机制
  5. 使用纯 Web Components 构建应用
  6. 结合 Web Components 构建

此次实践,采用的是Single-SPA的加载机制,具体如下。

项目架构

整体架构

内项目 作用
portal 最上层路由分发框架
menu 导航栏
cooper 主体项目
projects 有自定义西项目
.gitignore git提交忽略配置
readme.md 说明文档

框架之上的通讯机制

portal: 路由分发机制源头,systemJs 和 single-spa 的使用。

portal项目启动为服务时,port设置成为了8233。

systemJs: 是一个 通用模块加载器,支持AMD、CommonJS、ES6等各种格式的JS模块加载,也是Angular2官推的加载器。所以该微前端实例,支持跨技术(react、angular)模块加载。

single-spa: 是一个可以让使用多个javascript语言框架的构建的应用集成在一起的框架。

<script type="systemjs-importmap">{...}</script>
复制代码

用来导入可以需要引入的第三方模块,和插件。这里的config.js、single-spa.min.js、styles.css都是以HTTP形式引入,是为了避免后续的路由问题,因为该html将作为模板直接复用。

使用systemjs引入的方式

System.import('@portal/config')
复制代码

引入single-spa模块

registerApplication(名称,引入路径,是否引入)
singleSpa.start()启用
复制代码

用来判断某一模块是否引入

menu: 页面跳转

因为整个项目都是用vue写的,所以路由跳转这块用的是vue-router。

举例:

<router-link to="/index" />
复制代码

cooper: 页面响应 ***子项目因为使用vue-cli写的,所以 一定要引入vue-cli-plugin-single-spa插件,否则子项目的single-spa钩子无法正常exports。

vue项目中,先创建router.ts 举例:

import index from 'views/index/index.vue'

export default [{
    path: '/index',
    name: 'index',
    component: index
}, ...]
复制代码

在app.vue 中

<router-view />
复制代码

那为什么不同项目之间路由会相应呢?

所有独立项目都是以single-spa的形式打包输出,并引入到portal架构下的,经systemjs引入之后,相当与是在portal下运行的一个项目,http衔接到了localhost:8233下。因此,在独立项目中引用图片、css文件是,也需要已http形式引入。避免合并到portal下后,路劲找不到的问题。

单一应用入口文件配置

cooper/projects/menu: 入口文件配置

因为要打包成single-spa的形式,所以入口文件会有所不同。

入口文件main.ts

import Vue from 'vue'
import singleSpaVue from 'single-spa-vue'
import App from './App.vue'
import store from './store'
import router from './router'

const vueLifecircle = singleSpaVue({
    Vue,
    appOption: {
        el: '#vue',
        render: r => r(App),
        store,
        router
    }
})
复制代码

App.vue

<template>
    <div id="vue">
        <keep-alive>
            <router-view />
        </keep-alive>
    </div>
</template>
...
复制代码

webpack配置明细

项目single-spa形式输出配置

以menu为例的独立项目打包配置vue.config.js

const path = require('path')
module.exports = {
    chainWebpack: config => {
        config.entryPoints.clear()
        config.entry('menu').add('./src/main.ts').end()
        config.output.filename('menu.js').library('menu').libraryTarget('amd').end()
        config.devServer.port(8001).headers({
            "Access-Control-Allow-Origin": "*"
        })
    },
    outputDir: path.resolve(__dirname, 'dist/')
}
复制代码

输出的入口文件是menu.js,以AMD形式打包,原因:single-spa是AMD形式,所以也是在portal项目中会引用amd.js的原因。

portal项目打包配置

webppapck.config.config.js

module.export = {
    entry: './src/config',
    output: {
        filename: 'config.js',
        library: 'config',
        libraryTarget: 'amd',
        path: path.resolve(__dirname, 'build')
    },
    ...
    plugins: [
        CopyWebpackPlugin([
            {form: path.resolve(__dirname, 'src/index.html')},
            {from: path.resolve(__dirname, 'src/style.css')},
            {from: path.resolve(__dirname, 'common-deps-static')}
        ])
    ]
}
复制代码

打包后项目运行

只需要启动一个服务指向portal,其他子项目均放在portal目录下,以静态js文件形式引入。

子项目状态共享

可以把所有子项目的公共依赖全部提取,统一放到Portal层,已静态文件形式引入。同样,也可以把Vue、VueRouter、Vuex率先在portal层System.import(),并且注册为可用。详细细节后续会再整理一篇文档作为讲解。