qiankun 主项目和子项目都是 vue2,部署在不同的服务器上,nginx 配置

news2024/11/23 15:37:02

1、主项目配置

        1.1 micro.vue 组件

<template>
  <div id="container-sub-app"></div>
</template>

<script>
import { loadMicroApp } from 'qiankun';
import actions from '@/utils/actions.js';

export default {
  name: 'microApp',
  mixins: [actions],
  data() {
    return {
      microApp: null
    };
  },
  mounted() {
    const getMicroInfo = this.getMicroInfo();
    this.microApp = loadMicroApp(getMicroInfo, {
      singular: true
    });
  },
  beforeDestroy() {
    console.log('beforeDestroy...');
    this.microApp.unmount();
  },
  methods: {
    // 手动加载微应用
    getMicroInfo() {
      const appIdentifying = this.$route.path.split('/')[1];
      let data = {};
      const href = window.location.host;
      for (let i = 0; i < document.subApps.length; i++) {
        const element = document.subApps[i];
        if (element.activeRule.includes(appIdentifying)) {
          if (typeof element.entry !== 'string') {
            data = {
              ...element,
              entry: element.entry[href]
                ? element.entry[href]
                : Object.values(element.entry)[0]
            };
          } else {
            data = { ...element };
          }
          data.props = {
            token: {
              userInfo: {
                userName: '小明',
                userId: '123',
                date: new Date().toLocaleString()
              }
            }
          };
          data.activeRule = [appIdentifying];
          break;
        }
      }
      return data;
    }
  }
};
</script>

   1.2 index.html 引入配置

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
    />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <script src="<%= BASE_URL %>register-apps.js"></script>
    <title><%= webpackConfig.name %></title>
  </head>
  <body>
    <noscript>
      <strong
        >We're sorry but <%= webpackConfig.name %> doesn't work properly without
        JavaScript enabled. Please enable it to continue.</strong
      >
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

        1.3 register-apps.js 配置

document.subApps = [
  {
    name: 'besFront',
    //entry: '//localhost:8086/bes-front/',// 本地调试
    entry: '/bes-front/',// 部署到服务器
    container: '#container-sub-app',
    activeRule: '/bes-front'
  }
];

        1.4 路由配置

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

Vue.use(Router);

import Layout from '@/layout';
import MicroApp from '@/components/microApp';

export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },
  {
    path: '/dashboard',
    component: Layout,
    redirect: '/dashboard/index',
    children: [
      {
        path: 'index',
        name: 'Dashboard',
        component: () => import('@/views/dashboard/index'),
        meta: { title: 'Dashboard', icon: 'dashboard' }
      }
    ]
  },
  {
    path: '/',
    component: Layout,
    children: [
      {
        path: 'bes-front',
        component: MicroApp// 重点,用于加载子项目
      }
    ]
  }
  // 404 page must be placed at the end !!!
  // { path: '*', redirect: '/404', hidden: true }
];

const createRouter = () =>
  new Router({
    mode: 'history', // require service support
    base: '/parent/',// 部署在不同服务器上,主应用加前缀
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRoutes
  });

const router = createRouter();

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter();
  router.matcher = newRouter.matcher; // reset router
}

export default router;

2、子项目配置

        2.1 main.js 配置

// 动态设置 publicPath
import './public-path';
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.config.productionTip = false;
Vue.use(ElementUI);

let instance = null;
function render(props = {}) {
  console.log('子应用 render props::', props, 'instance====', instance);
  // sessionStorage.setItem('userInfo', JSON.stringify(props.token.userInfo));
  const { container } = props;

  instance = new Vue({
    router,
    store,
    render: (h) => h(App)
  }).$mount(container ? container.querySelector('#app') : '#app');
}

// 独立运行时
/* eslint-disable */
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

export async function bootstrap() {
  console.log('子应用 bootstrap ===========================');
}

let initialState = null;
export async function mount(props) {
  console.log('子应用 mount props ===============', props);
  sessionStorage.setItem('userInfo', JSON.stringify(props.token.userInfo));
  props.onGlobalStateChange((state, prev) => {
    // state: 变更后的状态; prev 变更前的状态
    console.log('子应用获取共享数据 state::', state, 'prev::', prev);
    // 接收主应用中的共享数据 并将其设置为全局变量
    Vue.prototype.$initialState = state;
  });
  props.setGlobalState({
    initialState:
      '子应用中修改主应用中的全局变量,实现住应用子应用间数据的双向双向通信'
  });

  render(props);
}
export async function unmount() {
  console.log('子应用 unmount==========');
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance = null;
}

        2.2  public-path 文件

