微前端之qiankun的使用(二)

285 阅读2分钟

前言

上篇介绍了 qiankun 主应用子应用的配置要求,这篇介绍具体的子应用的改造方法。

webpack 项目

允许跨域配置

webpack-dev-server

module.exports = {
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
}

导出生命周期

声明导出生命周期的 js 文件

webpack 的入口 js 文件在打包后就是一个 script 标签,因此满足 qiankun 从最后一个 script 标签对应的 js 文件读取生命周期的条件,因此不用再添加 entry 属性。

导出生命周期

export async function bootstrap() {
  console.log('app bootstraped');
}
export async function mount(props) {
  console.log("app mount");
}
export async function unmount() {
  console.log("app unmount")
}
const { name } = require('./package');
module.exports = {
  output: {
    library: `${appName}-[name]`,
    libraryTarget: 'umd',
  },
}

因为 qiankun 会从 window 上的某个属性上去获取生命周期,因此为了使打包后的 bootstrap / mount / unmount 等生命周期函数可以挂到 window 的某个属性上,首先必须设置 libraryTarget 为 umd 或者 window / global / this。使其可以挂在 window 上,其次必须设置 library,否则这三个函数会被直接挂在 window 上,qiankun 无法拿到。

处理动态加载的资源路径

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

特殊配置

jsonpFunction 为 webpack 打包 import() 的资源时特有的特殊改造,如果子应用中有动态 import() 的代码,则一定要配置。jsopnFunction 在 webpack5 中被更名为 chunkLoadingGlobal。

module.exports = {
  output: {
    jsonpFunction: `webpackJsonp_${appName}`,//webpack4
    //chunkLoadingGlobal: `webpackJsonp_${appName}`,//webpack5
  },
}

非 webpack 项目

这里以普通的项目,以 http-server 起服务为例的配置。

允许跨域配置

http-server

http-server -c-1 --cors

导出生命周期

非 webpakc 的项目只需要按照 qiankun 获取生命周期函数的原理进行配置导出生命周期函数的 js 文件后,直接往 window 上挂生命周期对象就行。

声明导出生命周期的 js 文件

可以将导出生命周期的 js 文件对应的 script 标签放置最后,也可以添加 entry 属性指定。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Purehtml Example</title>
  </head>
  <body>
    <div>
      Purehtml Example
    </div>
  </body>
  + <script src="//yourhost/entry.js" entry></script>
</html>

导出生命周期

在 entry js 里声明 lifecycles。

const render = ($) => {
  $('#purehtml-container').html('Hello, render with jQuery');
  return Promise.resolve();
};

((global) => {
  global['purehtml'] = {
    bootstrap: () => {
      console.log('purehtml bootstrap');
      return Promise.resolve();
    },
    mount: () => {
      console.log('purehtml mount');
      return render($);
    },
    unmount: () => {
      console.log('purehtml unmount');
      return Promise.resolve();
    },
  };
})(window);

PS: 挂在 window 上的生命周期函数对象对应的属性名可以为任意值,比如上面的 purehtml,也可以是 xxx。但是根据 qiankun 获取生命周期函数的方式来看,最好设置为该子应用在主应用注册的 appName 最佳。否则在后面再在 window 上挂了一个属性,就会导致错误❌。

处理动态加载的资源路径

写死即可,或者发布在 cdn 上。

特殊配置

子应用全局变量

后续供其他文件全局使用的用 var 定义的全局变量和全局的 function,在 qiankun 里面,由于 eval+with 包裹执行的特征,导致本应该挂在 window 上的这些全局变量,都变成了在函数中定义了,无法自动挂在 window 上了。则需要在后面手动挂在 window 上。

var a = 123
function test(){}

// add to the end
window.a = a;
window.test = test;

mount 在前,render 声明在后

qiankun 在激活子应用的时候,会立马调用子应用的 bootstrap``mount生命周期函数。但是有时候此时 render 函数还没出现,还没被定义,因此拿不到 render 函数放在 mount 里。

此时可以将 mount 函数进行改造如下:

setTimeout(() => {
    function render(props) {
        console.log('render')
    }
    window["waitRender"](render)
}, 5000)

;((global) => {
    global['purehtml'] = {
        bootstrap: () => {
            console.log('purehtml bootstrap');
            return Promise.resolve();
        },
        mount: (props) => {
            console.log('purehtml mount');
            new Promise((resolve, reject) => {
                window["waitRender"] = resolve
            }).then(fn => fn(props))
            return Promise.resolve();
        },
        unmount: () => {
            console.log('purehtml unmount');
            return Promise.resolve();
        },
    };
})(window);