微前端(5)ice

这篇记录飞冰相关实验。

主应用搭建

安装依赖

1
2
3
4
5
"dependencies": {
"@ice/stark": "^2.7.5",
"@ice/stark-app": "^1.5.0",
"@ice/stark-data": "^0.1.3"
}

App.vue 中初始化

1
2
3
4
<template v-loading="loading">
<span id="controllerApp"></span>
<router-view v-if="!microAppsActive" />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { registerMicroApps } from '@ice/stark/lib/apps'
import start from '@ice/stark/lib/start'
import { store } from '@ice/stark-data'

const userStore = useUserStore()
const config = window.APP_CONFIG[import.meta.env.VITE_USER_NODE_ENV]
let loading = ref(false)
let microAppsActive = ref(false)

onMounted(() => {
const container = document.getElementById('controllerApp') as HTMLElement
registerMicroApps([
{
name: 'pts', // 微应用唯一标识
activePath: '/pts',
title: '产品追溯系统',
loadScriptMode: 'import',
scriptAttributes: ['crossorigin=anonymous'],
entry: `${config?.controlCenterUrl}/index.html`,
container
}
])

start({
// 微应用加载前的回调,在微应用加载过程中渲染加载动画
onLoadingApp: () => {
loading.value = true
},
// 微应用加载并执行后的回调, 在微应用加载过程中结束渲染加载动画、结合 onLoadingApp 记录微应用加载执行的时长
onFinishLoading: () => {
loading.value = false
},
// 处理微应用间跳转无法触发 Vue Router 响应
onRouteChange: (_, pathname) => {
router
.push(pathname)
.catch(() => {})
},
// 微应用开始被激活的回调, 记录当前 url 匹配的微应用
onActiveApps: (activeApps) => {
console.log('activeApps: ', activeApps)
microAppsActive.value = !!(activeApps || []).length
if (microAppsActive.value) {
store.set('controlData', { token: getToken(), userInfo: userStore.getUserInfo })
}
},
// 微应用开始渲染前的回调, 结合 onLoadingApp 记录微应用从加载到渲染的时长,结合 onFinishLoading 记录微应用渲染耗时
onAppEnter: () => {},
// 微应用卸载前的回调, 记录用户的停留时长
onAppLeave: () => {},
// 微应用在 icestark 在加载或执行错的回调, 记录微应用运行的错误信息
onError: () => {},
})
})

微应用搭建

main.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { createApp } from 'vue'
import App from './App.vue'
import { createWebHistory, createRouter } from 'vue-router';
import getBasename from '@ice/stark-app/lib/getBasename';
import isInIcestark from '@ice/stark-app/lib/isInIcestark';
import setLibraryName from '@ice/stark-app/lib/setLibraryName';

let vue: Root<Element> | null = null;
// setLibraryName('microApp')

// export function mount({ container }: { container: Element}) {
// vue = createApp(App);
// vue.mount(container);
// }

const runApp = (container: Element | string) => {
const history = createWebHistory(isInIcestark() ? getBasename() : '/');
const router = createRouter({
history,
routes,
});
vue = createApp(App);
vue.use(router);
vue.mount(container);
};

if (!isInIcestark()) {
createApp(App).mount('#app');
}

export function mount({ container }: { container: Element}) {
runApp(container);
}

export function unmount() {
vue.unmount();
}

App.vue 可以跳回主应用

1
2
3
4
5
import appHistory from '@ice/stark-app/lib/appHistory';

const jumpToLayout = () => {
appHistory.push('/');
};

html

加载模式

icestark 目前支持三种加载模式,分别是 script、fetch 和 import,由 loadScriptMode 字段指定。

  1. script—默认加载方式。该模式下,icestark 会通过 HTML script 标签加载微应用脚本资源,再次加载时充分利用浏览器缓存进行加载。
  2. fetch—当指定 loadScriptMode 为 fetch,或配置微应用沙箱模式时,会通过 window.fetch 或用户自定义的 fetch 能力加载并缓存脚本资源。再次加载时,会充分利用本地内部缓存进行加载。
  3. import—加载 ES modules 类型微应用的主要方式,该模式会通过 Dynamic Import 动态加载脚本资源。

Q & A

  1. 直接启动 UMS,首页能渲染,浏览器地址栏输入 /pts,显示的是浏览器404,不是自己的404页面。
    【错误❌】猜测是否是因为 pts 首页进行了一个跳转?尝试将地址更改为 /pts/traceChip。
    直接启动 pts,发现是因为 router 没有成功,恢复到之前的写法,此时 UMS 中输入 /pts 跳转到自己的404页面。(路由请求已经成功,只是页面没找到)
    经过检查,发现 activeApps 开始是有的,不知道为什么数据加载了又没了。
    【原因】router.ts 中修改 createRouter,不能直接用原来的 history。
    activeApps

  2. 首页都能渲染并且点击侧栏都能跳转,但是点击操作列跳转显示 Not Found,浏览器返回按钮点击无效。
    Not Found
    【原因】终端开启的服务自己在重新加载,加载完成后未出现该问题。
    芯片台账-查看 访问成功

  3. 静态资源访问失效
    主应用和子应用本地开发启动端口不一样,导致资源加载以主应用IP+绝对路径访问,线上环境应该不会出现这个问题。

附录
飞冰


微前端(5)ice
https://guoningyan.com/2023/09/26/微前端(5)ice/
作者
Ningyan Guo
发布于
2023年9月26日
许可协议