if (window.__POWERED_BY_QIANKUN__) {
  /* eslint-disable @typescript-eslint/camelcase */
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

        2.3 vue.config.js 配置

'use strict';
const path = require('path');
const defaultSettings = require('./src/settings.js');
const proxyTable = require('./proxyTable');

function resolve(dir) {
  return path.join(__dirname, dir);
}

const name = defaultSettings.title || 'vue Admin Template'; // page title

// If your port is set to 80,
    // use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
const port = process.env.port || process.env.npm_config_port || 9528; // dev port

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
  publicPath: '/bes-front/',
  outputDir: 'dist',
  assetsDir: 'static',
  lintOnSave: process.env.NODE_ENV === 'development',
  productionSourceMap: false,
  devServer: {
    headers:{
        "Access-Control-Allow-Origin": "*",
    },
    port: port,
    open: true,
    proxy: proxyTable,
    overlay: {
      warnings: false,
      errors: true
    }
  },
  configureWebpack: {
    // provide the app's title in webpack's name field, so that
    // it can be accessed in index.html to inject the correct title.
    name: name,
    output:{
        library: `besFront`,// 主应用
        libraryTarget: "umd",// 把微应用打包成 umd 库格式
        jsonpFunction: `webpackJsonp_besFront`,// webpack5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
    },
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
  },
  chainWebpack(config) {
    // it can improve the speed of the first screen, it is recommended to turn on preload
    config.plugin('preload').tap(() => [
      {
        rel: 'preload',
        // to ignore runtime.js
        // https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/lib/config/app.js#L171
        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
        include: 'initial'
      }
    ]);

    // when there are many pages, it will cause too many meaningless requests
    config.plugins.delete('prefetch');

    // set svg-sprite-loader
    config.module.rule('svg').exclude.add(resolve('src/icons')).end();
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end();

    config.when(process.env.NODE_ENV !== 'development', (config) => {
      config
        .plugin('ScriptExtHtmlWebpackPlugin')
        .after('html')
        .use('script-ext-html-webpack-plugin', [
          {
            // `runtime` must same as runtimeChunk name. default is `runtime`
            inline: /runtime\..*\.js$/
          }
        ])
        .end();
      config.optimization.splitChunks({
        chunks: 'all',
        cacheGroups: {
          libs: {
            name: 'chunk-libs',
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: 'initial' // only package third parties that are initially dependent
          },
          elementUI: {
            name: 'chunk-elementUI', // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
          },
          commons: {
            name: 'chunk-commons',
            test: resolve('src/components'), // can customize your rules
            minChunks: 3, //  minimum common number
            priority: 5,
            reuseExistingChunk: true
          }
        }
      });
      // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
      config.optimization.runtimeChunk('single');
    });
  }
};

         2.3  接口需加前缀区分

const uri = '/child1/api';

// 部门新增
export async function departmentAddApi(params) {
  return $ajax.post(`${uri}/department/add`, params);
}

3、主项目和子项目部署在不同的服务器上,其中主应用路由使用history模式,子应用路由使用hash模式,子应用所有的静态资源及接口统一从主应用进行转发,nginx 配置如下:

主应用 nginx 配置:

locatoin /parent/ {
    root /opt/parent;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
}


