基于qiankun添加一个子工程实践

1,933 阅读4分钟

前言

最近工作需要把三个开源项目做一个整合, 本来打算开iframe去做路由的间接访问, 也就是说同时要跑三个项目跟一个外壳项目... 同事希望能在一个页面中直接能访问三个项目的页面而不要跑三个项目, 希望笔者做一个合并, 就是单纯的合并...不过我把项目下载下来后发现并不简单, 因为node.js环境兼容性问题,单纯能让三个项目跑起来都费了不少时间

项目名称技术栈打包工具和版本
nacos/console-fereact"webpack": "^4.41.4" , "webpack-cli": "^3.3.10"
sentinelsentinel-dashboardangular"gulp": "^3.9.1"
skyWalking-rocketbotvuevue-cli 3.x 带的 webpack

刚好最近的一个前端技术培训的时候有提到一个微前端的概念, 并提到一个目前最好的解决方案 qiankun, 于是便去体验了一波, 以下是笔者在qiankun 下载下来的demo中添加一个子应用的步骤

具体的操作步骤

针对子应用的修改----以examples中的vue项目为参照

入口文件的修改

image_1.png

  1. 引入文件public-path.js到子工程的src目录

    if (window.__POWERED_BY_QIANKUN__) {
      // eslint-disable-next-line no-undef
      __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    }
    
  2. 路由的配置要更改base, 其中三元运算符 ? 后面的值要与跟主应用中的注册的路由相同, 也就是说这个是匹配子工程的路由, router也可以分开配置, 需要调整base设置!

image_2.png

  1. 构造render函数, render函数会在生命周期函数中执行

  2. 导出生命周期函数 bootstrap, mount, unmount

    1. bootstrap 只会在子应用初始化的时候调用一次,下次子应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等
    2. mount 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
    3. unmount 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载子应用的应用实例
// main.ts
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();
}

export async function unmount() {
   instance.$destroy();
   instance = null;
   router = null;
}

vue.config.js 修改

  1. 需要固定子应用的端口并提供给主工程访问, 所以在devServer中配置了端口

  2. 按照文档需要给webpack传入相应的配置对象, 把子应用打包成 umd 库格式

const port = 7109;
module.exports.devServer.port = port;
module.exports.configureWebpack.output = {
    // 把子应用打包成 umd 库格式
    library: `${name}-[name]`,
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_${name}`,
}

针对主应用的修改 ---- 以example中的main为参照

  1. 需要注册把子应用的路由注册到主应用中
// main/index.js
registerMicroApps(
    [...,{
    //添加子应用路由, name对应base的设置, entry地址端口对应子应用端口
    name: 'skywalking',
    entry: '//localhost:7109',
    render,
    activeRule: genActiveRule('/skywalking'),
}]
  1. 如果项目比较庞大, 可以添加到预加载选项中
main/index.js
/**
* Step3 设置默认进入的子应用
*/
setDefaultMountApp('/skywalking');
/** 
*  Step4 启动应用
*/
start({
   prefetch: ['react16', 'vue', 'skywalking'],  //预加载, 其余为懒加载
   jsSandbox: true,
   singular: false,
});

针对qiankun项目package.json命令修改

//因为install和start命令会执行所有的 'install: *' 和 'start: *', 所以添加的命令也需要按照指定的格式来添加 
scripts: {
    "examples:install": "npm-run-all --serial build install:*",
    "examples:start": "npm-run-all --parallel start:*", 
	"install:skywalking": "cd examples/skywalking-rocketbot && yarn",
    "start:skywalking": "cd examples/skywalking-rocketbot && yarn start",
}

上面的start:skywalking表示执行相应路径下package.json中的start命令, 由于新增的子应用基于vue-cli 3.x版本, 只有serve命令, 没有start命令, 那么可以把 yarn start 更换为 yarn serve, 或者也可以在package.json中增加一个start命令去启动子应用 为了保持统一使用了yarn命令, 其实也可以使用npm命令来进行下载和安装

最终结果

image_3.png

正确访问到添加的子应用, 刷新时会有三个localhost的请求发出, 分别指向三个预加载的项目的地址

使用体验

  1. 笔者十分惊叹这种蚂蚁金服神奇的技术, 简直就是公司遗产项目的福音, 可以不考虑技术栈, 不考虑相应的运行环境(包括不同node.js的版本, 不同的打包工具和不同的版本)把项目都集成起来, 从一个入口做访问, 而且使用的体验也是相当的不错, 欢迎大家来体验使用
  2. 笔者是在已有的demo里面做的一个简单的增删子应用操作, 还没有以依赖的方式集成到项目中使用, 欢迎有这样使用经验的大牛来交流经验
  3. 执行安装依赖命令的时候安装比较久(可能是最近网络都不太行的原因), 也可以考虑在子应用中单独使用镜像地址来安装node_modules速度会比较快, 执行install命令时如果控制台提示已经是最新的依赖则没有问题