微前端qiankun的使用说明

本文介绍了如何使用Qiankun框架构建微前端应用,包括主应用与多个微应用的注册、启动,以及应用间的数据传递、路由参数共享、props传递和资源管理的方法。同时涵盖了利用NPM脚本简化多项目管理和跨应用通信的最佳实践。
摘要由CSDN通过智能技术生成

概念

微前端:微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。

qiankun存在一个主应用及一个或多个微应用,主应用和微应用不限技术栈

快速上手(官方文档

  1. 主应用中安装
$ yarn add qiankun  # or npm i qiankun -S
  1. 主应用中注册微应用并启动

注意:启动主应用的同时也需要启动微应用,否则点击跳转微应用会报错

import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'reactApp',
    entry: '//localhost:3000',
    container: '#container',
    activeRule: '/app-react',
    props:{},//主应用需要传递给微应用的数据
  },
  {
    name: 'vueApp',
    entry: '//localhost:8080',
    container: '#container',
    activeRule: '/app-vue',
  },
  {
    name: 'angularApp',
    entry: '//localhost:4200',
    container: '#container',
    activeRule: '/app-angular',
  },
]);
// 启动 qiankun
start();
//设置默认进入的微应用
setDefaultMountApp('/react')

应用间传值(参考文档

1、qiankun内部提供了initGlobalState方法用于注册MIcroAppStateActions实例用于通信,存在以下三个方法:

setGlobalState:设置globalState,设置新值时,内部会做浅检查,如果监测到globalState的值发生变化,会通知所有的观察者

onGlobalState:注册观察者模式

offGlobalStateChange:取消观察者模式

  1. 利用url路由参数共享
主应用
    <Link to='/vue?id=1'>vue3微应用</Link>
react应用
    window.location获取
vue3子应用
    import { useRouter, useRoute } from 'vue-router';
    通过useRoute获取
vue2子应用
    可以通过window.location.search去获取


  1. 利用props传值
主应用中使用props进行传值
registerMicroApps([{
    name: 'm-vue',
    entry: '//localhost:6061/',
    container: '#container',
    activeRule: '/vue',
    loader,
    //增加props进行传值
    props:{
        something:'这是registerMicroApps传递的props'
    }
}])
子应用中在src/main.js中将props挂载在根节点上面
function render(props) {
 instance = new Vue({
   router,
   render: h => h(App),
   data(){
    return{
        //挂载在根节点上面
      parentRouter:props.something
    }
   }
 }).$mount('#app'); 
}

应用之间跳转

利用history.pushState(null,'',url)不刷新页面,更改页面的url进行跳转
缺点:要求各个应用路由系统都是用history模式

利用NPM脚本运行多条命令,简化操作

  1. 在最外层文件夹下下载依赖
yarn add yarn-run-all
  1. 利用yarn-run-all下载所有项目依赖
1、修改package.json文件夹下的script配置
    "scripts": {
        "install": "npm-run-all -s install:*",
        "install:my-react":"cd my-react && yarn",
        "install:my-react1":"cd my-react1 && yarn",
        "install:my-vue":"cd my-vue && yarn",
        "install:my-vue2":"cd my-vue2 && yarn"
   }
2、执行yarn install安装所有项目依赖

资源共享

利用import maps对import做一个映射处理

示例:

项目结构:主应用React + 微应用React1 + 微应用VUE2(vue版本2) + 微应用VUE3(vue版本3)+ 微应用HTML + 微应用vite项目

主应用修改

1、主应用src文件夹中创建registerApp.js

import { registerMicroApps,start} from 'qiankun';
const loader = (loading) =>{
    console.log(loading);
}
registerMicroApps([{
    name: 'm-vue',
    entry: '//localhost:6061/',//端口号必须与对应项目的端口号一致
    container: '#container',//对应页面上的容器
    activeRule: '/vue',
    loader
},{
    name: 'm-vue2',
    entry: '//localhost:6062/',
    container: '#container',
    activeRule: '/vue2',
    loader
},{
    name: 'm-react',
    entry: '//localhost:6063/',
    container: '#container',
    activeRule: '/react',
    loader
},{
    name: 'm-html',
    entry: '//localhost:7104/',
    container: '#container',
    activeRule: '/html',
    loader
}],{
    beforeLoad: () =>{
        console.log('加载前');
    },
    beforeMount: () =>{
        console.log('加载后');
    }
})
start();

2、在src/index.js中引入registerApp.js

import './registerApp'
  1. 在src/App.js中加入容器
import './App.css';
import { BrowserRouter as Router, Link } from 'react-router-dom'

function App() {
  return (
    <div className="App">
      <Router>
        <Link to='/'>
          <h1>
            我是主应用
          </h1>
        </Link>
        <Link to='/vue'>vue3微应用</Link>
        <br />
        <Link to='/vue2'>vue2微应用</Link>
        <br />
        <Link to='/react'>react微应用</Link>
      </Router>
      <div id='container'></div>//容器
    </div>
  );
}

export default App;

react微应用修改

修改src/index.js

import React from 'react';
import { createRoot } from 'react-dom/client'
import './index.css';
import App from './App';
function render(props = {}) {
  const { container } = props;
  const root = createRoot(container ? container.querySelector('#root') : document.querySelector('#root'))
  root.render(<App />);
}

if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

export async function bootstrap() {
  console.log('[react16] react app bootstraped');
}

export async function mount(props) {
  console.log('[react16] props from main framework', props);
  render(props);
}

export async function unmount(props) {
  const { container } = props;
  const root = createRoot(container ? container.querySelector('#root') : document.querySelector('#root'))
  root.unmount(<App />);
}
  1. config-overrides.js配置

2.1引入react-app-rewired(作用:覆盖react脚手架配置)

npm install react-app-rewired -D

2.2修改package.json启动命令

  "scripts": {
    "start": "set PORT=6063 && react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },

2.3修改dev以及打包配置,在根目录下创建config-overrides.js,文件配置如下:

module.exports = {
    webpack: config => {
      config.output.library = "m-react";
      config.output.libraryTarget = "umd";
      config.output.publicPath = "http://localhost:6063/"; // 此应用自己的端口号
      return config;
    },
    devServer: configFunction => {
      return function(proxy, allowedHost) {
        const config = configFunction(proxy, allowedHost);
        config.port = "6063";
        config.headers = {
          "Access-Control-Allow-Origin": "*"
        };
        return config;
      };
    }
  }

vue3微应用修改

  1. 在src目录中新增public-path.js(判断当前环境是否是在微前端的环境下)
if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
  }
  1. 在src/router.js文件中的顶部引入public-path.js
import './public-path'
import HelloWorld from './components/HelloWorld.vue'
import Home from './Home.vue'

const routes = [
  {
    path: '/home',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    component: HelloWorld
  },
]
export default routes
  1. 入口文件main.js修改,为了避免根id #app与其他的DOM冲突,需要限制查找范围
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue'
import routes from './router'

let history;
let router;
let app;

function render(props = {}) {
    history = createWebHistory('/vue');
    router = createRouter({
        history,
        routes
    });
    app = createApp(App);
    let { container } = props;
    app.use(router).mount(container ? container.querySelector('#app') : "#app")
}

// 独立运行时
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() {
    console.log('[vue] vue app unmount');
    history = null;
    app = null;
    router = null;
}
  1. 修改vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false,
  devServer:{
    port: 6061,
    headers:{
      // 允许跨域
      "Access-Control-Allow-Origin": "*"
    }
  },
  configureWebpack:{
    output: {
      library: 'm-vue',
      libraryTarget:'umd'
    }
  }
})

