记一次 - 微前端 qiankun 之 webpack5 构建

145 阅读2分钟
  • node v19.6.1
  • npm 9.4.0
  • vue-cli 4.x

package.json

{
  "dependencies": {
    "@element-plus/icons-vue": "^2.1.0",
    "axios": "^1.4.0",
    "core-js": "^3.6.5",
    "element-plus": "^2.3.7",
    "node-sass": "^9.0.0",
    "qiankun": "^2.10.11",
    "sass": "^1.64.1",
    "sass-loader": "^13.3.2",
    "vue": "^3.0.0",
    "vue-router": "^4.2.4",
    "vuex": "^4.1.0",
    "webpack": "^5.88.1",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
  },
  "devDependencies": {
    "@vue/babel-plugin-jsx": "^1.1.5",
    "@vue/cli-plugin-eslint": "~4.5.14",
    "@vue/cli-service": "^5.0.8",
    "@vue/compiler-sfc": "^3.3.4",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0"
  },
}

主应用 vue.config.js

const base = process.env.VUE_APP_BASE_URL || "/"; 
module.exports = { 
    productionSourceMap: true, 
    publicPath: base, 
    devServer: { 
        port: "8081", 
        client: { 
            overlay: { 
                errors: true, 
                warnings: false, 
                runtimeErrors: true
            }, 
        }, 
    }, 
}

子应用 vue.config.js [webpack5]

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

module.exports = {
  lintOnSave: false,
  devServer: {
    port: "8083",
    headers: {
      'Access-Control-Allow-Origin': '*' // 主应用获取子应用时跨域响应头
    },
    client: {
      overlay: {
        errors: true,
        warnings: false,
        runtimeErrors: true,
      },
    },
  },
  configureWebpack: config => {
    return {
      output: {
        library: `${name} - [name]`,
        libraryTarget: `umd`,
        globalObject: "window",
        // chunkLoadingGlobal: `webpackJsonp_${name}` // 提供一个唯一的名称, 主应用请求子应用回找不到资源
      }
    }
  },
}

子应用 vue.config.js [webpack4]

const { name } = require("./package");
module.exports = {
  lintOnSave: false,
  devServer: {
    port: "8083",
    headers: {
      'Access-Control-Allow-Origin': '*' // 主应用获取子应用时跨域响应头
    },
    client: {
      overlay: {
        errors: true,
        warnings: false,
        runtimeErrors: true,
      },
    },
  },
  configureWebpack: config => {
    return {
      output: {
        ibrary: `${name} - [name]`,
        libraryTarget: `umd`,
        // jsonpFunction: `webpackJsonp_${name}` // 提供一个唯一的名称, 主应用请求子应用回找不到资源
      }
    }
  },
}

在主应用,注册微应用

  • 这一步注意,微应用应该都是启动状态,不然会注册失败,报错。因为找不到微应用
import { registerMicroApps, 
  addGlobalUncaughtErrorHandler, 
  removeGlobalUncaughtErrorHandler} from 'qiankun';
  
registerMicroApps(
  {
    name: 'microChild', // 唯一性,可用微应用的名称
    entry: MICRO_CHILD, // 微应用入口
    container: '#microContainer', // 微应用挂载的dom
    activeRule: '/microChild', // 触发匹配微应用的路由规则
    props: { // 提供给子应用的数据
      store, // 将主应用的store实例传给子应用
    }
  },
], {
  beforeLoad: (app) => {
    console.log("qiankun 微应用加载前----", app)
    return Promise.resolve();
  },
  afterMount: (app) => {
    console.log("qiankun微应用挂载后----", app)
    return Promise.resolve();
  }
}); 

// 全局的未捕获异常处理器
addGlobalUncaughtErrorHandler((event) => {
  console.log("全局异常捕获加载失败--=------", event)
})

// 移除全局未捕获异常处理器
removeGlobalUncaughtErrorHandler(() => {}));

应用间通信

initGlobalState 存储全局共享数据,各个子应用可以通过 initGlobalState 读取和修改数据

  • 定义全局状态,并返回通信方法,建议在主应用使用,微应用通过 props 获取通信方法。
  • 主应用中定义:
import { initGlobalState, MicroAppStateActions } from 'qiankun';
// 初始化 stateconst 
actions: MicroAppStateActions = initGlobalState(state);actions.onGlobalStateChange((state, prev) => {  
// state: 变更后的状态; prev 变更前的状态  
console.log(state,prev);});
actions.setGlobalState(state);
actions.offGlobalStateChange();
  • 微应用中接收
// 从生命周期 mount 中获取通信方法,使用方式和 master 一致
export function mount(props) {  
props.onGlobalStateChange((state, prev) => {    
    // state: 变更后的状态; prev 变更前的状态    
    console.log(state, prev);  
});  
props.setGlobalState(state);}
  • 启动 qiankun
start()