# 为什么使用qiankun框架?
我们项目使用的初衷是为了解决一个后台项目的重构问题,因为项目太过庞大,vue2升级vue3选择了重构,希望可以两个项目并行操作,这也就是我们使用qiankun的理由吧。我想很大原因还是iframe有很大的局限性,导致很多人选择qiankun这种微前端框架吧。
主项目配置
这是我自己根据qiankun框架重新搭建了一个项目,公司的项目不适合放到这里。主项目和子项目都是根据react和webpack进行构建的
import {} from "react-router-dom";
import {Outlet} from "react-router-dom";
import LeftMenu from './components/layout/LeftMenu';
import { Layout } from 'antd';
import { registerMicroApps, start } from 'qiankun';
import "./index.less";
const { Header, Footer, Sider, Content } = Layout;
export default () => {
// qiankun框架初始化
const initQiankunHandler = () => {
registerMicroApps([
{
name: "op-first", // 名字
entry: "//localhost:3000/", // 需要加载的本地地址,如果放到线上这块需要修改为子项目线上地址
container: "#firstApp", // 子项目的容器,主项目这个id一定要定义好,不然子项目会没有容器而不显示
activeRule: "/firstApp" // 这是子项目的路由,访问这种路由开头的时候会访问子项目
/**
activeRule: (location: Location) => {
这里也可以放回一个布尔值告诉qiankun这是主项目路由还是子项目路由
},
*/
}
])
start()
}
React.useEffect(() => {
initQiankunHandler()
}, [])
return (
<>
<Layout>
<LeftMenu />
<Layout>
<Header>Header</Header>
<Content>
<Outlet />
<div id='firstApp'></div>
</Content>
<Footer>Footer</Footer>
</Layout>
</Layout>
</>
);
}
子项目配置
webpack配置
const path = require('path');
const HtmlWebapckPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js'
},
output: {
// asyncChunks: true,
// filename: '[name].[contenthash].bundle.js',
// path: path.resolve(__dirname, 'dist'),
// 这里也要有这三个配置项
library: `test-[name]`,
libraryTarget: 'umd',
// webpack5将qiankun官网上的jsonpFunction改为了chunkLoadingGlobal
chunkLoadingGlobal: `webpackJsonp_test`
},
mode: 'development',
devtool: 'source-map',
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 3000,
historyApiFallback: true,
hot: true,
// 这里一定要允许跨域,不然会导致主项目加载子项目过程中产生跨域问题,加载不进去
headers: {
'Access-Control-Allow-Origin': '*',
},
// proxy: {
// '/api': {
// target: '',
// pathRewrite: { '^/api': '' },
// changeOrigin: true
// }
// }
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'scss-loader']
},
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.tsx?$/,
use: ['babel-loader','ts-loader'],
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebapckPlugin({
title: 'react-project',
template: './public/index.html'
})
]
}
项目根目录下添加一个public-path.js 文件 添加下边这行代码
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
然后在项目初始化文件中抛出qiankun的生命周期函数
import ReactDom from 'react-dom';
import RenderRouters from './routers/index.tsx';
import '../public-path';
// ReactDom.render(RenderRouters(), document.getElementById('App'));
function render(props) {
const { container } = props;
console.log(ReactDom, container, '>><><<aaa')
ReactDom.render(RenderRouters(), container ? container.querySelector('#firstApp') : document.querySelector('#firstApp'));
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log('[react16] react app bootstraped');
}
export async function mount(props) {
console.log('[react16] props from main framework', props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDom.unmountComponentAtNode(container ? container.querySelector('#firstApp') : document.querySelector('#firstApp'));
}
这样子项目的配置也就好了
线上发布
线上发布的话可以在qiankun加载子项目的entry根据env配置不同的路径,我们是主项目和子项目部署到一个服务器上,通过ng配置不同的location进行区分,主项目不配置location这样取得就是ng上默认访问的html资源路径,然后在配置一个serve配置location这样的话访问这个服务器的域名再加一个location就能访问到子项目资源了。
// 主项目
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
}
子项目
server {
...
location /child {
root html;
index index.html index.htm;
}
}
这样配置的话子项目资源访问就会有一点的问题,因为子项目的资源不能直接通过域名进行访问了,需要域名/child进行访问,这样的话子项目打包的时候需要在,这是以webpack打包示例,output这个属性下,添加一个publicPath: /child属性这样的话,子项目加载资源的时候会默认添加一个/child,这样就可以调通了,剩下的就可以交给运维了。
iconfont样式问题
如果主子项目icon的前缀名一样会造成icon混乱问题,我的解决思路是修改fontClss的前缀
主子项目可以进行命名区分,这样就可以避免icon混乱问题。
[class^="op-main-"], [class*=" op-main-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'op-main-iconfont' !important;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
主子项目UI框架的样式隔离问题
这个下篇文章再说下吧,解决思路的话是通过babel来进行修改子项目中UI框架的class名来进行的样式隔离。
项目gitee地址:gitee.com/xuxuqingson…