从0到1构建一个qiankun项目

本教程适合刚接触qiankun的新人,介绍了如何从0构建一个qiankun项目

1、首先创建一个主应用

主应用不限技术栈,react或者vue都可以,只需要提供一个容器DOM,然后注册微应用并start开始

先安装qiankun:

yarn add qiankun // 或者 npm i qiankun -S

我是以react作为主应用的,首先注册微应用并启动。

// 在主应用的src下的index.js 里面注册微应用并启动

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
// import reportWebVitals from './reportWebVitals';
import { registerMicroApps, start } from 'qiankun';
import 'antd/dist/antd.less';
import { BrowserRouter } from 'react-router-dom';

// 注册
registerMicroApps([
    {
        name: 'vueApp',
        entry: '//localhost:8080',
        container: '#container',
        activeRule: '/app-vue',
    },
    {
        name: 'reactApp',
        entry: '//localhost:4000',
        container: '#container',
        activeRule: '/app-react',
    },
]);


// 启动
start();

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <BrowserRouter>
        <App />
      </BrowserRouter>
  </React.StrictMode>
);

// reportWebVitals();

/** 
 * 因为后续会加上 react-router-dom, 所以此处后续要记得加上 BrowserRouter
 * <BrowserRouter>
 *  <App />
 * </BrowserRouter>
 */

2、然后创建微应用

        2.1、vue微应用

                我是以vue-cli 3+生成的vue2.x项目为例

创建好之后修改main.js文件

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

Vue.config.productionTip = false

/** 文档中将此代码单独放到了一个文件中,此处是直接写在了 main.js 中,两种都可。但是 eslint-disable 需要加上 */
if (window.__POWERED_BY_QIANKUN__) { 
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

let instance = null;
function render(props = {}) {
    const { container } = props;
    // 文档中使用store,此处没有便删除了。
    instance = new Vue({
        router,
        render: h => h(App),
    }).$mount(container ? container.querySelector('#app') : '#app')
}

/** 独立运行时,直接渲染 */
if(!window.__POWERED_BY_QIANKUN__) {
    render();
}

export async function bootstrap() {
    console.log("[vue] vue app bootstraped")
}

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

export async function unmount() {
    instance.$destroy();
    instance.$el.innerHTML = "";
    instance = null;
}

接着配置router路由

// router/index.js

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const routes = [
    {
        path: '/',
        name: 'Home',
        component: () => import("./views/Home.vue")
    },
    {
        path: '/about',
        name: 'About',
        component: () => import("./views/About.vue")
    },
];

const router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? "/app-vue/" : "/",
    mode: "history",
    routes,
})

export default router;

最后修改打包配置文件,创建一个vue.config.js文件

const { name } = require("./package")

module.exports = {
    devServer: {
        headers: {
            "Access-Control-Allow-Origin": "*",
        },
    },
    configureWebpack: {
        output: {
            library: `${name}-[name]`,
            libraryTarget: "umd", /** 把微应用打包成 umd 库格式 */
            jsonpFunction: `webpackJsonp_${name}`,
        },
    },
};

        2.2、react微应用

                我使用的是react 16为例

首先在src目录下创建public-path.js

// public-path.js

if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

然后配置index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './public-path'
import reportWebVitals from './reportWebVitals';
import {BrowserRouter as Router } from 'react-router-dom';
import App from './App';

if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

