参考文档:

qiankun官方文档      csdn文档1  csdn文档2    github地址

umi-qiankun 的教程请移步 umi 官网 和 umi-qiankun 的官方 demo

一、过程

1.使用vue-cli创建主应用

vue create qiankun-main

选择2.x版本,选择eslint等等配置,完成后初始化并启动项目。vue-cli建的项目vue版本是2.6,所以不要用ts。路由需要是history模式。

遇到错误:关于使用vue create创建项目的时候出现了 command failed: pnpm install --reporter silent --shamefully-hoist 报错

2.主应用需要安装qiankun插件

npm i qiankun -S

3.配置些简单的eslint 和 prettierrc规则

注意  "vue/multi-word-component-names": "off",  要添加,否则创建view下其他vue文件如index.vue时会报错。

// in .eslintrc.jsmodule.exports = {root: true,env: {node: true,},extends: ["plugin:vue/essential",// "plugin:prettier/recommended",  // 还没配置prettier就先注释掉],parserOptions: {parser: "@babel/eslint-parser",ecmaVersion: 2020,},rules: {"no-console": process.env.NODE_ENV === "production" ? "warn" : "off","no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",},overrides: [{files: ["*.vue"], // 匹配views和二级目录中的index.vuerules: {"vue/multi-word-component-names": "off",}, //给上面匹配的文件指定规则},],
};
// in .prettierrc.jsmodule.exports = {// 一行最多 120 字符..printWidth: 120,// 使用 2 个空格缩进tabWidth: 2,// 不使用缩进符,而使用空格useTabs: false,// 行尾需要有分号semi: true,// 使用单引号singleQuote: true,// 对象的 key 仅在必要时用引号quoteProps: 'as-needed',// jsx 不使用单引号,而使用双引号jsxSingleQuote: false,// 末尾需要有逗号trailingComma: 'all',// 大括号内的首尾需要空格bracketSpacing: true,// jsx 标签的反尖括号需要换行jsxBracketSameLine: false,// 箭头函数,只有一个参数的时候,也需要括号arrowParens: 'always',// 每个文件格式化的范围是文件的全部内容rangeStart: 0,rangeEnd: Infinity,// 不需要写文件开头的 @prettierrequirePragma: false,// 不需要自动在文件开头插入 @prettierinsertPragma: false,// 使用默认的折行标准proseWrap: 'preserve',// 根据显示样式决定 html 要不要折行htmlWhitespaceSensitivity: 'css',// vue 文件中的 script 和 style 内不用缩进vueIndentScriptAndStyle: false,// 换行符使用 lfendOfLine: 'lf',
};

4.配置新路由

删除无用代码比如HomeView.vue等文件,重新配置路由。

配置些简单的路由:

// in src/router/index.tsimport Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/home/index.vue";Vue.use(VueRouter);const routes = [{path: "/",name: "home",component: Home,},{path: "/about",name: "about",component: () => import("../views/about/index.vue"),},
];const router = new VueRouter({mode: "history",base: process.env.BASE_URL,routes,
});export default router;

5.编写存放微应用的区域

参考上方文档1。定义子应用的加载位置,如 id 为 root-view 的一个盒子。

我选择在 src/app.vue 中存放:

<template><div id="app"><nav><router-link to="/home">Home</router-link> |<router-link to="/about">About</router-link> |<router-link to="/app1">app1</router-link></nav><router-view /><div class="app-content"><!-- 微应用所在 --><div id="root-view"></div></div></div>
</template><style lang="scss">
#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;a {font-weight: bold;color: #2c3e50;&.router-link-exact-active {color: #42b983;}}
}
</style>

其中子应用就是存放在 <div id="root-view"></div> 中。id 为 root-view 对应第六点 microApps 中的配置 container 项,将子应用挂载到 id="root-view" 的 div 中。

6. 注册微应用并启动

可以上方参考官方文档项目实践部分,或者文档1实战部分

src下新建modules文件夹,里面新建micro-app.js。 这是注册微应用的代码。

