乾坤qiankun-微前端-简单搭建demo

Micro-frontend,微前端,顾名思义,前端也可以像后端一样通过多个微服务,搭建项目。只是后端的微服务架构是Spring Boot, 而前端我们可以使用qiankun实现前端的微服务架构。轻松现实大型项目的迭代重构升级以及拓展,不受牵一发而动全身的限制。下面介绍简单搭建微前端框架。
项目下载地址 demo

一.项目架构

 ├── base    # 主服务 - 可以是任意框架vue/react/angular/原生....
   ├── public   # 资源
   └── src  # 主要code
           └──  main.js 配置注册微服务信息,以及给子应用传参等...
├── app1-vue      # 微服务app1 - vue
   ├── public   # 资源
   ├── src  # 主要code
              └── main.js  # 配置 注册信息 bootstrap/mount/unmount 方法声明
   └── vue.config.js  # 配置允许跨域,以及端口
├── app2-react    # 微服务app2 - react
   ├── public   # 资源
   └── src  # 主要code
            └── index.js 配置 注册信息 bootstrap/mount/unmount 方法声明
    └── config-overrides.js  # 配置允许跨域,以及端口

二.搭建过程

1.创建vue主应用
创建Vue工程作为主服务,当然也可以是任意框架vue/react/angular/原生项目作为主应用。

vue create base

乾坤qiankun-微前端-简单搭建demo_第1张图片

安装 qiankun

npm install qiankun -s

在这里插入图片描述
在主应用vue中配置main.js,如下:

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
import {
    registerMicroApps, // 注册应用
    start, // 开启方法
} from 'qiankun';
const apps = [
    {
        name: 'vueApp', // 应用名字,这个是微应用app1
        entry: '//localhost:10000', //默认会加载这个html 解析里面的js(这里使用的fetch) 动态的执行(子应用必须支持跨域)
        container: '#vue', //容器名 挂载元素
        activeRule: '/vue', // 激活路径 激活规则,当访问 /vue时就会把这个应用挂载到 #vue上
        props: { a: 1 }, // 实现主应用给子应用传参
    },
    {
        name: 'reactApp', // 应用名字,这个是微应用app2
        entry: '//localhost:20000',
        container: '#react',
        activeRule: '/react',
        props: { b: 2 }, // 实现主应用给子应用传参
    },
];
registerMicroApps(apps); // 注册应用
start({
    // 开启
    prefetch: false, // 取消预加载
});

Vue.config.productionTip = false;

new Vue({
    router,
    render: h => h(App),
}).$mount('#app-base'); // 这里需要更改挂载节点,防止跟app1-vue的节点重名。

注意:根节点与Vue子应用重名将会报错,这里将根节点改为app-base,对应的index.html和app.vue也需要将id="app"改为id=“app-base”。具体改动如下:

  • public/index.html中,把
    改成
  • src/App.vue中,把
    改成

    public/index.html改动如下:
<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width,initial-scale=1.0" />
        <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
        <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
        <noscript>
            <strong>
                We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without
                JavaScript enabled. Please enable it to continue.
            </strong>
        </noscript>
        <!-- <div id="app"></div> -->
        <div id="app-base"></div> // 这里需要把app改成app-base,防止跟app1-vue的挂载节点重名
        <!-- built files will be auto injected -->
    </body>
</html>

App.vue中需要改动如下:

<template>
  <div id="app-base"> 
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
    <el-menu default-active="/" :router="true" mode="horizontal">
      <el-menu-item index="/">base</el-menu-item>
      <el-menu-item index="/vue">vue应用</el-menu-item>
      <el-menu-item index="/react">react应用</el-menu-item>
    </el-menu>
    <router-view></router-view>
    <div id="vue"></div>
    <div id="react"></div>
  </div>
</template>

2.创建app1-vue 子应用
按照上述创建主应用Vue工程创建一个vue项目

注意 vite目前暂不支持qiankun !!!
运行时报错
[import-html-entry]: error occurs while executing entry script http://localhost:40000/src/main.ts?t=1678894335319

vue create app1-vue

在跟目录下添加配置文件 vue.config.js 配置如下:

