qiankun配置微前端

qiankun-微前端

主应用

1、安装qiankun

$ yarn add qiankun # 或者 npm i qiankun -S

2、在主应用中注册微应用

import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'react app', // app已经注册的名字
    entry: '//localhost:7100',  // 进入的主机端口号
    container: '#yourContainer',  // 类似于一个容器,起到占位的作用
    activeRule: '/yourActiveRule',  // 找到微应用的路径
  },
  {
    name: 'vue app',
    entry: '//localhost:3012',
    container: '#yourContainer1',
    activeRule: '/yourActiveRule1',
    props:{}  // 用于主应用与微应用之间的通信
  },
]);
// 启动乾坤
start();
当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。
微应用

微应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。

  • 导入相应的生命周期钩子

微应用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js) 导出 bootstrap、mount、unmount 三个生命周期钩子,以供主应用在适当的时机调用。

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log('react app bootstraped');
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount(props) {
  ReactDOM.unmountComponentAtNode(
    props.container ? props.container.querySelector('#root') : document.getElementById('root'),
  );
}

/**
 * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {
  console.log('update props', props);
}

qiankun 基于 single-spa,所以你可以在这里找到更多关于微应用生命周期相关的文档说明。

  • 配置微应用的打包工具

除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别微应用暴露出来的一些信息,微应用的打包工具需要增加如下配置:

const packageName = require('./package.json').name;

module.exports = {
  output: {
    library: `${packageName}-[name]`,
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_${packageName}`,
  },
};

相关配置介绍可以查看 webpack 相关文档

举例

react为主应用,vue3和react为子应用

react主应用配置

1、首先在主应用下面安装

$ yarn add qiankun # 或者 npm i qiankun -S

2、其次在这子应用的根目录下面建一个.env文件,里面分别配置上如下代码

PORT=端口号  // 这3个应用下的.env文件都配置上,但是`端口号`要写3个不一样的

3、在react主应用中src下面的index.js文件当中注册微应用

import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'qiankun_3', 
    entry: '//localhost:3012',
    container: '#qiankun3',
    activeRule: '/qiankun3',
    props:{}  // 数据的传递
  },
  {
    name: 'vue3_app',
    entry: '//127.0.0.1:3013',
    container: '#vue3_app',
    activeRule: '/vue3_app',
  },
]);
// 启动乾坤
start();
react子应用配置

1、子应用的src目录下创建public-path.js文件,里面做如下配置:

if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
//  __webpack_public_path__ :在入口文件中导入public-path.js文件以后,
//  webpack5需要在package.json中改为全局变量,要不这块会显示未找到的错误。
//  修改为package.json文件如下即可。
"eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "globals": {
      "__webpack_public_path__": true
    }
  },

2、入口文件 index.js 修改,为了避免根 id #root 与其他的 DOM 冲突,需要限制查找范围。

import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

function render(props) {
  const { container } = props;
  ReactDOM.render(<App />, container ? container.querySelector('#root') : document.querySelector('#root'));
}

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;
  ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}

这里需要特别注意的是,通过 ReactDOM.render 挂载子应用时,需要保证每次子应用加载都应使用一个新的路由实例。

3、下载react-app-rewired插件,更改子应用启动项

$ npm i react-app-rewired-S

package.json文件中改启动项

  "scripts": {
    "start": "react-app-rewired start",  // 更改启动区为react-app-rewired
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

4、重写webpack中的方法,根目录下创建config-overrides.js文件

const { name } = require('./package');

module.exports = {
    webpack: (config) => {
        config.output.library = `${name}-[name]`;
        config.output.libraryTarget = 'umd';  // 注入方式
        // config.output.jsonpFunction = `webpackJsonp_${name}`;
        // 在2020-10-10发布的webpack 5中已将 output.jsonpFunction 更名为
        // output.chunkLoadingGlobal
        config.output.globalObject = 'window';
        // 中自动推断出一个唯一的构建名称,并将其作为 output.uniqueName 的默认值。
        // 这个值用于使所有潜在的冲突的全局变量成为唯一。
   		config.output.globalObject = 'window';

        return config;
    },

    devServer: (_) => {
        const config = _;

        config.headers = {
            'Access-Control-Allow-Origin': '*',
        };
        config.historyApiFallback = true;
        config.hot = false;
        config.watchContentBase = false;
        config.liveReload = false;

        return config;
    },
};
vue3子应用配置

如果想配置vue2的请看这里

1、子应用的src目录下创建public-path.js文件,里面做如下配置:

if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

2、配置入口文件 main.js

import './public-path';  // 必须开头导入要不解析不了
import { createApp } from 'vue'
import App from './App.vue'
import routes from './router'
import { createRouter, createWebHistory } from 'vue-router';
// import store from './store'
import './assets/main.css'

let router = null;
let instance = null;
let history = null;

function render(props = {}) {
    const { container } = props;
    let arr = routes.options.routes;
    console.log(arr)
    history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/app-vue3' : '/');
    router = createRouter({
        history,
        routes: routes.options.routes,
    });
    instance = createApp(App);
    instance.use(router);
    // instance.use(store);
    instance.mount(container ? container.querySelector('#app') : '#app');
}

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

export async function bootstrap() {
    console.log('%c%s', 'color: green;', 'vue3.0 app bootstraped');
}

function storeTest(props) {
    props.onGlobalStateChange &&
    props.onGlobalStateChange(
        (value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
        true,
    );
    props.setGlobalState &&
    props.setGlobalState({
        ignore: props.name,
        user: {
            name: props.name,
        },
    });
}

export async function mount(props) {
    storeTest(props);
    render(props);
    instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
    instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}

export async function unmount() {
    instance.unmount();
    instance._container.innerHTML = '';
    instance = null;
    router = null;
    history.destroy();
}

3、在vue.config.ts文件中配置监听端口号,配置vue允许夸端口 设置vue.config,并且设置挂载点

const { name } = require('./package');
module.exports = {
  devServer: {
    port:3012,//设置端口号
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
      jsonpFunction: `webpackJsonp_${name}`,
    },
  },
};

这样一个过程完成下来后,您就会对微前端恍然大悟。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值