// in src/modules/micro-app.js// 在主应用中注册微应用    各子应用信息如下
const microApps = [{name: "module-app1", // name都不能重复entry: "http://localhost:8081", // 定义子应用入口,基于qiankun的应用一般直接写子应用的入口html地址即可。activeRule: "/app1", // url变化后, 所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中。要和子项目中配置的拦截到对应子项目的标识保持一致(  base: window.__POWERED_BY_QIANKUN__ ? '/app1/' : '/',)。container: "#root-view", // 定义子应用的加载位置,如 id为root-view的一个盒子sandbox: {strictStyleIsolation: true, // 开启样式隔离},},// {//   name: "module-app2",//   entry: "http://localhost:8082",//   activeRule: "/app2",//   container: "#root-view",//   sandbox: {//     strictStyleIsolation: true, // 开启样式隔离//   },// },];export default microApps;

导出了一个子应用数组,会作为参数传入到注册函数registerMicroApps中。

启动:

在  src/main.js  页添加相应代码:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import microApps from '../src/modules/micro-app';
// // 引入qiankun注册子应用和启动的接口函数
import { registerMicroApps, start } from 'qiankun';Vue.config.productionTip = false;new Vue({router,store,render: (h) => h(App),
}).$mount("#app");// 引入微应用入口配置
registerMicroApps(microApps, {// 注册一些全局生命周期钩子,如进行日志打印,如果不需要可以不传beforeMount() {console.log(21, "qiankun-beforeMount");},
});
// 启动qiankun,并开启预加载
start({prefetch: true,sandbox: {strictStyleIsolation: true, // 开启样式隔离},
});

注意: start() 中 strictStyleIsolation: true 开启严格的样式隔离模式,这种模式下 qiankun 会为每个微应用的容器包裹上一个 shadow dom 节点,从而确保微应用的样式不会对全局造成影响。即使主子应用页面样式都没 scoped 也互不影响。(详见官网)。

隔离前页面结构为:

隔离之后页面结构为(可见多了一个Shadow root 节点, 是Shadow tree 的根节点):

7.在vue.config.js文件添加反向代理配置

const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({transpileDependencies: true,lintOnSave: false,//反向代理devServer: {// 环境配置host: "0.0.0.0",port: 8080,https: false,// hotOnly: false,open: false, //配置自动启动浏览器proxy: {// 配置多个代理(配置一个 proxy: 'http://localhost:4000' )// "/service": {//     target: `http://172.16.21.153:6081/`,// },},},
});

8.在微应用进行相应配置:

参考官方文档:

①在 src 目录新增  public-path.js 文件

// 在qiankun环境下,修正加载路径
if (window.__POWERED_BY_QIANKUN__) {// eslint-disable-next-line no-undef__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

②入口文件 main.js 修改:

import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import routes from './router';
import store from './store';Vue.config.productionTip = false;let router = null;
let instance = null;
function render(props = {}) {console.log();const { container } = props;router = new VueRouter({base: window.__POWERED_BY_QIANKUN__ ? '/app1/' : '/',mode: 'history',routes,});instance = new Vue({router,store,render: (h) => h(App),}).$mount(container ? container.querySelector('#app') : '#app');
}// 独立运行时(在非qiankun环境下,直接执行渲染)
if (!window.__POWERED_BY_QIANKUN__) {render();
}/*** ootstrap引导函数* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。*/
export async function bootstrap() {console.log('[vue] vue app bootstraped');
}/*** 挂载函数* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法*/
export async function mount(props) {console.log('[vue] props from main framework', props);render(props);
}/*** 卸载函数* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例*/
export async function unmount() {instance.$destroy();instance.$el.innerHTML = '';instance = null;router = null;
}
/*** 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效*/
export async function update(props) {console.log('update props', props);
}

注意,要修改 src/router/index.ts 文件,此时该文件导出的应该是路由信息数组:

import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/home/index.vue";
import About from "../views/about/index.vue";Vue.use(VueRouter);const routes = [{path: "/",name: "home",component: Home,},{path: "/about",name: "about",// component: () => import("../views/about/index.vue"),component: About,},
];// const router = new VueRouter({
//   mode: "history",
//   base: process.env.BASE_URL,
//   routes,
// });export default routes;

否则会报错:Uncaught TypeError: routes.forEach is not a function。

注意作为子应用,其页面不能懒加载,不要这样写:  // component: () => import("../views/about/index.vue")。否则进入到该页面后报错ChunkLoadError: Loading chunk src_views_about_index_vue failed.

别忘记做第四点。

③ 打包配置修改(vue.config.js):

const { defineConfig } = require("@vue/cli-service");
const { name } = require('./package');
module.exports = defineConfig({transpileDependencies: true,lintOnSave: false,devServer: {port: 8081, // 与注册的微应用的entry地址端口号一致headers: {'Access-Control-Allow-Origin': '*'}},configureWebpack: {output: {library: `${name}-[name]`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式chunkLoadingGlobal: `webpackJsonp_${name}`,},},
});

注意:官方文档里是jsonpFunction: `webpackJsonp_${name}`,。这样会报错:

搜索 报错 configuration has an unknown property ‘jsonpFunction‘ ,见文档。

webpack  在2020-10-10发布的webpack 5中已将 output.jsonpFunction 更名为 output.chunkLoadingGlobal 。所以要把 jsonpFunction 改为 chunkLoadingGlobal 。

④ 注意要配置第三点,别忘了 libraryTarget ,否则报跨域的错和 TypeError: application 'module-app1' died in status LOADING_SOURCE_CODE: Failed to fetch。

参考文档1   参考文档2

9.同时启动主应用和微应用

成功如下:

10.qiankun- 应用间的通讯

参考文档1   参考文档2

使用官方提供的应用间通信方式 - Actions 通信

qiankun 内部提供了 initGlobalState 方法用于注册 MicroAppStateActions 实例用于通信,该实例有三个方法,分别是:

setGlobalState:设置 globalState - 设置新的值时,内部将执行 浅检查,如果检到 globalState 发生改变则触发通知,通知到所有的 观察者 函数。
        onGlobalStateChange:注册 观察者 函数 - 响应 globalState 变化,在 globalState 发生改变时触发该 观察者 函数。
        offGlobalStateChange:取消 观察者 函数 - 该实例不再响应 globalState 变化。

​​​​​​这几个函数的文档

实践步骤:

1. 在主应用的 src目录下新建 actions 文件夹,里面新建index.js文件,用于写入initGlobalState函数

// in src\actions\index.jsimport { initGlobalState } from "qiankun";
// import store from '../store';const initialState = {//这里写初始化数据test: "测试",mes2: 0,app1Msg: 0, // 子应用app1的数据
};// 初始化 state
const actions = initGlobalState(initialState);
actions.onGlobalStateChange((state, prev) => {//监听公共状态的变化console.log("主应用: 变更前");console.log(prev);console.log("主应用: 变更后");console.log(state);// store.commit('setProject', state); // 这里可以把公共状态存到主应用的vuex里了
});export default actions;

导出了actions对象,里面有三个通信方法。

2.在主应用的组件中使用actions

在一个挂载了子应用的页面中:

// in src\views\app1\index.vue<template><div class="app1"><div style="margin-bottom: 40px"><p>本主应用消息1:{{ mes1 }}</p><button @click="sendMes1">点击向子应用发送消息1</button></div><div><p>本主应用消息2:{{ mes2 }}</p><button @click="sendMes2">点击向子应用发送消息2</button></div><p>接收到的消息:{{ app1Msg }}</p></div>
</template><script setup>
import { ref, onMounted } from "vue";
import actions from "../../actions";const mes1 = ref(""); // 有vuex等状态管理的话可以设置为vuex里的值,并在vuex中用actions.onGlobalStateChange和store.commit改变相应的值
const mes2 = ref(0);
const app1Msg = ref(0);
const sendMes1 = () => {mes1.value += 1;actions.setGlobalState({ test: mes1.value }); //通过setGlobalState改变全局状态
};const sendMes2 = () => {mes2.value += 1;actions.setGlobalState({ mes2: mes2.value }); //通过setGlobalState改变全局状态
};// 数据要存入vuex的话可以在src\actions\index.js中进行监听并用store.commit改变相应的值
actions.onGlobalStateChange((state, prev) => {console.log(31, "主应用监听子应用发来的信息", state, prev);if (state.app1Msg !== prev.app1Msg) {app1Msg.value = state.app1Msg;}
}, true);
onMounted(() => {console.log(10, "主应用app1地址");
});
</script>

改变数据时触发actions.setGlobalState函数,监听数据变化时触发了actions.onGlobalStateChange函数。数据要存入vuex的话也可以在src\actions\index.js中进行监听并用store.commit改变相应的值(见注释)。

3.在子应用的 src目录下新建 actions 文件夹,里面新建index.js文件,用于写入actions实例,此实例将用于存入主应用返回的props和通信方法:

// in src\actions\index.jsfunction emptyAction() {// 设置一个actions实例// 提示当前使用的是空 Actionconsole.warn('Current execute action is empty!');
}class Actions {// 默认值为空 Actionactions = {onGlobalStateChange: emptyAction,setGlobalState: emptyAction,};/*** 设置 actions*/setActions(actions) {this.actions = actions;}/*** 映射*/onGlobalStateChange(...args) {this.actions.onGlobalStateChange(...args);return;}/*** 映射*/setGlobalState(...args) {this.actions.setGlobalState(...args);return;}
}const actions = new Actions();
export default actions;

4.在子应用的main.js的mounted的生命周期里注入actions实例

import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import routes from './router';
import store from './store';
import actions from './actions';Vue.config.productionTip = false;let router = null;
let instance = null;
function render(props = {}) {const { container } = props;router = new VueRouter({base: window.__POWERED_BY_QIANKUN__ ? '/app1/' : '/',mode: 'history',routes,});instance = new Vue({router,store,render: (h) => h(App),}).$mount(container ? container.querySelector('#app') : '#app');
}// 独立运行时(在非qiankun环境下,直接执行渲染)
if (!window.__POWERED_BY_QIANKUN__) {render();
}/*** ootstrap引导函数* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。*/
export async function bootstrap() {console.log('[vue] vue app bootstraped');
}/*** 挂载函数* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法*/
export async function mount(props) {actions.setActions(props); // 把actions实例的actions对象值设置为props,这样actions对象值就有props里面的onGlobalStateChange等方法了,之后可以在vue页面调用。相当于将action对象绑到Vue原型上,为了项目中其他地方使用方便Vue.prototype.$actions = actions 、 Vue.prototype.$onGlobalStateChange = props.onGlobalStateChange、Vue.prototype.$setGlobalState = props.setGlobalStateconsole.log('[vue] props from main framework', props);render(props);
}/*** 卸载函数* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例*/
export async function unmount() {instance.$destroy();instance.$el.innerHTML = '';instance = null;router = null;
}
/*** 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效*/
export async function update(props) {console.log('update props', props);
}

注入后actions就拥有了props(包括了通信方法)。之后在任意页面就可以引入此action以使用通信方法。参考文档2 中将action对象绑到Vue原型上也是同样的效果。

5.在子应用组件中

// in src\views\home\index.vue<template><div class="home"><h1>子应用app1</h1><div style="margin-bottom: 40px"><p>接收到的消息1:{{ mes1 }}</p><p>接收到的消息2:{{ mes2 }}</p></div><div><p>子应用自己的数据:{{ app1Msg }}</p><button @click="butClick">点击向父应用发送消息</button></div></div>
</template><script setup>
import { ref, onMounted } from 'vue';
import actions from '../../actions';const mes1 = ref('');
const mes2 = ref(0);
const app1Msg = ref(0);
const butClick = () => {app1Msg.value += 1;actions.setGlobalState({ app1Msg: app1Msg.value });
};onMounted(() => {actions.onGlobalStateChange((state, prev) => {console.log(28, '子应用监听主应用发来的信息', state, prev);if (state.test !== prev.test) {mes1.value = state.test;}if (state.mes2 !== prev.mes2) {mes2.value = state.mes2;}}, true);
});
</script>

跟父组件差不多的写法。

成功展示如下:

用微前端框架qiankun配置项目的实战相关推荐

  1. 微前端框架qiankun项目实战(一)--本地开发篇

    ❝ 作者:黑化程序员 https://juejin.cn/post/6970310177517993998 ❞ 大家好,我是小黑. 公司使用技术栈是vue,最近遇到了一个需求,要把原有后台管理系统的功 ...

  2. 深入浅出解析阿里成熟的微前端框架 qiankun 源码【图文并茂】

    来源:leaf(a1029563229 ) https://github.com/a1029563229/blogs/blob/master/Source-Code/qiankun/1.md 本文将针 ...

  3. 深入浅出解析阿里成熟的微前端框架 qiankun 源码

    本文将针对微前端框架 qiankun 的源码进行深入解析,在源码讲解之前,我们先来了解一下什么是 微前端. 微前端 是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将单页面前端应用由单一的 ...

  4. 万字长文+图文并茂+全面解析微前端框架 qiankun 源码 - qiankun 篇

    写在开头 微前端系列文章: 基于 qiankun 的微前端最佳实践(万字长文) - 从 0 到 1 篇 基于 qiankun 的微前端最佳实践(图文并茂) - 应用间通信篇 基于 qiankun 的微 ...

  5. 微前端框架qiankun之原理与实战

    目录 一.微前端概述 1. 基本原理 2. 微前端的主要优势 3. 当前微前端方案的一些缺点 二.qiankun与single-spa实现原理 1. single-spa实现原理 (1). 路由问题 ...

  6. 微前端框架qiankun开发到部署保姆式教程原理与实战

    废话不多说先了解下在实践. 1. 什么是微前端 web应用构建方式 微前端 微前端在2016年ThoughtWorks Technology Radar正式被提出.微服务这个被广泛应用于服务端的技术范 ...

  7. iframe 接班人-微前端框架 qiankun 在中后台系统实践

    「福利」 ✿✿ ヽ(°▽°)ノ ✿:文章最后有抽奖,转转纪念 T 恤,走过路过不要错过哦 背景 在转转的中台业务中,交易流转.业务运营和商户赋能等功能,主要集中在两个系统中(暂且命名为 inner/o ...

  8. 微前端在得物客服域的实践/那么多微前端框架,为啥我们选Qiankun + MF

    一.业务背景 当前客服一站式工作台包含在线服务.电话.工单和工具类四大功能,页面的基本结构如下: 每个业务模块相对独立,各有独立的业务体系,单个模块体积较大,项目整体采用SPA + iframe的架构 ...

  9. 目标是最完善的微前端解决方案 - qiankun 2.0

    距  qiankun 开源已过去了 11 个月,距上次官方  发声 已过去 8 个月. Announcing qiankun@2.0 2019 年 6 月,微前端框架 qiankun 正式发布了 1. ...

最新文章

  1. 基于结构光测量技术和3D物体识别技术开发的机器人3D视觉引导系统
  2. 第五章 处理器拦截器详解——跟着开涛学SpringMVC
  3. [Android] 给图像加入相框、圆形圆角显示图片、图像合成知识
  4. 机房那么大,我想用AR来看看!
  5. Number of Components
  6. 高精度计时器(编程测试效率用)
  7. [转载] scala
  8. centos6.8安装telnet
  9. Dotnet程序集自动生成版本号
  10. 第一届中国iPhone技术开发者交流大会-----chinapub技术沙龙第一期
  11. HandlerSocket + MySQL
  12. 虚拟服务器设置自动关机,ESXi单个主机定时开关机的设置
  13. 无法打开匿名级安全令牌解决方法
  14. linux cadaver 命令,【Linux学习第三篇】[Tab].[Ctrl]-c.[Ctrl]-d
  15. Jupyter notebook显示k线图集合
  16. 紫光信息港 软件测试,紫光同创PGL22G开发平台试用连载-(2)以太网测试工程一
  17. 深度学习康耐视ViDi 工具概述
  18. 人事工资信息管理系统
  19. 四川大学20年计算机考研情况
  20. SqlSever是哪个公司出品的

热门文章

  1. [读书笔记] Deep learning by Yann LeCun1,2, Yoshua Bengio3 Geoffrey Hinton4,5 on nature
  2. 中国移动H1S-3光猫首发破解路由器桥接教程
  3. ChatGPT 使用 强化学习:Proximal Policy Optimization算法(详细图解)
  4. 企业微信 消息 html,企业微信怎么设置消息提醒
  5. 最全Hadoop视频教程(从入门到精通 视频教程下载)Hadoop八天完全攻克Hadoop视频教程 Hadoop开发新版Hadoop视频教程
  6. CUDA out of memory怎么解决
  7. Juc_并发编程目录
  8. R与Excel之数据分析
  9. h5 bootstrap 小程序模板_汉中餐饮行业支付宝小程序模板
  10. #打卡day1 ROS talker/listener