asm-service v0.1.3
基于 single-spa 的微前端框架
解决了 single-spa 没有解决的微前端项目资源加载的问题,到资源加载失败时,提供重新加载资源的方法。
asm-service
将每个项目的 html 作为 entry 得到这个项目的 js,css 资源,然后将 js,css 插入到 document 中
安装
npm i asm-service --save
基本用法
import AsmService from 'asm-service'
new AsmService([
{
name: 'xxx', // 项目名
projectIndex: 'http://xxxx.com', // 项目访问入口
base: false, // 是否需要一直在页面中显示
path: '#/body', // 项目显示条件。可以是数组
routeMode: 'hash', // 路由模式
},
]).start()
子项目配置
字段 | 类型 | 是否必填 | 可选值 | 默认值 | 描述 |
---|---|---|---|---|---|
name | String | 是 | - | - | 项目名 |
projectIndex | String | 是 | - | - | 项目访问入口 |
base | Boolean | 否 | true,false | false | 是否需要一直在页面中显示 |
path | String,Array | 否 | - | [] | 项目的显示条件,当 base 为 true 时,path 的值会被忽略 |
routeMode | String | 否 | hash,history | hash | 路由模式。 routeMode 和 path 配合使用来确认项目的显示与否 |
domID | String | 否 | - | '' | 项目要挂载的 dom 节点的 id 属性 |
customProps | Object | 否 | - | {} | 各个生命周期要传递到项目的自定义属性 |
AsmService 实例
start 方法
start 方法用于 启动 AsmService, start 方法可以接受一个对象作为参数,它返回一个 promise
AsmService.start(opts)
opts 对象的属性
属性名 | 类型 | 是否必填 | 可选值 | 默认值 | 描述 |
---|---|---|---|---|---|
fetch | Function | 否 | - | window.fetch | @hydesign/grape 通过 fetch 函数来获取项目访问入口对应的 html 文档,fetch 函数必须返回一个 promise |
repeatNum | Number | 否 | - | 1 | 当使用 fetch 获取项目的 html 失败之后,重新获取的次数 |
repeatInterval | Number | 否 | - | 2000 | 当使用 fetch 获取项目的 html 失败之后,再次获取间隔的毫秒数 |
setImportMap 方法
当需要将各个项目的公共库从项目代码中抽离出来统一管理,setImportMap 方法会很有用处。setImportMap 与 webpack externals 配合使用可以抽离出项目中不想打包的库,在项目运行时使用到这个库的时候再动态加载,setImportMap 的用法见下文
apps
如果想要得到 AsmService 中所有的 app 的信息你可以通过 apps 属性得到,apps 的值不能从外部修改
AsmService.apps
app 的状态
- NOT_LOAD: 还没有开始加载 app 的资源
- LOADING: 正在加载 app 的资源
- LOAD_ERROR: app 的资源加载失败
- LOADED: app 的资源加载成功
- REGISTERED: app 注册成功
- REGISTER_ERROR: app 注册失败
高级用法
除了可以通过实例化 AsmService 对象时传入一系列 app,然后调用 start 的方式去注册 app,也可以调用 AsmService 的 loadApp 方法去注册 app。
import AsmService from 'asm-service'
new AsmService().start()
AsmService.loadApp({
name: 'xxx', // 项目名
projectIndex: 'http://xxxx.com', // 项目访问入口
base: false, // 是否需要一直在页面中显示
path: '#/body', // 项目显示条件。可以是数组
routeMode: 'hash', // 路由模式
})
可以在AsmService
启动之后的任何时候调用AsmService.loadApp
调用AsmService.loadApp
注册 app 时,它会做如下判断:
- 这个 app 是否已经加入到 AsmService.apps 中,如果没有,将这个 app 加入 apps 中,并且加载 app 的资源,最后注册 app。
- 这个 app 的资源是否加载失败或者 app 是否注册失败,如果失败了,则重新加载资源,然后注册 app
- 这个 app 已经注册成功,这个方法什么都不会做
如果 app 已经加入到 AsmService.apps 中, 调用 AsmService.loadApp 会使用 AsmService.apps 队列中的 app 的 projectIndex 去加载资源。
设置子项目的生命周期函数
import vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue'
const vueLifecycles = singleSpaVue({
Vue: vue,
appOptions: {
el: '#main',
render: (h) => h(App),
router,
},
})
export const bootstrap = vueLifecycles.bootstrap
export const mount = vueLifecycles.mount
export const unmount = vueLifecycles.unmount
给子项目的入口 js 加标识
经过打包工具(如:webpack)打包之后一个项目在 index.html 中插入的 js 脚本可能不只一个,所以为了确保@hydesign/grape
能够正确的从项目中解析到入口 js,给入口 js 文件加上一个 entry 属性,如果所有的 js 脚本都没有 entry 属性,AsmService
会将 index.html 的中最后一个脚本当作入口 js
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
plugins:[
...
new ScriptExtHtmlWebpackPlugin({
custom: {
test: /app.*\.js$/,
attribute: 'entry',
value: true
}
})
]
将子项目打包成 umd 格式
output: {
...
libraryTarget: 'umd',
library: xxx,
}
setImportMap 方法与 webpack external 配合
AsmService
与webpack
的 externals 配合使用,能够抽离出项目中不想打包的库,并且在项目运行当使用到这个库的时候在动态加载。
externals(['vue',{'vue-router':'vueRouter'},{'element-ui':'elementUI'},'axios', {'asm-client':'asmClient'}])
import AsmService from 'asm-service'
new AsmService(appsConf)
.setImportMap({
vue: 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js',
vueRouter:
'https://cdn.jsdelivr.net/npm/vue-router@3.0.7/dist/vue-router.min.js',
elementUI: 'https://cdn.jsdelivr.net/npm/element-ui@2.12.0/lib/index.js',
Vuex: 'https://cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js',
axios: 'https://cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js',
})
.start()