function render(props) {
    const { container } = props;
    ReactDOM.render(
        <React.StrictMode>
            <Router basename={window.__POWERED_BY_QIANKUN__ ? '/app-react' : '/'}>
                <App />
            </Router>
        </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;
    ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

接下来就是配置webpack

首先使用 npm i react-app-rewired  引入插件

然后在根目录下新建config-overrides.js文件

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

module.exports = {
    webpack: (config, env) => {
        config.output.library = `${name}-[name]`;
        config.output.libraryTarget = 'umd';
        config.output.globalObject = 'window';
        config.output.chunkLoadingGlobal = `webpackJsonp_${name}`;
        return config;
    },
    devServer: (_) => {
        const config = _;
        config.headers = {
            'Access-Control-Allow-Origin': '*',
        };
        config.historyApiFallback = true;
        config.hot = false;
        config.watchContentBase = false;
        config.liveReload = false;
        config.injectClient = false
        return config;
    }
}

 最后修改一下package.json

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },

至此。微应用创建完毕

接下来配置主应用的app.js


import { useState } from 'react';
import { Layout, Menu } from 'antd';
import {
    PieChartOutlined,
    DesktopOutlined,
    ContainerOutlined,
     } from '@ant-design/icons';
import './App.css';
import { Link } from 'react-router-dom'

const { Header, Content, Footer, Sider } = Layout;

function getItem(label, key, icon, children, type) {
    return {
        key,
        icon,
        children,
        label,
        type,
    };
}

const items = [
    getItem((
        <Link to="/app-vue">
            Vue应用
        </Link>
    ), '1', <PieChartOutlined />),
    getItem((
        <Link to='/app-react'>
            React应用
        </Link>
    ), '2', <DesktopOutlined />),
    getItem((
        <Link to='/app-angular'>
            Angular应用
        </Link>
    ), '3', <ContainerOutlined />),
];

const App = () => {
    const [collapsed, setCollapsed] = useState(false);

    const onCollapse = collapsed => {
        setCollapsed(collapsed);
    };

    // const toggleCollapsed = () => {
    //     setCollapsed(!collapsed);
    // };

    return (
        // <div
        //     style={{
        //         width: 256,
        //     }}
        // >
        //     {/* <Button
        //         type="primary"
        //         onClick={toggleCollapsed}
        //         style={{
        //             marginBottom: 16,
        //         }}
        //     >
        //         {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
        //     </Button> */}
        //     <Menu
        //         defaultSelectedKeys={['1']}
        //         defaultOpenKeys={['sub1']}
        //         mode="inline"
        //         theme="dark"
        //         inlineCollapsed={collapsed}
        //         items={items}
        //     />
        // </div>
        <Layout style={{ minHeight: '100vh' }}>
            <Sider collapsible collapsed={collapsed} onCollapse={onCollapse}>
                <div className='logo' />
                <Menu
                defaultSelectedKeys={['1']}
                mode="inline"
                theme="dark"
                collapsed="true"
                items={items}
                />
                {/* <Menu theme='dark' defaultSelectedKeys={['1']} mode='inline'>
                    <Menu.Item key="1" icon={<PieChartOutlined />}>
                        <Link to="/app-vue">Vue应用</Link>
                    </Menu.Item>
                    <Menu.Item key="2" icon={<DesktopOutlined />}>
                        <Link to='/app-react'>React应用</Link>
                    </Menu.Item>
                </Menu> */}
            </Sider>
            <Layout className='site-layout'>
                <Header className='site-layout-background' style={{ padding: 0 }}  />
                <Content style={{ margin: '16px' }}>
                    <div id='container' className='site-layout-background' style={{ minHeight: 360 }}></div>
                </Content>
                <Footer style={{ textAlign: 'center' }}>
                    This Project ©2022 Created by Gorgio)
                </Footer>
            </Layout>
        </Layout>
    )
}

export default App;

配置完毕之后记得修改app.css,加上样式代码

#components-layout-demo-side .logo {
    height: 32px;
    margin: 16px;
    background: rgba(255, 255, 255, 0.3);
}

.site-layout .site-layout-background {
    background: #fff;
}

最后将主应用跟微应用都启动起来,这时候你会发现react默认的端口号都是3000,这时候就需要手动改一下微应用的端口号,这里就不作修改了,不会的自行百度吧。

启动成功之后会展示出来如下效果

 

至此,恭喜你完成了整个qiankun项目的搭建!!! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值