最近因为面试被面问到了mico-frontend, 所以就准备学习一下。做了两个demo,一个是基于module federation, 这个的demo有很多。另外一个based on qiankun。
- qiankun: 2.8.4
- react: 18
两个app:
- 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();
- 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正好~