前言
前段时间在刷文章的时候偶然看到了 “微前端” ,于是一时起兴便浅浅的体验一把~嗨嗨嗨。
废话不多说直接上菜!!!(概念那些可以前往qiankun官网阅读);
是的,本次体验的微前端方案就是 qiankun;
注:只是简单体验了一把(最最最最基础的东西)!!!
实践
本次实践中会用到三个项目,并且这三个项目都是Vue2项目(没有任何限制,也可以用react等等项目),为什么需要三个项目呢?一个项目用来做主应用,剩下两个则是用作子应用(分应用、微应用)(个人认为)。
ok,相信到这还是懵懵的,我也是,嘿嘿。那么主应用、子应用分别是用来干什么的呢?
主应用: 我的理解是将所有子应用聚集在一起,使用统一路由管理子应用,只需要通过主应用的路由就可以访问到每个子应用;
子应用: 我的理解是一个大系统中的很多个小系统(小模块),可以独立开发与其他子系统互不干扰,并且每个子系统可以完全使用不同的技术栈进行开发,比如:A子系统使用Vue,B子系统使用React进行开发;
创建项目
-
创建主应用项目
vue create micro-main -
创建第一个子应用项目
vue create micro-first-app -
创建第二个子应用项目
vue create micro-second-app
搭建主应用(micro-main)
-
安装 qiankun
npm i qiankun -S -
在App.vue中创建容器(显示子应用的容器)
<template> <div id="app"> <!-- 第一个子应用显示的容器 --> <div id="first-app"></div> <!-- 第二个子应用显示的容器 --> <div id="second-app"></div> </div> </template>注意:
一个应用一个容器来进行展示!!! -
注册子应用
使用 qiankun 提供的
registerMicroApps方法对所有子应用进行注册;<script> import { registerMicroApps, start } from 'qiankun' export default { name: 'App', created() { registerMicroApps([ { name: "FirstApp", entry: "//localhost:8888", container: "#first-app", activeRule: "/first", }, { name: "SecondApp", entry: "//localhost:8889", container: "#second-app", activeRule: "/second", }, ]); }, mounted() { start(); }, } </script>注意:
mounted周期调用start函数,注意不要重复调用
搭建子应用(micro-first-app、micro-second-app)
-
src目录下创建 public-path.js 并在 main.js 中导入
public-path.js:/* eslint-disable */ if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; }main.js:import "./public-path"; -
导出相应的生命钩子函数,供主应用在适当的时机调用
main.jslet instance = null; function render(props = {}) { const { container } = props; instance = new Vue({ router, store, render: (h) => h(App), }).$mount( container ? container.querySelector("#first-child") : "#first-child" ); } // 独立运行时 if (!window.__POWERED_BY_QIANKUN__) { render(); } export async function bootstrap() { console.log("[vue] vue app bootstraped"); } 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; } -
修改 vue-router 的 base 路由根路径
router/index.jsimport Vue from "vue"; import VueRouter from "vue-router"; Vue.use(VueRouter); const routes = []; const router = new VueRouter({ mode: "history", base: window.__POWERED_BY_QIANKUN__ ? "/first-chold/" : "/", routes, }); export default router; -
修改服务器端口以及跨域添加请求头和webpack导出配置
vue.config.js// vue.config.js const packageName = require("./package.json").name; module.exports = { devServer: { port: 8888, headers: { "Access-Control-Allow-Origin": "*", }, }, configureWebpack: { output: { library: `${packageName}-[name]`, libraryTarget: "umd", jsonpFunction: `webpackJsonp_${packageName}`, }, }, }; -
修改 public/index.html 挂载容器的 id
<div id="first-app"></div>注意:这里的 id 一定要与 main.js 中的 $mount 的参数对应上
-
修改App.vue
<template> <div id="app"> <h1>First App</h1> </div> </template>
micro-second-app 的配置同上,只需要将 index.html 的 容器 id 以及 main.js 中的 $mount 的参数 改为 second-app,还有开发服务器端口改成不一样即可。
展示!!!
浏览器访问主应用 开发服务器 地址 并 路径拼接上 activeRule:
http://localhost:8081/first
http://localhost:8081/second
主应用的 路由组件 内注册展示子应用
-
创建组件
-
在路由组件中注册子应用
<template> <div calss="child-container"> <!-- 第一个子应用显示的容器 --> <div id="first-app"></div> <!-- 第二个子应用显示的容器 --> <div id="second-app"></div> </div> </template> <script> import { registerMicroApps, start } from "qiankun"; export default { name: "ChildApp", created() { registerMicroApps([ { name: "FirstApp", entry: "//localhost:8888", container: "#first-app", activeRule: "/child-app/first", }, { name: "SecondApp", entry: "//localhost:8889", container: "#second-app", activeRule: "/child-app/second", }, ]); }, mounted() { start(); }, }; </script>注意:
activeRule需要加上路由配置中注册子应用组件对应的路由的path; -
配置组件对应路由
router/index.jsconst routes = [ { path: "/child-app/*", name: "ChildApp", component: ChildApp, }, ];注意:一定要在 path 后面加上 *,* 表示/child-app/后接任意字符都匹配到ChildApp组件;
-
修改App.vue
<template> <div id="app"> <router-view /> </div> </template>
再次展示!!!
http://localhost:8081/child-app/first
http://localhost:8081/child-app/second