前端微服务几种方式:
- 使用HTTP服务器(Nginx)的路由来重定向多个应用
- 在不同的框架之上设计通讯、加载机制,诸如 Mooa 和 Single-SPA
- 通过组合多个独立应用、组件来构建一个单体应用
- iFrame,使用 iFrame 及自定义消息传递机制
- 使用纯 WebComponent 构建应用
- 结合 WebComponent 和 ShadowDOM 来隔离应用
一、 Nginx路由分发
1. 微前端应用目录
/web/root
├── index.html // 统一入口
├── login.js // 登录逻辑
│
├── app1 // 应用1
│ ├── index.html
│ ├── favicon.ico
│ └── static
│
└── app2 // 应用2
├── index.html
├── favicon.ico
└── static
2. 子应用打包配置
下面以vue配置为例
1.) 路由基路径修改
export default new Router({
mode: 'history',
base: '/app1/',
routes: []
})
2.) 打包路径修改
此路径为打包输出目录
// vue.config.js
outputDir: '/web/root/app1'
// webpack.conf.js
output: {
path: '/web/root/app1',
}
3.) 发布路径修改
// vue.config.js
publicPath: '/app1/',
// webpack.conf.js
output: {
publicPath: '/app1/',
}
publicPath配置是index.html引用js的基路径
<script src="/app1/static/js/app.bb9cddb6.js"></script>
3. Nginx路由配置
注意子应用的try_files路径,最后一个是fall back兜底方案
server {
location / {
root /web/root;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /app1/ {
root /web/root;
index index.html index.htm;
try_files $uri $uri/ /app1/index.html;
}
location /app2/ {
root /web/root;
index index.html index.htm;
try_files $uri $uri/ /app2/index.html;
}
location /app1Api/ {
proxy_pass http://server1.domain.com/;
}
location /app2Api/ {
proxy_pass http://server2.domain.com/;
}
}
再优化一下nginx配置,对所有非/*Api/*
请求做正则匹配,获取RegExp.$1(应用的主路径)
location ~ ^/((\w(?!Api))*)/.* {
root /web/root;
index index.html index.htm;
try_files $uri $uri/ /$1/index.html;
}
location ~ 表示后面是正则表达式,区分大小写;~* 为不区分大小写匹配
二、 Single-SPA
Single-SPA优点:
- 兼容各种技术栈:同一页面可使用多种技术框架(React, Vue, AngularJS, Angular, Ember...),且无需刷新页面。
- 无需重构现有代码:使用新的技术框架编写代码,现有项目中的代码无需重构。
- 更优的性能:每个独立模块的代码可按需加载,不浪费额外资源。
- 每个独立模块可独立运行。
1、 源码引用模式
通过single-spa跨端组件将源码直接引用,打包编译成单应用
1.)微服务入口文件:single-spa-config.js
import { registerApplication, start } from 'single-spa'
// 路由模式
let routerMode = 'history'
// 匹配路由规则
let pathPrefix = prefix => {
if (routerMode === 'hash') {
return location.hash.startsWith(`#${prefix}`)
}
return location.pathname.startsWith(prefix)
}
// 注册应用
registerApplication(
'react',
() => import('./src/react/index.js'),
() => pathPrefix('/react')
)
registerApplication(
'vue',
() => import('./src/vue/index.js'),
() => pathPrefix('/vue')
)
// 启动
start()
2.)react入口文件:src/react/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import singleSpaReact from 'single-spa-react'
import App from './App.js'
const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: App,
domElementGetter: () => document.getElementById('root')
})
export const bootstrap = [reactLifecycles.bootstrap]
export const mount = [reactLifecycles.mount]
export const unmount = [reactLifecycles.unmount]
3.)vue入口文件:src/vue/index.js
import Vue from 'vue'
import singleSpaVue from 'single-spa-vue'
import App from './app.vue'
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
el: '#root',
render: r => r(App)
}
})
export const bootstrap = [vueLifecycles.bootstrap]
export const mount = [vueLifecycles.mount]
export const unmount = [vueLifecycles.unmount]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。