qiankun demo with React 18

1,264 阅读2分钟

最近因为面试被面问到了mico-frontend, 所以就准备学习一下。做了两个demo,一个是基于module federation, 这个的demo有很多。另外一个based on qiankun

  • qiankun: 2.8.4
  • react: 18

两个app:

  1. qiankunMainApp, 使用create-react-app创建,再install qiankun.

(1)package.json文件如下:

"qiankun": "^2.8.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.6.1",
"react-scripts": "^5.0.1"

(2)在src/index.js中注册sub app

registerMicroApps([
  {
    name: 'qksubapp',
    entry: '//localhost:7001',
    container: '#container',
    activeRule: '/app-react',
  }
]);
// start qiankun
start();
  1. qiankunSubApp, 同样使用create-react-app创建

(1)package.json文件如下:

dependencies: {
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-scripts": "^3.0.4", //note: this one used 3.0.4, not the create-react-app default one
     "web-vitals": "^2.1.4"
 },
 "scripts": {
    "start": "rescripts --openssl-legacy-provider start",
    "build": "rescripts build",
    "test": "rescripts test",
    "eject": "rescripts eject"
 },
  "devDependencies": {
    "@rescripts/cli": "^0.0.16" 
  }

我们需要重写webpack的配置,使用了rescripts,可以0.0.16这个版本只支持react-scripts 2~4, 所以无法使用react-scripts 5

(2).env

SKIP_PREFLIGHT_CHECK=true
PORT=7001  // becuase we register 7001 port in main app

(3).rescriptsrc.js

// this file's config is from offical site 

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

module.exports = {
  webpack: (config) => {
    config.output.library = `${name}`;
    config.output.libraryTarget = 'umd';
    config.output.jsonpFunction = `webpackJsonp_${name}`;
    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;
  },
};

(4) src/public-path.js

let __webpack_public_path__ = "..."; // set this line, totally because can't find webpack_public_path
if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

(5)src/index.js

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

//let root = document.querySelector('#root');
function render(props) {
  const { container } = props;
  // root = ReactDOM.createRoot(container ? container.querySelector('#root') : document.querySelector('#root'));
  // root.render(
  //   <App />
  // );
  // note!!! if we use react 18 render method. ReactDom.createRoot, then the sub App would be empty in main app, also there isn't any error in qikuan. 
  ReactDOM.render(<React.StrictMode><App /></React.StrictMode>, container ? container.querySelector('#root') : document.querySelector('#root'));
}

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

export async function bootstrap() {
  console.log('[react18] react app bootstraped');
}

export async function mount(props) {
  console.log('[react18] props from main framework', props);
  render(props);
}

export async function unmount(props) {
  const { container } = props;
  //root.unmount(); 
  ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}
reportWebVitals();

这里要注意的就是,如果使用react 18的createRoot方法来render, 那么在main app里面,sub app是empty 并且qiankun也没有报错,我猜测是qiankun不支持。但是使用ReactDOM.render的话,react会有一个Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17.

所以现阶段结论就是: qiankun 2.8.4 还是先别用react 18了,搭配react 17正好~