module.exports = {
    devServer: {
        port: 10000, // 跟父应用配置的子应用端口一致
        headers: {
            // 因为qiankun内部请求都是fetch来请求资源,所以子应用必须允许跨域
            'Access-Control-Allow-Origin': '*',
        },
    },
    configureWebpack: {
        output: {
            //资源打包路径
            library: 'vueApp',
            libraryTarget: 'umd',
        },
    },
};

配置src/main.js
父应用之所可以加载子应用,是因为子应用必须暴露三个接口:bootstrap,mount,unmount。

import Vue from 'vue';
import App from './App.vue';
// Vue.config.productionTip = false

let instance = null;
function render(props) {
    instance = new Vue({
        render: h => h(App),
    }).$mount('#app'); // 这里是挂载到自己的html中  base会拿到这个挂载后的html 将其插入进去
}

// 动态添加publicPath
if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 默认独立运行
if (!window.__POWERED_BY_QIANKUN__) {
    render();
}

// 父应用加载子应用,子应用必须暴露三个接口:bootstrap,mount,unmount

/**
 * required
 * bootstrap z只会在微应用初始化时调用一次,下次微应用重新进入时会直接调用mount钩子,不会再重复触发,bootstrap.
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在unmount 阶段被销毁的应用级别的缓存等。
 *
 */

export async function bootstrap(props) {
    console.log('bootstrap:', props);
}
/**
 * required
 * 应用每次进入都会调用mount方法,通常我们在这里触发应用渲染方法
 */
export async function mount(props) {
    console.log('mount:', props);
    render(props);
}

/**
 * required
 * 应用每次 切出/卸载 都会调用的方法
 * 通常我们会卸载微应用的应用实例
 */
export async function unmount(props) {
    console.log('unmount:', props);
    instance.$destroy();
    instance.$el.innerHTML = '';
    instance = null;
}
/**
 * not required
 * 仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {
    console.log('update props', props);
}

3.创建app2-react 子应用

npm install -g create-react-app
create-react-app app2-react

src/index.js中配置挂载信息,暴露父应三个接口:bootstrap,mount,unmount。

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
// import reportWebVitals from './reportWebVitals';

// const root = ReactDOM.createRoot(document.getElementById('root'));
// root.render(
//   
//     
//   
// );

// 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();

const root = ReactDOM.createRoot(document.getElementById('root'));
function render() {
    root.render(
        <React.StrictMode>
            <App />
        </React.StrictMode>
    );
    // ReactDOM.render(
    //     
    //         
    //     ,
    //     document.getElementById('root')
    // );
}
if (!window.__POWERED_BY_QIANKUN__) {
    render();
}

export async function bootstrap(props) {
    console.log('bootstrap:', props);
}

export async function mount(props) {
    console.log('mount:', props);
    render();
}

export async function unmount(props) {
    console.log('unmount:', props);
    // 卸载节点
    // ReactDOM.unmountComponentAtNode(document.getElementById('root'));
    root.unmount();
}

项目引入配置依赖react-app-rewired

npm install react-app-rewired -D

在根目录添加config-overrides.js,配置如下:

module.exports = {
    webpack: config => {
        config.output.library = 'reactApp';
        config.output.libraryTarget = 'umd';
        config.output.publicPath = 'http://localhost:20000'; // 此应用自己的端口号
        return config;
    },
    devServer: configFunction => {
        return function (proxy, allowedHost) {
            const config = configFunction(proxy, allowedHost);
            config.port = '20000';
            config.headers = {
                'Access-Control-Allow-Origin': '*',
            };
            return config;
        };
    },
};

package.json中修改启动方式如下:

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

运行项目

1.运行主项目

cd base
npm run serve

2.运行子应用

cd app1-vue
npm run serve

3.运行子应用

cd app1-react
npm run start

主应用配置的vue子应用的运行端口为10000,react子应用的端口号为20000,三个项目分别启动成功后就可以通过主应用来访问了。这时子应用就会加载到主应用里面。子应用也可以通过各自的端口单独访问。

乾坤qiankun-微前端-简单搭建demo_第2张图片
app1-vue子应用效果
乾坤qiankun-微前端-简单搭建demo_第3张图片
app2-react 子应用效果
乾坤qiankun-微前端-简单搭建demo_第4张图片

你可能感兴趣的:(架构,前端,前端,javascript,前端框架,微前端,Micro-frontend)