乾坤微前端部署vue和react子应用

一、安装乾坤父应用

1.以umi创建一个react工程,开启乾坤插件

    
mkdir myapp && cd myapp
yarn add @umijs/plugin-qiankun -D

2. 父工程添加qiankun插件

yarn add @umijs/plugin-qiankun -D

3.修改 .umirc.ts 配置文件

import { defineConfig } from 'umi';
​
export default defineConfig({
  title: '乾坤微应用demo',
  layout:{
    name: '乾坤微应用demo',
  },
  qiankun: {
    slave:{},
    master: {
      // 注册子应用信息
      apps: [
        {
          name: 'vue-app', // 唯一 id
          entry: '//localhost:9001',
          props:{},
        },
        {
          name: 'react-app', // 唯一 id
          entry: '//localhost:9000',
          props:{},
        },
      ],
    },
  },
  fastRefresh:{},
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    { path: '/home', component: '@/pages/index' },
    // 配置微应用 app1 关联的路由
    {
      path: '/vue-app',
      name: 'vue子应用',
      microApp: 'vue-app',
      props: {
        onClick: (e: any)=>console.log(e),
        name: 'vue子应用',
      },
    },
    {
      path: '/react-app',
      name: 'react子应用',
      microApp: 'react-app',
      props: {
        onClick: (e: any)=>console.log(e),
        name: 'react子应用',
      },
    },
  ],
});

二、安装vue子应用

1.安装vue-cli3

由于vue-cli高版本有许多问题,这里选择4以下的版本进行安装

npm i [email protected]

2.新增vue.config.js