vue2微应用修改

  1. 修改vue.config.js

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false,
  devServer:{
    port: 6061,
    headers:{
      // 允许跨域
      "Access-Control-Allow-Origin": "*"
    }
  },
  configureWebpack:{
    output: {
      library: 'm-vue2',
      libraryTarget:'umd'
    }
  }
})
  1. 修改main.js  (这里与vue3不同)
import Vue from 'vue'
import App from './App.vue'
import router from './router'

let instance = null
function render(props) {
 instance = new Vue({
   router,
   render: h => h(App)
 }).$mount('#app'); // 这里是挂载到自己的html中  基座会拿到这个挂载后的html 将其插入进去
}

if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath
 __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
if (!window.__POWERED_BY_QIANKUN__) { // 默认独立运行
 render();
}

// 父应用加载子应用,子应用必须暴露三个接口:bootstrap、mount、unmount
// 子组件的协议就ok了
export async function bootstrap(props) {

};

export async function mount(props) {
 render(props)
}

export async function unmount(props) {
 instance.$destroy();
}

HTML微应用修改

  1. 新增入口文件 entry.js
const render = ($) => {
    // 渲染前do something
    return Promise.resolve();
};
((global) => {
    // 对应微应用的名称
    global['m-html'] = {
        bootstrap: () => {
            console.log('purehtml bootstrap');
            return Promise.resolve();
        },
        mount: () => {
            console.log('purehtml mount');
            return render($);
        },
        unmount: () => {
            console.log('purehtml unmount');
            return Promise.resolve();
        },
    };
})(window);
  1. 在html中引入entry.js

注意:

这里js需要放在最后加载,放在最后引入或者将入口js标记为entry

entry.js基于jq,需要在entry前引入jq

<script src="./entry.js"></script>//放最后引入
或者
<script src="./entry.js" entry></script>
  1. 新建package.json文件
{
    "name": "my-html",
    "version": "1.0.0",
    "description": "",
    "main": "index.html",
    "scripts": {
      "start": "cross-env PORT=7104 http-server . --cors",
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "MIT",
    "devDependencies": {
      "cross-env": "^7.0.2",
      "http-server": "^0.12.1"
    }
  }
  1. 运行
yarn  //下载依赖
yarn start //运行

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值