手把手教你使用vue2搭建微前端micro-app
简述
本文主要讲述新手小白怎么搭建micro-app,几乎是每一步都有截图说明。上手应该很简单。
研究背景
这段时间在网上找了很多有关微前端相关的知识,起初本来是想着先搭建一个single-spa,但是奈何网上能找到的内容都是千篇一律。我也是搭了好久没搭出来。不知道为啥,反正就是一个劲的报错。
后面发现京东嫌弃single-spa太难用,他们自己搞了一套micro-app,那我想着这个应该比single-spa好用吧。很明显的好处就是,micro-app最起码能找到好理解的官网
但是对于项目的搭建,官网介绍的也是很粗糙,网上找到的也是一上来就npm,对于零基础的新手来说真的是太不友好了。说实话,渣渣的我看了都不知道npm在哪输入。不过还是在一步步的探索中取得了成功。
接下来先看一下搭建成功的效果图吧,图中展示了基座运行和两个子应用下运行的效果,即:可以单独运行,也可以整体运行:
项目代码
看完运行效果后,就开始搭建项目了
1、准备工作
1-1、创建项目
首先第一步就是先创建一个文件夹 ,如下图所示,我这边新建了一个叫micro-app-demo的文件夹,用webStrom打开,效果如下图所示:
1-2、创建vue项目
接下来就是创建vue,这个命令之前装single-spa的时候就遇到过,让我升级vue3。
所以你在安装时如果提示你升级,就按照提示进行升级,不然会报错。
vue create base
由于忘记截图,这个是之前搭single-spa时的截图,一样的道理,只是文件夹名称和create名称不一样而已,可以理解大概意思 。
提示vue create是vue cli3的唯一命令 ,而已使用的是vue cli 2.9.6 ,公司的电脑我也不敢随便改,怕影响到项目,所以接下来就算自己笔记本了。
创建时先升级到vue3
npm uninstall -g vue-cli
npm install -g @vue/cli
我笔记本只安装了vsCode,所以接下来的代码展示都是在vsCode中进行操作的。
接下来就步入正题,开始创建:
2、安装base(基座)
base我这边理解为基座,即:子应用都需要在base基座中配置,类似iframe框架
2-1、创建base,在micro-app-demo文件夹下安装
接上一步,使用vsCode将新建好的文件夹micro-app-demo打开,如下图所示,打开一个新终端,在下面输入命令创建base,创建时可选择vue2还是vue3,我这边以vue2为例,如果要选vue3的话,下面代码中的语法会不一样。
我这边选择vue2后,安装完成后,效果如下图所示:
可以从图中看到安装完后的整个目录,既然它有提示让我们运行,那就运行一下看看效果。运行效果如下:
接下来开始对base进行改造,注:下面的修改都是对base目录下的修改,别搞错地方了。
2-2、添加配置文件vue.config.js
module.exports = {devServer: {host: 'localhost', port: 3000}
}
2-3、安装micro-app插件,安装在base目录下
npm install @micro-zoe/micro-app --save
安装完成后可以在package.json文件下看到刚刚安装好的 插件
2-4、micro配置
接下来创建一个文件夹,文件夹里面有两个js文件
base/src/micro/index.js
import microApp from '@micro-zoe/micro-app'
import * as config from './config'/**启用 micro */
microApp.start({preFetchApps: config.MICRO_APPS, globalAssets: config.GLOBAL_ASSETS
})
base/src/micro/config.js
/**
* 子应用前缀
*/
export const CHILD_PREFIX = 'app'/**
* 子应用地址
*/
export const MICRO_APPS = [{ name: 'first-child', url: `http://localhost:3001/` }, { name: 'second-child', url: `http://localhost:3002/` }
]/**
* 全局资源
*/
export const GLOBAL_ASSETS = {js: [], css: []
}
2-5、安装路由
这里路由我装低一点的版本,安装完成后package.json中可以看到效果
npm install vue-router@3
2-6、修改main.js
修改入口文件main.js,引入micro-app配置,在这里顺便将上一步安装的路由也引入
import './micro'
import Vue from 'vue'
import App from './App.vue'
import router from './router'Vue.config.productionTip = falsenew Vue({router,render: h => h(App),
}).$mount('#app')
2-7、修改App.vue文件
<template><div id="app"><div id="nav"><router-link to="/">Home</router-link> |<router-link to="/about">About</router-link>|<router-link :to="`/${prefix}/first-child/home`">FirstChildHome</router-link>|<router-link :to="`/${prefix}/first-child/about`">FirstChildAbout</router-link>|<router-link :to="`/${prefix}/second-child/home`">SecondChildHome</router-link>|<router-link :to="`/${prefix}/second-child/about`">SecondChildAbout</router-link></div><div><micro-appv-if="isChild"v-bind="micro"destory@created='created'@beforemount='beforemount'@mounted='mounted'@unmount='unmount'@error='error'@datachange='handleDataChange'></micro-app><router-view v-else></router-view></div></div>
</template><script>
import { MICRO_APPS, CHILD_PREFIX } from './micro/config.js'export default {name: 'App',data () {return {isChild: false /**是否为子模块 */, micro: { url: '' /**子模块地址 */, key: '' /**vue 标签的 key 值,用于不同子模块间的切换时,组件重新渲染 */, name: '' /**子模块名称,唯一 */, data: {} /**子模块数据 */, baseroute: '' /**子模块数据 */}, prefix: CHILD_PREFIX /**子模块链接前缀 */}}, watch: {$route (val) { /**监听路由变化修改视图显示 */this.changeChild(val)}}, created () {this.changeChild(this.$route)}, methods: {created () { /**子模块创建 */console.log(`${this.micro.name}-created`)}, beforemount () { /**子模块挂载之前 */console.log(`${this.micro.name}-beforemount`)}, mounted () { /**子模块挂载 */this.loading = falseconsole.log(`${this.micro.name}-mounted`)}, unmount () { /**子模块卸载 */console.log(`${this.micro.name}-unmount`)}, error () { /**子模块异常 */console.log(`${this.micro.name}-error`)}, getAppUrl (name) { /**获取子模块 url 和 name */return MICRO_APPS.find(app => app.name === name) || {}}, changeChild (route) { /**修改子视图显示 */let path = route.path.toLowerCase(), paths = path.split('/')/**判断是否为子模块,子模块有固定的前缀,在 micro/config 设置 */this.isChild = paths.length > 2 && paths[1] === CHILD_PREFIXif (this.isChild) {let app = this.getAppUrl(paths[2])this.micro = {...app, data: { name: route.name }, key: `${app.name}`, baseroute: `/${CHILD_PREFIX}/${paths[2]}`}}}, handleDataChange (event) { /**获取子路由传递的信息 */let data = event.detail.dataif(data.route) this.$router.push({ name: data.route.name })}}
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}#nav {padding: 30px;
}#nav a {font-weight: bold;color: #2c3e50;
}#nav a.router-link-exact-active {color: #42b983;
}
</style>
2-8、配置路由
我们虽然在2-5中安装了路由,但是没有对路由进行配置,所以这边要配置一下路由。
刚创建好的vue项目中没有对路由的配置,所以需要手动添加配置。
创建文件夹router,router中添加index.js文件
base/src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'import { CHILD_PREFIX } from '@/micro/config.js'Vue.use(VueRouter)const routes = [{path: '/', name: 'Home', component: () => import('../views/Home.vue')}, {path: '/about', name: 'About', component: () => import('../views/About.vue')}, {path: `/${CHILD_PREFIX}/first-child`, name: 'FirstChild', children: [{path: 'home', name: 'FirstHome'}, {path: 'about', name: 'FirstAbout'}]}, {path: `/${CHILD_PREFIX}/second-child`, name: 'SecondChild', children: [{path: 'home', name: 'SecondHome'}, {path: 'about', name: 'SecondAbout'}]}
]const router = new VueRouter({mode: 'history', routes
})export default router
2-9、创建视图(views)
创建views文件夹,文件夹下面有home和about两个文件,路由中有配置,所以也需要这个页面。
base/src/views/Home.vue
<template><div class="home"><img src="../assets/logo.png"><h1>基座-home page</h1></div>
</template><script>
export default {name: 'Home'
}
</script>
base/src/views/About.vue
<template><div class="about"><h1>基座-about page</h1></div>
</template>
到此基座就搭建完成了,因为基座中有对子应用的配置,而子应用还没开始搭建,所以 这边暂时先不运行。
3、创建app_first(子应用1)
子应用为刚刚搭建完base的子应用,在例子中我们搭建两个子应用,为了方便起见,接下来的操作中我们一起把两个子应用都创建好,在去修改里面的配置。
创建之前需要注意的是,子应用与基座的层级关系是并列的,所以创建子应用时目录需要回到micro-app-demo目录下,具体操作如下:
3-1、创建app_first,cd…回到micro-app-demo文件夹下
cd .. // 返回上一级目录
vue create app_first
3-2、创建app_second
这边为了减少麻烦我直接把app_second也创建了,等会就不用创建app_second了
vue create app_second
到这里子应用就都创建完成了,接下来开始对子应用开始配置,因为一下子有了三个目录文件,很容易搞错,所以配置的时候一定要看清楚哪个文件夹下的哪个文件。
接下来开始对app_first(子应用1)的修改,注:接下来的所有修改都在app_first文件夹下
3-3、修改vue.config.js
修改vue.config.js文件,设置允许跨域
module.exports = {devServer: {host: 'localhost', port: 3001, headers: { // 设置本地运行的跨域权限'Access-Control-Allow-Origin': '*',}}
}
3-4、micro配置
和基座一样,在src下创建文件夹micro/index.js。不同的是,子应用不需要config.js了
app_first/src/micro/index.js
// 设置 webpack 的公共路径
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'
3-5、修改main.js
/**引入 publicPath 设置 */
import './micro'import Vue from 'vue'
import App from './App.vue'
import router from './router'Vue.config.productionTip = false// new Vue({
// router,
// render: function (h) { return h(App) }
// }).$mount('#app')let app/**
* 挂载函数
*/
function mount () {app = new Vue({el: '#app',router,render: function (h) { return h(App) }})
}/**
* 卸载函数
*/
function unmount () {app.$destroy()app.$el.innerHTML = ''app = null
}/**微前端环境下,注册mount和unmount方法 */
if (window.__MICRO_APP_ENVIRONMENT__)window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount }
elsemount()
3-6、安装路由
cd app_first // 1.先进入子应用1目录下
npm install vue-router@3 // 2.安装路由
3-7、修改App.vue文件
<template><div id="app"><div id="nav"><router-link :to="`${prefix}/home`">子应用1Home</router-link> |<router-link :to="`${prefix}/about`">子应用1About</router-link> |<button @click="goto('SecondHome')">SecondHome</button> |<button @click="goto('SecondAbout')">SecondAbout</button></div><router-view /></div>
</template><script>
export default {name: 'App', data () {return {prefix: window.__MICRO_APP_BASE_ROUTE__ || ''}}, methods: {dataListener (data) {if (data.name !== this.$route.name) /** 不判断时会报一个“冗余导航【NavigationDuplicated】”的异常 */this.$router.push({ name: data.name })}, goto (name) {// 向基项目发送数据window.microApp && window.microApp.dispatch({ route: { name } })}},created () {/** 绑定数据【data属性】监听事件 */window.microApp && window.microApp.addDataListener(this.dataListener)}, destroyed () {/** 移除数据【data属性】监听事件 */window.microApp && window.microApp.removeDataListener(this.dataListener)}
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}#nav {padding: 30px;
}#nav a {font-weight: bold;color: #2c3e50;
}#nav a.router-link-exact-active {color: #42b983;
}
</style>
3-8、配置路由
创建router文件夹,配置路由
app_first/src/router/index
import Vue from 'vue'
import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [{path: window.__MICRO_APP_BASE_ROUTE__ || '/' /**根据项目运行的不同环境,设置路径的前缀 */, name: 'Home', redirect: { name: 'FirstHome' }, component: () => import('../views/Empty.vue'), children: [{path: 'home', name: 'FirstHome', component: () => import('../views/Home.vue')}, {path: 'about', name: 'FirstAbout', component: () => import('../views/About.vue')}]}
]const router = new VueRouter({mode: 'history',routes
})export default router
3-9、创建视图(views)
app_first/src/views/About.vue
<template><div class="about"><h1>First Child About Page</h1></div></template>
app_first/src/views/Empty.vue
<template><router-view />
</template>
app_first/src/views/Home.vue
<template><div class="home"><imgalt="Vue logo"src="../assets/logo.png"><h1>First Child Home Page</h1></div>
</template><script>
export default {name: 'Home'
}
</script>
到此app_first就算改造完成了,怀着忐忑的心情运行一下,果然,,,没让我失望,是真的在认真报错。
npm run serve
3-10、报错处理
可以看到有4条错误,先从第一条开始解决吧
bug1:mircro/index.js百度找到要加if条件。就修改了一下,修改完成后就剩3个bug了
if (window.__MICRO_APP_ENVIRONMENT__) {// eslint-disable-next-line__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'}
bug2:从报错可以看出是view命名的问题,需要驼峰命名啥的,应该是eslint引起的,继续百度解决方法
需要在package.json中修改
"vue/multi-word-component-names": 0 // 多字符组件名称,不设置检测
修改完成后继续跑,又报错,没路由,奇怪,我刚刚明明装了路由,有上面的截图 为证,但是就是不见了,可能在修改上面bug的时候百度好多种解决方法,试着试着不小心删掉了吧,既然没了那就重装一下吧。
安装完后又出现了
安装完成后在重新跑,,,耶耶耶耶耶耶,成功了,效果如下图所示,可以看到子应用1的效果:
4、创建app_second(子应用2)
接下来开始修改子应用2,(在上面3-2中已经创建好了子应用2),有了1的辛酸历程后,2的修改应该会很轻松,几乎和1一模一样,虽然我不想在写一遍了。但是既然文章叫手把手教学,那就在啰嗦一遍吧。
4-1、修改vue.config.js
修改vue.config.js文件,设置允许跨域访问,和app_first不同的是端口修改成3002
module.exports = {devServer: {host: 'localhost', port: 3002, headers: { // 设置本地运行的跨域权限'Access-Control-Allow-Origin': '*',}}
}
4-2、micro配置
和基座一样,在src下创建文件夹micro/index.js。不同的是,子应用不需要config.js了
这边已经将子应用1中的bug修改掉,加上了if
app_second/src/micro/index.js
// 设置 webpack 的公共路径
if (window.__MICRO_APP_ENVIRONMENT__) {// eslint-disable-next-line__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'
}
4-3、修改main.js
/**引入 publicPath 设置 */
import './micro'import Vue from 'vue'
import App from './App.vue'
import router from './router'Vue.config.productionTip = false// new Vue({
// router,
// render: function (h) { return h(App) }
// }).$mount('#app')let app/**
* 挂载函数
*/
function mount () {app = new Vue({el: '#app',router,render: function (h) { return h(App) }})
}/**
* 卸载函数
*/
function unmount () {app.$destroy()app.$el.innerHTML = ''app = null
}/**微前端环境下,注册mount和unmount方法 */
if (window.__MICRO_APP_ENVIRONMENT__)window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount }
elsemount()
4-3、安装路由
ctrl+c // 中断app_first的运行
cd .. // 返回上级目录
cd app_second // 1.先进入子应用2目录下
npm install vue-router@3 // 2.安装路由
"rules": {"vue/multi-word-component-names": 0}
4-4、修改App.vue文件
<template><div id="app"><div id="nav"><router-link :to="`${prefix}/home`">子应用2Home</router-link> |<router-link :to="`${prefix}/about`">子应用2About</router-link> |<button @click="goto('SecondHome')">SecondHome</button> |<button @click="goto('SecondAbout')">SecondAbout</button></div><router-view /></div>
</template><script>
export default {name: 'App', data () {return {prefix: window.__MICRO_APP_BASE_ROUTE__ || ''}}, methods: {dataListener (data) {if (data.name !== this.$route.name) /** 不判断时会报一个“冗余导航【NavigationDuplicated】”的异常 */this.$router.push({ name: data.name })}, goto (name) {// 向基项目发送数据window.microApp && window.microApp.dispatch({ route: { name } })}},created () {/** 绑定数据【data属性】监听事件 */window.microApp && window.microApp.addDataListener(this.dataListener)}, destroyed () {/** 移除数据【data属性】监听事件 */window.microApp && window.microApp.removeDataListener(this.dataListener)}
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}#nav {padding: 30px;
}#nav a {font-weight: bold;color: #2c3e50;
}#nav a.router-link-exact-active {color: #42b983;
}
</style>
4-5、配置路由
创建router文件夹,配置路由
app_second/src/router/index
注:这边路由中的name需要修改成Second…,与base中设置的子路由名称保持一致,我这边刚开始搭建的时候就漏掉了,后面在学习代码过程中发现了,又重新做了修改
import Vue from 'vue'
import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [{path: window.__MICRO_APP_BASE_ROUTE__ || '/' /**根据项目运行的不同环境,设置路径的前缀 */, name: 'Home', redirect: { name: 'SecondHome' }, component: () => import('../views/Empty.vue'), children: [{path: 'home', name: 'SecondHome', component: () => import('../views/Home.vue')}, {path: 'about', name: 'SecondAbout', component: () => import('../views/About.vue')}]}
]const router = new VueRouter({mode: 'history',routes
})export default router
4-6、创建视图(views)
app_second/src/views/About.vue
<template><div class="about"><h1>Second Child About Page</h1></div></template>
app_second/src/views/Empty.vue
<template><router-view />
</template>
app_second/src/views/Home.vue
<template><div class="home"><imgalt="Vue logo"src="../assets/logo.png"><h1>Second Child Home Page</h1></div>
</template><script>
export default {name: 'Home'
}
</script>
到此app_second也算改造完了,接下来运行一下
npm run serve
嘿嘿嘿,果然有了1的慢吞吞后,2就快多了,也没让我失望,一下子就成功了,结果如下:
5、运行基座目录
通过前面的操作后,子应用1和子应用2都已经运行出来了,在运行基座目录之前,先解决一下子应用中遇到的那个bug
"rules": {"vue/multi-word-component-names": 0}
改造完成后,就可以运行基座了,当然我发现如果要运行基座,且想在基座中看到子应用,那么两个子应用也要一起运行,所以我在vsCode中开三个终端,将三个都运行了
分别看一下每一个的运行吧:
好了,运行完后,接下来看一下浏览器的显示效果:
总结
我这篇文章写的很啰嗦,如果照着一步步操作应该是不会遇到什么大问题的,因为我这边也是一步步探索出来的结果。纯小白探索,所以如果想搭建micro-app的话,我这篇文章应该很适合小白操作。
当然我也有参考文章,就是参考文章写的没有我这边这么细致,对于新手来说,还是不太友好的。
下一篇micro-app在本文基座上的一些学习笔记
手把手教你使用vue2搭建微前端micro-app相关推荐
- 手把手教你用express搭建个人博客(二)
转自http://www.zhentaoo.com/program/one?id=58a32067aa82ab69510c26be 上篇说到了如何使用express生成器快速生成一个node项目,如果 ...
- 手把手教你使用 VuePress 搭建个人博客
手把手教你使用 VuePress 搭建个人博客 有阅读障碍的同学,可以跳过第一至四节,下载我写好的工具包: git clone https://github.com/zhangyunchencc/vu ...
- 手把手教你用vuepress搭建自己的网站(2)
虽互不曾谋面,但希望能和您成为笔尖下的朋友 以读书,技术,生活为主,偶尔撒点鸡汤 不作,不敷衍,意在真诚吐露,用心分享 点击左上方,可关注本刊 标星公众号(ID:itclanCoder) 如果不知道如 ...
- 手把手教你用owncloud搭建属于自己的云盘
https://www.jianshu.com/p/6e0be77b688e 手把手教你用owncloud搭建属于自己的云盘 owncloud是一个开源的云盘解决方案,我们可以用owncloud快速地 ...
- 方言听不懂,手把手教你用 Milvus 搭建方言翻译器!
坐在上海的公交车上,我有时会遇到这样的烦恼:稍一分神,没能听见普通话报站,支棱起耳朵,却听不懂沪语报站.为了解决这个问题,我决定--学习沪语?No, 作为一名数据工程师,我索性搭建了一个方言翻译器,帮 ...
- maven hibernat mysql_手把手教你用 maven 搭建 SSH (struts2 +hibernate5 + spring5) 项目
手把手教你搭建 SSH 环境 一.项目环境搭建 1.1 配置 Spring 坐标依赖 1.2 配置 hibernate 坐标依赖 1.3 配置 struts2 坐标依赖 1.4 配置Java EE 坐 ...
- 手把手教你36小时搭建无人超市系统 !(附代码)
来源:QbitAI 编译:夏乙 问耕 本文经AI新媒体量子位(公众号ID:qbitai )授权转载,转载请联系出处 本文共1635字,建议阅读5分钟. 本文手把手教大家用代码工具搭建亚马逊无人商店. ...
- 手把手教你通过vue-cli搭建手机端框架
前言:欢迎前端的小伙伴们前来围观.学习借鉴,如果你是后端.测试和其他的小伙伴也没关系,如果自己也想玩一下前端,想搭建一个前端的框架,那么不妨静下心来看看这篇文章.如果你不是从事开发工作的人员,内容可能 ...
- 手把手教你使用hexo搭建属于你的个人博客
前言 每当看到别人精美的个人博客时,不知你是否有一点点的羡慕.别急,现在我就来手把手教你搭建自己的个人博客. 在技术日趋成熟的今天,有着很多种快速生成博客的框架:Hexo,Jekyll,Wordpre ...
最新文章
- 4、自定义部分国家语言代号对照表
- Windows Phone 二、WP控件
- [原创]Android Monkey测试工具使用介绍
- 无源定位之时差估计的精确时差估计算法(ETDE)及MATLAB实现程序
- 如何利用计算机做主题模型,利用概率主题模型的微博热点话题发现方法-计算机系统应用.PDF...
- UEFI+GPT安装Windows8和CentOS双系统
- TIOBE 6月编程语言排行榜:Python势不可挡
- StyleGAN如何定制人脸生成
- Python+VSCode是我的心头爱,飞一般的Coding体验!
- IDEA/Eclipse安装 Alibaba Java Coding Guidelines 插件
- 【原】Eclipse部署Maven web项目到tomcat服务器时,没有将lib下的jar复制过去的解决办法...
- qt 访问共享文件夹_怎样用IP访问局域网共享文件
- 海德也离开了,祝你一路顺风。
- 如何让novnc/websockify支持tls1.2 (by quqi99)
- mysql使用delete from where in 删除时报错如何解决
- 了解一下iframe页面嵌入使用,轻松实现页面集成
- P3084 [USACO13OPEN]照片Photo
- 《良乔说软件》第一回 问君情深深几许?我的眼里只有你
- windows 2003 删除一键恢复EISA
- 【硬核干货】4500字、10个案例分享几个Python可视化小技巧,助你绘制高质量图表...