配置vue.config.js如下:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {VueLoaderPlugin} = require("vue-loader");
module.exports = {
    entry: {
        main: path.join(__dirname, 'src', 'main.ts'),
    },
    output: {
        library: 'vue-app-[name]',
        libraryTarget: 'umd',
        jsonpFunction: 'webpackJsonp_vue',
    },
    module: {
        rules: [
            {
                test: /\.(tsx|ts)?$/,
                use: [
                    {
                        loader: 'ts-loader',
                        options: {
                            transpileOnly: true,    //只进行语法转换,不进行类型校验,提高构建速度
                        }
                    }
                ],
                exclude: [/node_modules/],
            },
            {
                test: /\.(js|jsx)$/,
                // 如果js文件在node_modules里边,就不使用babel-loader了
                // 因为它里边的代码都是些第三方代码,已经做好了转译的工作。
                exclude: [/node_modules/],
                use: [{
                    loader: "babel-loader",
                    options: {
                        //将async/await转化为es5语法,需要用到regeneratorRuntime函数,这个函数在babel-runtime包中
                        plugins: ["@babel/plugin-transform-runtime"]
                    },
                },
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.less$/,//处理.less文件
                use: ["style-loader", "css-loader", "less-loader"],
            },
            {
                test: /\.html$/,
                loader: 'html-loader',
                options: {
                    esModule: false
                }
            },
            {
                //处理图片资源
                test: /\.(png|jpg|jpeg|gif|bmp|stl|fbx|gltf)$/,
                loader: 'url-loader',
                options: {
                    //图片小于1024kb,就会被base64处理,一般处理8-12KB的图片
                    //优点: 减少请求数量
                    //缺点: 图片体积会变大
                    // limit: 1024 * 1024,
                }
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader',
            }
        ]
    },
    plugins: [
        //生成一个 HTML5 文件, 其中包括使用 script 标签的 body 中的所有 webpack 包。
        new HtmlWebpackPlugin({
            title: 'vue-app子应用',
            template: path.resolve(__dirname, "src/index.html"),
            filename: "index.html"
        }),
        new VueLoaderPlugin(),
    ],
    resolve: {
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.png', 'vue'],
        alias: {
            "@": path.resolve(__dirname, "src"),
        }
    },
    devServer: {
        hot: true,//热更新
        compress: true,
        host: "127.0.0.1",
        open: false,
        port: 9001,
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    }
}

3.安装其他plugin和loader

我安装的依赖如下:

"dependencies": {
    "core-js": "^2.6.5",
    "vue": "^2.6.10",
    "vue-router": "^3.0.3",
    "vuex": "^3.0.1",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.1"
  },
  "devDependencies": {
    "@umijs/plugin-qiankun": "^2.43.1",
    "@vue/cli-plugin-babel": "^3.12.0",
    "@vue/cli-plugin-typescript": "^3.12.0",
    "@vue/cli-service": "^3.12.0",
    "@babel/plugin-transform-runtime": "^7.16.8",
    "compression-webpack-plugin": "^9.2.0",
    "file-loader": "^6.2.0",
    "glob": "^7.2.0",
    "happypack": "^5.0.1",
    "html-loader": "1.3.0",
    "html-webpack-plugin": "^4.4.1",
    "less": "^4.1.2",
    "less-loader": "^7.3.0",
    "mockjs": "^1.1.0",
    "mockjs-fetch": "^1.0.3",
    "thread-loader": "^3.0.4",
    "ts-loader": "^4.0.0",
    "vue-loader": "15.10.1",
    "typescript": "^4.5.4",
    "url-loader": "^4.1.1",
    "style-loader": "^2.0.0",
    "css-loader": "^0.23.1",
    "webpack-node-externals": "^3.0.0",
    "vue-template-compiler": "^2.6.10"
  },

4.修改子应用package.json中的name属性

name属性要与父工程中注册的子应用名保持一致。

我这里使用的是vue-app。

{
  "name": "vue-app",
},

5.给vue子应用添加qiankun插件

yarn add @umijs/plugin-qiankun -D

6.修改入口文件和router文件

我这里的入口文件是main.ts,与webapck中配置的entry一致。

main.ts

import Vue from 'vue';
import App from './App.vue';
import routes from './router';
import store from './store';
import VueRouter from 'vue-router';
​
Vue.use(VueRouter);
Vue.config.productionTip = false;
​
let route:any;
let instance:any;
function render(props = {}) {
  // @ts-ignore
  const {container} = props;
  route = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? '/qiankun/vue-app' : '/',
    mode: 'history',
    routes: routes,
  });
  instance = new Vue({
    router: route,
    // store,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}
​
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}
​
export async function bootstrap() {
  console.log('vue子应用bootstrap');
}
​
export async function mount(props: {}) {
  console.log('vue子应用mount');
  render(props);
}
​
export async function unmount(props: {}){
  console.log('vue子应用unmount', props);
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance =null;
  route = null;
}

router.ts

import Home from './views/Home.vue';
import About from './views/About.vue';
​
let routes = [
  {
    path: '/',
    name: 'home',
    component: Home,
  },
  {
    path: '/about',
    name: 'about',
    component: About,
  },
]
export default routes;

注意上面component中组件引入方式如果使用懒加载方式,会报错找不到chunk包。

三、最终效果

1.父应用

乾坤微前端部署vue和react子应用_第1张图片

2.子应用

乾坤微前端部署vue和react子应用_第2张图片

四、安装react子应用

说明

react子应用部署步骤与vue类似,除开乾坤生命周期写法有些不同外,然后就是基础路由替换方式有些不同,其他没有什么区别。

main.js中添加

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';
import './index.less';
import './public-path';
import { BrowserRouter } from 'react-router-dom';
const initApp = container =>{
    ReactDOM.render(
        
            
        ,
        container?container.querySelector('#root'):document.getElementById('root')
    );
}
​
if(!window.__POWERED_BY_QIANKUN__){
    initApp();
}
export async function bootstrap() {
    console.log('react子应用bootstrap');
}
export async function mount(props) {
    const {container} = props;
    console.log('react子应用挂载', props);
    initApp(container);
}
​
export async function unmount(props){
    console.log('react子应用unmount', props);
    const {container} = props;
    ReactDOM.unmountComponentAtNode(container.querySelector('#root'));
}

public-path.js

if(window.__POWERED_BY_QIANKUN__){
    __webpack_pubilc_path = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

1.替换基础路由

如果不替换基础路由,可能会出现在react项目本地可以访问,但是乾坤主应用上面会提示匹配不到路由。

这里我采用的是在routes文件夹里对所有路由前面加一个变量base,例如:

const base = window.__POWERED_BY_QIANKUN__ ? "qiankun/react-app" : '';
const routes = [
    {
        path: '/',
        component: () => import('../route/Demo')
    },
]
const exportRoutes = routes.map(item => {
    return {
        path: base + item.path,
        component: asyncComponent(item.component) //asyncComponent 处理异步加载组件
    }
})

如果当当前环境处于乾坤主应用环境时候,给所有路由加一个"qiankun/react-app",这样就能匹配上路由了

五、父子应用通信

六、可能遇到的问题

1.安装loader和plugin时候,版本不兼容问题。

解决办法: 替换对应loader和plugin版本。

2.webpack启动时候报的一些错误

解决办法:仔细观察看是插件和loader版本不兼容问题,还是缺少插件和loader去处理某个资源文件。缺少的话就手动添加一下在重新启动。

3.devserver版本与webapck版本不兼容问题

解决方法: 修改devserver版本

4.系统报'you need to export lifecycle funtions in app-vue entry'

解决办法:安照上面修改main.ts里面的方法,给乾坤环境添加生命周期函数并导出。

5.如果vue启动没问题,但是父应用访问子应用资源报404

解决办法:检查webapck配置输出,按照上面vue.config.js配置output中,library设置为 '子应用名-[name]'。

 output: {
        library: 'vue-app-[name]',
        libraryTarget: 'umd',
        jsonpFunction: 'webpackJsonp_vue',
    },

你可能感兴趣的:(前端,vue.js,react.js)