location /bes-front/ {
    proxy_pass http://子应用ip/bes-front/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE_HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}


location /bes-front/static/ {
    proxy_pass http://子应用ip/bes-front/static/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE_HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}


location /child1/ {
    proxy_pass http://子应用ip/child1/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE_HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

注:使用的下面这种部署方式,主应用代码放在主应用服务器的/opt/parent目录下,子应用代码放在子应用服务器的/opt/bes-front目录下面,重点是主应用的路由要加前缀进行区分,其次,子应用的所有接口转发都统一从主应用转发到子应用,因此子应用的接口要增加前缀进行区分

官网参考链接:https://qiankun.umijs.org/zh/cookbook#%E5%9C%BA%E6%99%AF-2%E4%B8%BB%E5%BA%94%E7%94%A8%E5%92%8C%E5%BE%AE%E5%BA%94%E7%94%A8%E9%83%A8%E7%BD%B2%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BD%BF%E7%94%A8-nginx-%E4%BB%A3%E7%90%86%E8%AE%BF%E9%97%AE

4、总结

在部署主应用和子应用时,遇到两个核心问题

1、主应用路由未加前缀,导致主应用转发到子应用时,脱离了qiankun框架直接访问子应用的静态资源,致使的结果是,无法再返回到主应用。

2、如果要求子应用接口都统一从主应用转发,那么子应用接口需要前缀进行区分。

3、最后,静态资源的问题,多半是子应用的 publicPath 配置有关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2203523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react实现实时计时的最简方式

js中时间的处理&#xff0c;不借助于moment/dayjs这样的工具库&#xff0c;原生获取格式化的时间&#xff0c;最简单的实现方式可以参考下面这样。 实现效果 代码实现 封装hooks import { useState, useEffect } from "react";export function useCountTime() {c…

Linux——which-find命令

which命令 查找命令的程序文件&#xff08;二进制 find命令 按文件名查找文件 find / -name "test" 命令 路径(根目录 命令选项 查找文件名 find命令 -name 模糊查询 find / -name "…

Linux:进程控制(三)——进程程序替换

目录 一、概念 二、使用 1.单进程程序替换 2.多进程程序替换 3.exec接口 4.execle 一、概念 背景 当前进程在运行的时候&#xff0c;所执行的代码来自于自己的源文件。使用fork创建子进程后&#xff0c;子进程执行的程序中代码内容和父进程是相同的&#xff0c;如果子进…

Python入门笔记(七)

文章目录 第十五章. 下载数据15.1 csv文件15.2 json文件 第十六章. 使用API16.1 requests 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转&#xff1a;人工智能从入门到精通教程 本文电子版获取…

猫头虎分享已解决Bug || Error: ERESOLVE unable to resolve dependency tree 解决方案

&#x1f42f; 猫头虎分享已解决Bug || Error: ERESOLVE unable to resolve dependency tree 解决方案 摘要 在前端开发中&#xff0c;尤其是使用 Node.js 和 npm 管理依赖时&#xff0c;ERESOLVE unable to resolve dependency tree 错误是很多开发者遇到的常见问题。这个 Bu…

ES 入门 -http-条件查询分页查询查询排序

第一种方法的url 地址: http://192.168.1.108:9200/shopping/_search?qcategory:小米 上述url地址的情况&#xff0c;对应的后面的参数信息包含中文&#xff0c;有些时候也会出现乱码导致无法查询到数据&#xff0c; 第二种方式进行body的row -json的传参方式. { "que…

双十一最值得购买的好物?这四款数码好物一定要收藏好!

随着双十一购物节的脚步日益临近&#xff0c;消费者们的热情也在逐渐升温&#xff0c;大家都在翘首以待这场年度购物狂欢。回顾过去&#xff0c;我在双十一期间入手的不少商品都显得格外物超所值&#xff0c;与平日相比确实省下了不少开支。我很高兴能够分享这些精明的购物心得…

【图论】(一)图论理论基础与岛屿问题

图论理论基础与岛屿问题 图论理论基础深度搜索&#xff08;dfs&#xff09;广度搜索&#xff08;bfs&#xff09;岛屿问题概述 岛屿数量岛屿数量-深搜版岛屿数量-广搜版 岛屿的最大面积孤岛的总面积沉没孤岛建造最大人工岛水流问题岛屿的周长 图论理论基础 这里仅对图论相关核…

《企业实战分享 · SonarQube10.x 代码质量推广手册》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

【AI算法岗面试八股面经【超全整理】——CV】

AI算法岗面试八股面经【超全整理】 概率论【AI算法岗面试八股面经【超全整理】——概率论】信息论【AI算法岗面试八股面经【超全整理】——信息论】机器学习【AI算法岗面试八股面经【超全整理】——机器学习】深度学习【AI算法岗面试八股面经【超全整理】——深度学习】NLP【A…

vbox创建虚拟机后用户没有root 权限

XXX is not in the sudoers file. This incident will be reported. 打开终端输入 Su - 输入密码进入root账户 终端visudo修改配置文件 添加如下代码&#xff1a;Syy ALL(ALL:ALL) ALL 编写完成后保存文件 ctrlO 后输入文件名 sudoers.tmp 后按Enter键 退出编辑器&#xf…

018 发布商品

文章目录 获取分类关联的品牌CategoryBrandController.javaCategoryBrandServiceImpl.javaBrandVo.java 获取分类下的所有分组&关联属性AttrGroupController.javaAttrGroupServiceImpl.java 保存七张表sqltb_spu_info.sqltb_spu_info_desc.sqltb_spu_images.sqltb_product_…

UE4 材质学习笔记06(布料着色器/体积冰着色器)

一.布料着色器 要编写一个着色器首先是看一些参考图片&#xff0c;我们需要找出一些布料特有的特征&#xff0c;下面是一个棉织物&#xff0c;可以看到布料边缘的纤维可以捕捉光线使得边缘看起来更亮 下面是缎子和丝绸的图片&#xff0c;与棉织物有几乎相反的效果&#xff0c;…

基于SPI的flash读写操作

1、实验目标 使用页写或连续写操作向Flash芯片写入数据&#xff0c;再使用数据读操作读取之前写入数据&#xff0c;将读取的数据使用串口传回PC机&#xff0c;使用串口助手传回数据并与之前写入数据比较&#xff0c;判断正误。 注意&#xff1a;在向Flash芯片写入数据之前&…

【Redis原理】数据结构(上)

文章目录 动态字符串(SDS)概念SDS特点SDS的优势 IntSet概念IntSet的特点升序统一的编码格式IntSet自动升级 Dict概念Dict特点Dict的伸缩Dict的扩容Dict收缩 Dict的rehash渐进式哈希 总结Dict的结构Dict的伸缩 动态字符串(SDS) 概念 Redis是使用C语言实现的,C语言字符串底层是…

【后端开发】自动化部署、服务管理、问题排查工具(cicd流水线,k8s集群,ELK日志)

【后端开发】自动化部署、服务管理、问题排查工具&#xff08;cicd流水线&#xff0c;k8s集群&#xff0c;ELK日志&#xff09; 文章目录 1、Devops与CICD流水线(TeamCity, Jenkins&#xff0c;GitHub Actions)2、Kubernetes 集群的管理和操作&#xff08;对比Portainer&#x…

【解决】Set-ExecutionPolicy不是内部或外部命令

简介 当使用 VsCode 配置Django项目时&#xff0c;需要配置环境&#xff0c;但是当切换至虚拟环境时&#xff0c;出现了下面的情况。 无法加载文件&#xff1a;D:\django\Scripts\Activate.ps1&#xff0c; 上述问题可通过下面的命令进行解决 解决方法 1 命令行(最好是管理员…

JVM进阶调优系列(1)类加载器原理一文讲透

今天开始写JVM调优系列&#xff0c;并发编程系列也会继续穿插连载&#xff0c;让各位同学闲暇之余有更多阅读选择。 起笔写第一篇&#xff0c;并不好写。首先要构思整个系列的大概框架&#xff0c;一个好的框架一定是深度上由浅入深、逻辑上有严格顺序&#xff0c;读者订阅跟踪…

免费获取的8个SVG图标库,轻松下载与复制!

SVG图标相比传统的JPG、PNG图标具有诸多优势&#xff0c;适用于各种类型的图像&#xff0c;不仅能在不同尺寸下保持清晰度&#xff0c;还具备高度压缩性和轻量特性&#xff0c;支持静态和动态效果。因此&#xff0c;SVG格式在网页设计中往往是优选。尽管如今有很多免费的图标库…

风扇PD协议取电协议芯片-ECP 5702

随着USB-C的普及&#xff0c;市面上消费者PD充电器越来越多&#xff0c;如何让小家电产品也能够支持PD协议快充呢&#xff1f;加入一颗能芯科技PD协议取电协议芯片ECP5702试试看 USB PD协议受电端诱骗协议芯片 1、概述 ECP5702是能芯科技开发的一款专门PD协议的Sink控制器。 …