前言

qiankun 框架是基于single-spa框架的,所以遵循的协议都一样,也是向外暴露三个钩子函数,但是qiankun 在single-spa的基础上进行了改进:
1,与技术栈无关
2,解决了single-spa的隔离问题,css隔离,js隔离
3,js沙箱机制
4,可以预加载子应用
5,主应用也无需构建请求,内部封装了fecth请求,只需要子应用配置跨域就行

bug

昨天晚上开始写,不断遇见bug,解决一个又会遇见另外一个,真好。今天早上才解决完成,主要遇到的问题是react子应用上的bug,好久没用react了,版本问题,配置问题都有。

一:子应用挂载dom的问题
这次qiankun实战使用vue作为主应用,子应用有vue,react技术栈,这就出现问题了,vue作为主应用,vue也构建了子应用,都是挂载到id 为app的容器上,本来子应用应该是挂载到自己的HTML上,然后再挂载到主应用的容器上,结果出现了子应用挂载到主应用id 为app 的容器上,覆盖主应用,所以子应用应该配置与子应用不一样的挂载id

配置前:
在这里插入图片描述
配置后:
在这里插入图片描述

二:在配置好react子应用时,npm start可以运行,但是在groom浏览器就是不显示页面
报错:Cannot read property ‘forEach’ of undefined

解决:跟新groom 中react-devtools工具,版本问题

三:配置react子应用,主应用请求重定向为子应用绝对路径
报错:webpack_public_path is not defined

解决:eslint的问题

"eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "globals": {
      "__webpack_public_path__": true
    }
  },

qiankun实战

1,构建主应用,子应用

// 构建主应用
vue create qiankun-base
// 构建vue子应用
vue create child-vue
//构建react子应用
create-react-app child-react

2,主应用安装qiankun,这里子应用无需安装其他插件

npm i qiankun --save

3,配置路由,可以原生也可以使用UI库

npm i element-ui --save

4,配置主应用,注册子应用,在主应用中声明两个容器接收子应用

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';


Vue.use(ElementUI);


import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'reactApp',   //子应用的名字
    entry: '//localhost:3020',  // 子应用的路径
    container: '#react',  // 装载子应用的容器
    activeRule: '/react',  // 路由匹配
  },
  {
    name: 'vueApp',
    entry: '//localhost:3010',
    container: '#vue',
    activeRule: '/vue',
  }
]);
// 启动 qiankun
start();

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')


// 乾坤主应用会根据配置项,主动发起fecth请求,加载子应用,所以配置子应用的时候,需要解决跨域

5,配置vue子应用

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

let instance = null;
function render () {
  instance = new Vue({
    router,
    render: h => h(App)
  }).$mount('#app-vue')
  
}

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


// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}



export async function bootstrap() {
 
}
export async function mount() {
 
  render();
}
export async function unmount() {
  instance.$destroy();
}

配置vue.config.js

module.exports = {
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
    port:3010
  },
  configureWebpack: {
    output: {
      library: `vueApp`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
    
    },
  },
};

vue子应用中有路由,记得修改路由base

6,配置react子应用


import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );
// 定义一个渲染函数,方便主应用调用和子应用自己运行
function render () {
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById('root')
  );
}

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

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

export async function bootstrap() {
  
}

export async function mount() {  
  // 挂载子应用
  render();
}

export async function unmount() {
  // 卸载子应用
    ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}

reportWebVitals();

创建配置文件config-overrides.js

module.exports = {
    webpack: (config) => {
        config.output.library = `reactApp`;
        config.output.libraryTarget = 'umd';
        config.output.globalObject = 'window';
        config.output.publicPath = `http://localhost:3020/`
        return config;
      },
    
      devServer: (configFunction) => {
        return function (proxy,allowedHost){
          const config = configFunction(proxy,allowedHost);
          config.headers = {
            "Access-Control-Allow-Origin":'*'
          }
          return config
        }
      },
}

注意修改eslint中的配置

7,分别运行主,子应用

总结

通过qiankun实现微前端,比single-spa性能更好,上手更容易。总体来说搭建一个微前端应用不是很难,不管是single-spa还是qiankun。
qiankun官网:官方文档

qiankun中的沙箱机制

什么是沙箱机制?
沙箱就是应用运行的环境,在沙箱中运行的应用,不会影响外界应用,当沙箱中的应用卸载后,主应用可以还原之前的状态。这就是为什么主应用加载微应用,显示完微应用,可以看到之前的主应用。原来主应用的js,css都被缓存起来了。

一:快照沙箱
当页面不支持Proxy,使用快照沙箱,也是代理的意思,原生只能创建一个。
二:Proxy沙箱
使用es6中的Proxy实现代理,可以支持创建多个沙箱。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