參考:html
答:不是,只須要安裝在主框架便可,子框架不須要引入
安裝 qiankun前端
yarn add qiankun
或者 npm i qiankun -S
vue
配置微應用webpack
// /src/micro/apps.js const apps = [ { name: 'planResource', entry: '//localhost:8083', container: '#iframe', activeRule: '/plan' }, { name: 'configration', entry: '//localhost:8081', container: '#iframe', activeRule: '/configure' } ]; export default apps;
在主應用中註冊微應用web
// src/micro/index.js import { registerMicroApps, addGlobalUncaughtErrorHandler, start } from 'qiankun'; import apps from './apps'; // registerMicroApps 第二個參數能夠不要,若是要作點啥,就寫到對應的地方 registerMicroApps(apps, { beforeLoad: [ app => { console.log('[LifeCycle] before load %c%s', 'color: green;', app.name); }, ], beforeMount: [ app => { console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name); }, ], afterUnmount: [ app => { console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name); }, ], },); // 出錯時顯示的內容 addGlobalUncaughtErrorHandler((event) => { // console.log(event); const { message } = event; if (message && message.includes('died in status LOADING_SOURCE_CODE')) { console.log('微應用加載失敗,請檢查應用是否可運行'); } }); export default start;
使用 startvue-router
// /src/main.js import microApp from './micro'; new Vue({ router, store, render: (h) => h(App) }).$mount('#app'); microApp();
注意:vuex
<font color=orange>不必定要放在入口文件內,看你的項目而定</font>npm
- 若是你的微應用容器在index.html裏的話,是沒有多大問題,
可是不少時候是嵌入在Layout框架裏的,正常進入是沒有問題,若是是在微應用路徑下刷新頁面,會有以下圖片的報錯json
<font color=red>Uncaught Error: application 'cloud' died in status LOADING_SOURCE_CODE: [qiankun] Target container with #cloud not existed while cloud loading!</font>bootstrap
這種狀況下建議在改組件的mounted事件鉤子下start, main.js下引入,不執行便可
eg:
//main.js ... import microApp from './micro' // 加載乾坤app microApp // 註冊應用 // 包含子應用容器的VUE組件 <template> <div class="vab-app-main"> <section> <transition mode="out-in" name="fade-transform"> <vab-keep-alive v-if="routerView" /> </transition> <div id="cloud"></div> <div id="vue3"></div> </section> <vab-footer /> </div> </template> <script> ... import { start } from 'qiankun' export default { name: 'VabAppMain', data() { return { ... } }, ... mounted() { start({ prefetch: false, // 取消預加載 }) // 開啓 }, ... } </script>
修改webpack配置
// webpack.config.js || vue.config.js const port = 8088; const packageName = require("./package.json").name; module.exports = { lintOnSave: false, // 關閉eslint檢測 devServer: { port, // 這裏的端口是必須和父應用配置的子應用端口一致 disableHostCheck: false, // 關閉主機檢查,保證子應用能夠被主應用fetch到 headers: { //由於qiankun內部請求都是fetch來請求資源,因此子應用必須容許跨域 "Access-Control-Allow-Origin": "*", }, }, configureWebpack: { output: { //資源打包路徑 library: `${packageName}`, libraryTarget: "umd", jsonpFunction: `webpackJsonp_${packageName}`, // publicPath: `//localhost:${port}`, }, }, // outputDir: 'dist', // assetsDir: 'static', // filenameHashing: true, };
增長 public-path配置文件並在入口文件引入
// /src/micro/public-path.js if (window.__POWERED_BY_QIANKUN__) { // eslint-disable-next-line no-undef __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } // /src/main.js import '@/micro/public-path'
路由實例化配置
// src/router/index.js import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: () => import('../views/Home.vue') }, { path: '/about', name: 'About', component: () => import('../views/About.vue') } ] const router = new VueRouter({ mode: 'history', // @ts-ignore base: window.__POWERED_BY_QIANKUN__ ? '/cloud' : '/', // 獨立運行是用"/"做爲根路徑 // base: '/cloud', routes }) export default router
Vue實例化包裝和生命週期鉤子導出
// /src/main.js import "@/micro/public-path"; import Vue from "vue"; import App from "./App.vue"; import actions from "./micro/actions.js"; import router from "./router"; import store from "./sotre"; let instance = null; function render(props = {}) { // 通過實踐這個判斷要有,否則在獨立運行時報錯 if (window.__POWERED_BY_QIANKUN__) { if (props) { actions.setActions(props); actions.onGlobalStateChange((state) => { console.log("app1", state); }, true); } } const { container } = props; // 這裏是掛載到本身的html中 基座會拿到這個掛載後的html 將其插入進去 const renderContainer = container ? container.querySelector("#app") : "#app"; instance = new Vue({ router, store, render: (h) => h(App), }).$mount(renderContainer); } // @ts-ignore if (!window.__POWERED_BY_QIANKUN__) { // 默認獨立運行 render(); } // 父應用加載子應用,子應用必須暴露三個接口:bootstrap、mount、unmount export async function bootstrap() { console.log("cloud app bootstraped"); } export async function mount(props) { console.log("mount"); render(props); } export async function unmount() { console.log("unmount"); instance.$destroy(); }
props 傳值不夠靈活,不推薦使用
<font color=red>Actions</font>推薦使用方法,能夠在狀態改變時觸發
// /src/micro/actions.js import { initGlobalState } from 'qiankun'; const initState = {}; const actions = initGlobalState(initState); export default actions;
// /src/app.vue <template> <div id="app"> <router-view /> </div> </template> <script> import actions from '@/micro/actions' export default { name: 'App', computed: { visitedRoutes() { return this.$store.state.tabs.visitedRoutes //須要監聽的數據 }, }, watch: { visitedRoutes(newVal, oldVal) { this.setGlobalState() }, }, created() { // this.setGlobalState() }, methods: { setGlobalState() { let data = { time: this.$store.state.user.time, token: this.$store.state.user.token, ability: this.$store.state.acl, routes: this.$store.state.routes, tabs: this.$store.state.tabs.visitedRoutes, } actions.setGlobalState(data) }, }, } </script>
注意:
<font color=orange>能夠監聽vuex數據,若是變化,執行setGlobalState</font>
// /src/micro/actions.js function emptyAction() { // 警告:提示當前使用的是空 Action console.warn('Current execute action is empty!'); } class Actions { // 默認值爲空 Action actions = { onGlobalStateChange: emptyAction, setGlobalState: emptyAction }; /** * 設置 actions */ setActions(actions) { this.actions = actions; } /** * 映射 */ onGlobalStateChange(...args) { return this.actions.onGlobalStateChange(...args); } /** * 映射 */ setGlobalState(...args) { return this.actions.setGlobalState(...args); } } const actions = new Actions(); export default actions;
// /src/main.js import "@/micro/public-path"; import Vue from "vue"; import App from "./App.vue"; import actions from "./micro/actions.js"; import router from "./router"; import store from "./sotre"; let instance = null; function render(props = {}) { // @ts-ignore if (window.__POWERED_BY_QIANKUN__) { if (props) { actions.setActions(props); actions.onGlobalStateChange((state) => { console.log("app1", state); const { token, ability, tabs } = state; store.state.ability = ability store.state.token = token store.state.tabs = tabs }, true); } } const { container } = props; // 這裏是掛載到本身的html中 基座會拿到這個掛載後的html 將其插入進去 const renderContainer = container ? container.querySelector("#app") : "#app"; instance = new Vue({ router, store, render: (h) => h(App), }).$mount(renderContainer); } // @ts-ignore if (!window.__POWERED_BY_QIANKUN__) { // 默認獨立運行 render(); } // 父應用加載子應用,子應用必須暴露三個接口:bootstrap、mount、unmount export async function bootstrap() { console.log("cloud app bootstraped"); } export async function mount(props) { console.log("mount"); render(props); } export async function unmount() { console.log("unmount"); instance.$destroy(); }
若是基座和子應用使用的都是VUE,要使用devtools是比較老火的事情:
- 若是使用的devtools 5.xx 的版本,那麼只能查看主框架的數據
- 若是使用devtools 6.xx(目前只有bata版本),且基座和子應用使用不一樣的VUE版本,那麼能夠查看對應應用的數據,<font color=orange>但是開發開發工具會不停的報錯,蛋痛</font>
建議:基座框架和子框架使用不一樣的框架語言開發(這樣是否要好一些,或者有解決的辦法)
很重要:否則首次是拿不到值的哦
參考傳值Actions 主應用下的設置 監聽vuex