Copyright notice: This article is originally published BY the blogger. It follows the COPYRIGHT agreement CC 4.0 BY-SA. Please attach the link of the original source and this statement. This paper links: gudepeng. Making. IO/note / 2020/0…
1. Previous information
The last post has talked about what is micro front-end, students who are not familiar with the micro front-end architecture design and practice: Origin of this case will continue to update into an open source management project, welcome star, if you need support and need new features can contact me at the project address: github.com/gudepeng/vu… Official link: github.com/umijs/qiank… Versions and methods after qiankun2.0 are used in this paper
2. The actual combat
1. Create projects
Since both the main project and the sub-project are developed using VUE, create the project using VUE-cli4. Create 2 projects, one main project and one sub-project.
npm install -g @vue/cli @vue/cli-service-global
vue create vue-giant-master
vue create vue-giant-module
Copy the code
2. Main project preparation
Now I will start to write the project normally. I have seen many demo and actual projects on the Internet before, and everyone’s main project is directly put the universe code in the main. Then use V-if in app.vue to control whether the route is displayed or the loaded subproject is displayed. Because it is a background management project, in my actual project development, there are many routing pages of the main project, so I feel that this way is not very convenient. So I used the normal VUE project to start and then loaded the code of Qiankun on the home page after login. Here is the implementation.
<template>
<div class="panel" @click="doOnWeb" @keydown="doOnWeb">
<top-header class="panel-heder"></top-header>
<div class="panel-main"> <! --> <router-view v-if="showView" />
<div v-else id="root-view"></div>
</div>
<main-menu ref="mainMenu" class="main-menu" v-show="showMenu"></main-menu>
<main-login ref="mainLogin"></main-login>
</div>
</template>
<script>
import TopHeader from '@/layout/components/Header'
import MainMenu from '@/layout/components/Menu'
import MainLogin from '@/layout/components/MainLogin'Import {registerMicroApps, start} from'qiankun'
import axios from '@/utils/request'
export default {
name: 'Layout',
components: {
TopHeader,
MainMenu,
MainLogin
},
data() {
return {
showMenu: false
}
},
computed: {
showView: function() {
return this.$route.path === '/home'}},mounted() {// Define the data, methods, and components passed into the child application const MSG = {data: this.$store.getters,
fns: [],
prototype: [{ name: '$axios', value: axios}]} registerMicroApps([{name: axios}]})'module-app1',
entry: '//localhost:8081',
container: '#root-view',
activeRule: '/app1',
props: msg
},
{
name: 'module-app2',
entry: '//localhost:8082',
container: '#root-view',
activeRule: '/app2',
props: msg
}
],
{
beforeLoad: [
app => {
console.log('before load', app)
}
],
beforeMount: [
app => {
console.log('before mount', app)
}
],
afterUnmount: [
app => {
console.log('after unload', app)}]}) // start({prefetch:true })
},
methods: {
toggleMenu() { this.showMenu = ! this.showMenu this.$refs['mainMenu'].showTwoMenu = false
},
doOnWeb() {
this.$refs.mainLogin.doOnWeb()
}
}
}
</script>
Copy the code
By doing so, you can make a good distinction between subprojects and main project loads. There can also be common deployment displays (such as Menu and title)
Pay attention to the implementation
PushState () {if (# rootview) {if (# rootview) {if (# rootview) {if (# rootview) {if (# rootview) {if (# rootview) {if (# rootview) {if (# rootview) { The Qiankun will report an error and will not load when jumping to the sub-project page.
2. At the time of transmission method to the component or components, do not use/function array directly within the method of direct way, because in the actual deployment package when the method name can be webpack packing compression, receive the name of the method in the component will be wrong, component to invoke additional qualifications purpose method would find this method.
3. When passing data, this article uses the getter for passing store, and then the subproject receives the initial store of the subproject at the appropriate time. When the value of the main item changed, the initGlobalState provided by Qiankun was used to transfer the value (in the version of Qiankun 1.x, the communication after loading the sub-item was not supported. I used the window event to transfer the value). Update to store in subproject.
I have also tried to pass store directly to the subproject, and it will, so that the main project and the subproject act as public stores, but the pages in the subproject don’t listen for store changes. You need to manually use $forceUpdate(). I have taken a look at vuex’s source code. It seems that it is because he only created a monitoring of DOM changes. I haven’t looked into the details yet, and I will make a detailed investigation later.
The design of the router
import router from '.. /router'
import store from '.. /store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getUserToken } from '@/utils/user'
import Layout from '@/layout/index.vue'
NProgress.configure({
showSpinner: false
})
router.beforeEach(async (to, from, next) => {
NProgress.start()
const hasToken = getUserToken()
if (hasToken) {
if (to.path === '/login') {
next({
path: '/home'
})
NProgress.done()
} else {
const isLogin = store.getters.userInfo
if (isLogin) {
next()
} else{try {// Add to router permission await store.dispatch('user/getUserInfo')
router.addRoutes([
{
path: '/',
name: 'Layout',
component: Layout,
children: [
{
path: 'app1*'} ] } ]) next({ ... to, replace:true
})
} catch (error) {
Message.error(error || 'Has Error') next(`/login? redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
if (to.path === '/login') {
next()
NProgress.done()
} else {
next({
path: '/login'
})
}
}
})
router.afterEach(() => {
NProgress.done()
})
Copy the code
If the user does not log in, the user will be intercepted to the login page. If the user has logged in, it will determine whether the user has obtained the permission. If the user has not obtained the permission, it will obtain the permission, and then add the route of the corresponding subproject to the router. Since my subproject page is under the layout page, I need to add the corresponding permissions for any subproject that I don’t have
router.addRoutes([
{
path: '/',
name: 'Layout',
component: Layout,
children: [
{
path: 'app1*'}}]])Copy the code
Subproject writing
The subproject is just a normal Vue project, with methods and components received in main.js mounted to vue.prototype and data received initialized to store.
import './public-path'
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
import '@/utils/permission.js'
Vue.config.productionTip = false
let instance = null
export async function bootstrap({ prototype }) {
prototype.map(p => {
Vue.prototype[p.name] = p.value
})
}
function initStore(props) {
props.onGlobalStateChange && props.onGlobalStateChange((value, prev) => {})
props.setGlobalState &&
props.setGlobalState({
ignore: props.name,
user: {
name: props.name
}
})
}
function render(props = {}) {
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')}export async function mount(props) {
initStore(props)
if (props.data.userInfo.roles) {
store.commit('permission/SET_ROLES', props.data.userInfo.roles)
}
render()
}
export async function unmount() {
instance.$destroy()
instance = null
}
if(! window.__POWERED_BY_QIANKUN__) { render() }Copy the code
You need to create public-path.js in the parent directory of main.js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
Copy the code
The design of the router
The master project has passed permissions to its subprojects. When initializing the route, you only need permission to load the route of the object
import router from '@/router'
import store from '@/store'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
NProgress.configure({ showSpinner: false })
router.beforeEach(async (to, from, next) => {
NProgress.start()
const hasRoles = store.getters.routes && store.getters.routes.length > 0
if (hasRoles) {
next()
} else {
// get user info
const roles = await store.state.permission.roles
const accessRoutes = await store.dispatch(
'permission/generateRoutes', roles ) router.addRoutes(accessRoutes) next({ ... to, replace:true })
}
})
router.afterEach(() => {
NProgress.done()
})
Copy the code
Vue. Config. Js
You need to add the output of the file to it
output: {
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`}Copy the code
Subprojects need to support cross-domain, so they need to be added
headers: {
'Access-Control-Allow-Origin': The '*'
}
Copy the code
other
The above is the core code of the whole project, the other part is the development method of the specific VUE project, this article will not elaborate. For example, if the user does not operate for a period of time, the dialog and menu of login will pop up