2021年7月由京东开源的微前端框架
官方文档
micro-appgit地址
了解micro-app
这段不重要可跳过
版本:0.8.0
使用背景:目前所在的公司存在多个项目共用同一个模块的情况,比如有A,B,C三个项目,这三个项目中有一部分页面是完全相同的,我们不希望去重复开发同一个模块,于是领导提出将重复的页面单独提取出来成为独立的项目单独部署,这个项目单独拿出来也可以成为一个合格的项目,并且A,B,C三个项目中可以使用iframe进行内嵌,但是我始终觉得iframe不算是好的解决方案,比如多个滚动条的问题,弹窗不能覆盖全局的问题,以及项目加载使用了NProgress,加载iframe的时候会在页面上显示这个进度条
我的想法:我希望实现的效果是子项目起码看起来就像是父项目自己的页面一样,于是最初我选择使用vue-cli提供的远程组件,将页面打包成组件,放到服务器上,父项目引入必要的文件地址,挂载组件
父项目index.html
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="http://你的ip:端口/v2/yczjTest/pageTest.css">
<link rel="stylesheet" href="http://你的ip:端口/nj/packages/packages.css">
<title>xxx平台title>
head>
<body>
<div id="app">div>
body>
<script src="https://unpkg.com/vue">script> 必须引入这一行
<script src="http://你的ip:端口/v2/yczjTest/pageTest.umd.min.js">script>
<script src="http://你的ip:端口/nj/packages/packages.umd.min.js">script>
html>
子项目打包命令 :"build:node": "vue-cli-service build --target lib --name 包名 --dest 输出地址 打包入口"
如:"vue-cli-service build --target lib --name pageTest --dest mock/public/lib export/index.js"
具体如何挂载可以查看参考地址
结果:子项目挂载后确实看起来和父项目融合的非常好,但是很快就发现问题,这样打包的子项目只是一个组件而已,子项目对于父项目来说完全不能算是一个独立的项目,他是依赖于父项目的,比如:store, router,以及全局this,说白了,父项目中有的子项目可以使用,但是如果父项目没有,或者有人不小心删除了父项目中的内容这个内容刚好又是子项目所需要依赖的,那就完了,并且子项目中的路由也是无法在父项目中使用的,只能自己监听路由来尝试着在父项目中实现子组件页面切换的效果。
于是我去了解微前端解决方案:iframe, qiankun, micro-app
父项目(基座项目):
//父项目下载
npm i @micro-zoe/micro-app --save
//main.js 写入
import Vue from 'vue'
import App from './App.vue'
import microApp from '@micro-zoe/micro-app'
import router from './router'
microApp.start()
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
// router/index.js 为子项目分配一个路由并创建文件夹以及文件/myPage/index.vue
// router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import MyPage from '../views/myPage.vue'
Vue.use(VueRouter)
const routes = [
{
// 非严格匹配,/my-page/* 都将匹配到 MyPage 组件
path: '/my-page/*', // [email protected] path的写法为:'/my-page/:page*'
name: 'my-page',
component: MyPage,
},
]
let router = new VueRouter({
routes
})
export default router
mypage/index.js
<template>
<div>
<h1 @click="go">我是基座应用</h1>
<!--
name(必传):应用名称,每个`name`都对应一个应用,必须以字母开头,且不可以带有 `.`、`#` 等特殊符号
url(必传):页面html的地址
baseroute(可选):基座应用分配给子应用的路由前缀,就是上面的my-page
-->
<micro-app name='app1' url='http://localhost:8083/' baseroute='/my-page'></micro-app>
</div>
</template>
子项目:
//vue.config.js
module.exports = {
publicPath: process.env.VUE_APP_PUBLICPATH || 'http://localhost:8080/', // 如果父项目访问子项目资源出现404,就指定publicPath
devServer: {
headers: {
'Access-Control-Allow-Origin': '*', // 本地开发环境需要允许跨域访问 生产环境需要在nginx配置允许跨域稍后贴出nginx配置文件
},
},
};
子项目router
import Vue from "vue"
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path:'/my-page/index',
component:() => import('../views/index.vue')
}
]
const router = new VueRouter({
// 添加路由前缀,子应用可以通过window.__MICRO_APP_BASE_ROUTE__获取基座下发的baseroute,如果没有设置baseroute属性,则此值默认为空字符串
base: window.__MICRO_APP_BASE_ROUTE__ || '/',
routes,
})
export default router
子项目 view/index.vue
<template>
<div @click="go" class="div">我是子应用</div>
</template>
<script>
export default {
data(){
return{
}
},
methods:{
go:function(){
console.log(11111);
}
}
}
</script>
<style scoped lang='less'>
.div{
color:red;
}
</style>
现在启动父项目和子项目就可以看到效果
至此我以为我可以快乐地开始敲代码了,但是我发开始发现了一些问题
一、micro-app子项目引入高德地图报错
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %>title>
head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
noscript>
<div id="app">div>
<script
src="https://webapi.amap.com/maps?v=1.4.15&key=(key)&&plugin=AMap.Scale,AMap.OverView,AMap.ToolBar,AMap.DistrictSearch">
script>
body>
html>
这个错误是micro-app解析css是抛出的,所以使用时需要注意这个问题,把这个script注释掉,就恢复正常,我在今天上午的时候在git留言提出这个问题,作者回复下个版本修复这个问题所以不妨再等等啦
上午刚留言的问题作者下午就解决了,0.8.1已经修复了!!!!
.scss文件中包含注释导致css解析报错
由于项目是我后来接手的,所以项目中并不是每一个文件我都检查过或者打开过,我发现父项目引入子项目始终报错:Declaration missing ‘}’
于是我打断点检查源码,对子项目的scss文件进行检查,发现了如下代码
把这段注释删除,不再报错,子项目正常加载
server
{
listen 8082;
server_name 域名/ip;
index index.html;
root /files/test;
location ~ .*\.(js)$ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
gzip_static on;
gzip_http_version 1.0;
gzip_comp_level 1;
gzip_proxied expired no-cache no-store private auth;
gzip_vary on;
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png image/x-icon;
root /files/test;
}
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
location @router {
rewrite ^.*$ /index.html last;
}
}
以上就是我目前为止发现的一些问题,以及micro-app简单的使用方式,相对于qiankun我个人更加喜欢micro-app的实现方式和使用方式,用组件的形式来引入子项目,包括数据通信也非常容易,不过当需要展示子项目时,由于父项目需要加载和解析子项目所需要所需要的资源,所以会出现一段时间的空白,这个可以适当的对子项目进行优化,减少关键资源数量与大小来减少白屏时间,有兴趣的也可以到知乎看作者的教程自己动手实现微前端