最近公司要整合目前所有的前端项目,希望放到同一个项目里面进行管理,但是项目使用的技术栈大体不相同,有原生js的,有用jq的也有用Vue的,整合的话要么重构,统一技术栈,不过这是不现实的,成本高,时间长,要么使用iframe,但是iframe也有很多缺点,通信不方便,刷新页面会导致路由丢失,这都是很不好的体验,于是我想起了最近很火的微前端概念,打算用微前端的技术来整合已有项目。
yarn add qiankun 或者 npm i qiankun -S
安装完qiankun后我们在创建主应用,也是我们的基座
vue create qiankun-base
接着创建vue子应用
vue create qiankun-vue
接着创建react子应用
cnpm install -g create-react-app
create-react-app my-app
创建好后的目录如下,qiankun-js忽略
项目创建好后我们首先进行主应用qiankun-base的配置,进入man.js文件进行配置, 在main.js中加入以下代码,要注意的是,entry这项配置是我们两个子项目的域名和端口,我们必须确保两字子项目运行在这两个端口上面,container就是我们的容器名,就是我们子应用挂载的节点,相当于Vue项目里面的app节点,activeRule就是我们的激活路径,根据路径来显示不同的子应用。
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'vueApp', // 应用的名字
entry: '//localhost:8021',// 默认会加载这个html 解析里面的js 动态的执行 (子应用必须支持跨域)fetch
container: '#vue', // 容器名
activeRule: '/vue',// 激活的路径
},
{
name: 'reactApp',
entry: '//localhost:8020',
container: '#react',
activeRule: '/react',
},
]);
start();
配置完之后我们去到qiankun-base的app.vue文件进行主应用的页面编写,这里我安装了element-ui来进行页面美化,大家可以安装一下,
npm i element-ui -S
修改app.vue的组件代码如下
Home
vue应用
react应用
大家可以看到,在elementui的路由导航模式下,菜单子元素的index就是要跳转的路径,这个路径和我们刚刚在main.js编写activeRule是一致,子应用的切换就是根据这里的index进行监听。
接下来我们进行router的配置
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
我们运行一下qiankun-base
npm run serve
目前页面除了菜单是没有其他东西的,点击也是没有效果的,因为我们还没配置子应用,现在我们来配置子应用
打开qiankun-vue目录, 在子Vue应用的main.js中加入以下代码
import Vue from 'vue'
import App from './App.vue'
import router from './router'
let instance = null;
//挂载实例
function render(){
instance = new Vue({ router, render: h => h(App) }).$mount('#app')
}
//判断当前运行环境是独立运行的还是在父应用里面进行运行,配置全局的公共资源路径
if(window.__POWERED_BY_QIANKUN__){
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
//如果是独立运行window.__POWERED_BY_QIANKUN__=undefined
if(!window.__POWERED_BY_QIANKUN__){
render()
}
//最后暴露的三个方法是固定的,加载渲染以及销毁
export async function bootstrap(){}
export async function mount(props){
render();
}
export async function unmount(){
instance.$destroy();
}
配置完main.js后我们继续配置基础配置模块,我们在子Vue应用的根目录下面新建一个Vue.config.js文件
module.exports = {
devServer:{
port:10000,//这里的端口是必须和父应用配置的子应用端口一致
headers:{
//因为qiankun内部请求都是fetch来请求资源,所以子应用必须允许跨域
'Access-Control-Allow-Origin':'*'
}
},
configureWebpack:{
output:{
//资源打包路径
library:'vueApp',
libraryTarget:'umd'
}
}
}
接下里再进行router的配置
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: '/vue',
routes
})
export default router
这三步就已经把子应用配置好了,接下来我们再进行子React应用的配置。
重写子React的src目录下的index.js文件,如下
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
function render(){
ReactDOM.render(
,
document.getElementById('root')
);
}
if(!window.__POWERED_BY_QIANKUN__){
render();
}
export async function bootstrap(){
}
export async function mount() {
render()
}
export async function unmount(){
ReactDOM.unmountComponentAtNode( document.getElementById('root'));
}
再进行dev以及打包的配置,根目录下面的config-overrides.js
module.exports = {
webpack:(config)=>{
config.output.library = 'reactApp';
config.output.libraryTarget = 'umd';
config.output.publicPath = 'http://localhost:20000/';
return config;
},
devServer:(configFunction)=>{
return function (proxy,allowedHost){
const config = configFunction(proxy,allowedHost);
config.headers = {
"Access-Control-Allow-Origin":'*'
}
return config
}
}
}
子React的基础配置和子Vue基本相同,在这里我们就算是配置完了,接下来我们看看结果如何,启动主应用以及两个子应用
上面是我录制的一个gif,可以看到我们的微前端实践已经成功了,点击相应的菜单可以跳转到对应的子应用,并且子应用内的路由是不会受影响的。还有一个需要注意的是,我们的应用路由模式要用history模式,没有的要去router文件里面定义
const router = new VueRouter({
mode: 'history',
base: '/vue',
routes
})
那么今天的微前端的分享就到这里了,我可能讲得不太好,希望对大家有用,更加详细的教程和相关问题解答可以上官网
https://qiankun.umijs.org/zh
最后附上例子的源码地址, https://github.com/DJYang666/qiankun.git,喜欢的多多关注哦