基于micro-app+vue-element-admin实现微前端

news2024/9/30 5:40:40

简述

本文是在对之前搭建和学习micro-app的基础上的进一步研究学习。
因为我们目前项目使用的框架是vue-element-admin,所以还需要研究一下micro-app在vue-element-admin的使用方法。
关于micro-app在vue-element-admin的实现,百度什么也没找到,只能按照之前搭建的micro-app的基础模仿着搭建着自己搞。

接下来开始搭建

1、创建项目目录

关于目录的创建,新增文件夹micro-app-element,文件夹中有三个vue-element-admin项目:vue-element-base(基座)、vue-element-first(子应用1)、vue-element-second(子应用2)
具体如下图所示:
在这里插入图片描述
其中vue-element-base(基座)、vue-element-first(子应用1)、vue-element-second(子应用2)是创建的vue-element-admin项目,如果不会创建,可参考
我这边是之前创建好的现成的包,拿过来直接解压了三个修改了一下名称,一个基座两个个子应用,项目内容大致如下
在这里插入图片描述

2、基座配置

我这边按之前搭建micro-app的过程一步步来,只是把之前的创建项目的过程省略掉了,现在直接用现成的vue-element-admin,搭建参考
注:接下来的配置都是在vue-element-base中进行配置的

2-1、配置vue.config.js

之前搭建的时候配置了localhost和port端口,vue-element-admin看情况是封装好的,不用修改太多
在这里插入图片描述

2-2、安装micro-app

安装micro-app插件,安装在base目录下

npm install @micro-zoe/micro-app --save

安装完成后,可以在基座package.json中看到安装好的@micro-zoe/micro-app,如下图所示:
在这里插入图片描述

2-3、配置micro

创建micro配置文件夹,配置config和index
在这里插入图片描述
config.js

/**
* 子应用前缀
*/
export const CHILD_PREFIX = 'child'


/**
* 子应用地址
*/
export const MICRO_APPS = [
  { name: 'first-child', url: `http://localhost:9528` },
  { name: 'second-child', url: `http://localhost:9529` }
]


/**
* 全局资源
*/
export const GLOBAL_ASSETS = {
  js: [],
  css: []
}

index.js

import microApp from '@micro-zoe/micro-app'
import * as config from './config'


/** 启用 micro */
microApp.start({
  preFetchApps: config.MICRO_APPS,
  globalAssets: config.GLOBAL_ASSETS
})

2-4、修改main.js

修改main.js。引入micro

import './micro'

在这里插入图片描述

2-5、修改AppMain.vue

AppMain.vue修改(这个我在项目里找了一下,找到系统主体部分是写在AppMain.vue中的。按照之前搭建时的思路进行了一些修改)
差不多对AppMain.vue进行了如下图所示修改:
在这里插入图片描述

完整代码:

<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        <!--element-ui视图部分,这边可以判断是不是子应用,如果子应用显示micro-app,
        否则直接显示router-view-->
        <micro-app
          v-if="isChild"
          v-bind="micro"
          destory
        />
        <router-view v-else :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>


<script>
import { MICRO_APPS, CHILD_PREFIX } from '../../micro/config'


export default {
  name: 'AppMain',
  data() {
    return {
      isChild: false,    /** 是否为子模块 */
      micro: {
        url: '',     /** 子模块地址 */
        key: '',     /** vue 标签的 key 值,用于不同子模块间的切换时,组件重新渲染 */
        name: '',    /** 子模块名称,唯一 */
        data: {},    /** 子模块数据 */
        baseroute: ''   /** 子模块数据 */
      },
      prefix: CHILD_PREFIX /** 子模块链接前缀 */
    }
  },
  computed: {
    cachedViews() {
      return this.$store.state.tagsView.cachedViews
    },
    key() {
      return this.$route.path
    }
  },
  watch: {
    $route(val) { /** 监听路由变化修改视图显示 */
      this.changeChild(val)
    }
  },
  created() {
    this.changeChild(this.$route)
  },
  methods: {
    /**
     * 获取子模块 url 和 name
     * */
    getAppUrl(name) {
      return MICRO_APPS.find(app => app.name === name) || {}
    },
    /**
     * 修改子视图显示
     * */
    changeChild(route) {
      const path = route.path.toLowerCase()
      const paths = path.split('/')


      // 判断是否为子模块,子模块有固定的前缀,在 micro/config 设置
      this.isChild = paths.length > 2 && paths[1] === CHILD_PREFIX


      if (this.isChild) {
        const app = this.getAppUrl(paths[2])


        this.micro = {
          ...app,
          data: { name: route.name },
          key: `${app.name}`,
          baseroute: `/${CHILD_PREFIX}/${paths[2]}`
        }
      }
    }
  }
}
</script>


<style lang="scss" scoped>
.app-main {
  /* 50= navbar  50  */
  min-height: calc(100vh - 50px);
  width: 100%;
  position: relative;
  overflow: hidden;
}


.fixed-header+.app-main {
  padding-top: 50px;
}


.hasTagsView {
  .app-main {
    /* 84 = navbar + tags-view = 50 + 34 */
    min-height: calc(100vh - 84px);
  }


  .fixed-header+.app-main {
    padding-top: 84px;
  }
}
</style>


<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
  .fixed-header {
    padding-right: 15px;
  }
}
</style>

2-6、基座中配置子应用1路由

在基座中配置子应用1路由(vue-element-admin中有好多页面,随便找了两个配置子应用路由
在这里插入图片描述
在这里插入图片描述
vue-element-base\src\router\modules\first-child.js

// 子应用1路由菜单
import Layout from '@/layout'
import { CHILD_PREFIX } from '@/micro/config'


const appFirstRouter = {
  path: `/${CHILD_PREFIX}/first-child`,
  component: Layout,
  redirect: `/${CHILD_PREFIX}/first-child`,
  name: 'FirstChild',
  meta: {
    title: '子应用模块',
    icon: 'nested'
  },
  children: [
    {
      path: 'menu1',
      name: 'Menu1',
      meta: { title: '子应用菜单1' }
    },
    {
      path: 'menu2',
      name: 'Menu2',
      meta: { title: '子应用菜单2' }
    }
  ]
}
export default appFirstRouter

vue-element-base\src\router\modules\index.js

// 1.导入
import appFirstRouter from './modules/first-child'

// 2.使用
appFirstRouter,

2-7、基座中配置子应用2路由

在基座中配置子应用2路由(同样vue-element-admin中有好多页面,随便找了两个配置子应用路由,只要不和子应用1重复即可)—这边的创建差不多就是把1复制过来改改
在这里插入图片描述
在这里插入图片描述
vue-element-base\src\router\modules\second-child.js

// 子应用2路由菜单
import Layout from '@/layout'
import { CHILD_PREFIX } from '@/micro/config'


const appSecondRouter = {
  path: `/${CHILD_PREFIX}/second-child`,
  component: Layout,
  redirect: `/${CHILD_PREFIX}/second-child`,
  name: 'SecondChild',
  meta: {
    title: '子应用2模块',
    icon: 'table'
  },
  children: [
    {
      path: 'dynamic-table',
      name: 'DynamicTable',
      meta: { title: '子应用2菜单1' }
    },
    {
      path: 'drag-table',
      name: 'DragTable',
      meta: { title: '子应用2菜单2' }
    }
  ]
}
export default appSecondRouter

vue-element-base\src\router\modules\index.js

// 1.导入
import appSecondRouter from './modules/second-child'

// 2.使用
appSecondRouter,

到此对基座的改造就结束了。

3、子应用1配置

子应用1为vue-element-first。接下来的配置都是在vue-element-first下进行的配置

3-1、修改vue.config.js

修改vue.config.js文件,设置允许跨域
在这里插入图片描述

headers: { // 设置本地运行的跨域权限
  'Access-Control-Allow-Origin': '*'
},

3-2、配置micro

和基座一样,配置micro。新建在src下新建文件夹micro。并在micro下新建index.js文件
在这里插入图片描述

// 设置 webpack 的公共路径
if (window.__MICRO_APP_ENVIRONMENT__) {
  // eslint-disable-next-line
  __webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'
}

3-3、修改main.js

在这里插入图片描述
main.js

// 引入 publicPath 设置
import './micro'


import Vue from 'vue'


import Cookies from 'js-cookie'


import 'normalize.css/normalize.css' // a modern alternative to CSS resets


import Element from 'element-ui'
import './styles/element-variables.scss'


import '@/styles/index.scss' // global css


import App from './App'
import store from './store'
import router from './router'


import i18n from './lang' // internationalization
import './icons' // icon
import './permission' // permission control
import './utils/error-log' // error log


import * as filters from './filters' // global filters


/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
  const { mockXHR } = require('../mock')
  mockXHR()
}


Vue.use(Element, {
  size: Cookies.get('size') || 'medium', // set element-ui default size
  i18n: (key, value) => i18n.t(key, value)
})


// register global utility filters
Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})


Vue.config.productionTip = false


// new Vue({
//   el: '#app',
//   router,
//   store,
//   i18n,
//   render: h => h(App)
// })
let app


/**
* 挂载函数
*/
function mount() {
  app = new Vue({
    el: '#app',
    router,
    store,
    i18n,
    render: function(h) { return h(App) }
  })
}


/**
* 卸载函数
*/
function unmount() {
  app.$destroy()
  app.$el.innerHTML = ''
  app = null
}


/** 微前端环境下,注册mount和unmount方法 */
if (window.__MICRO_APP_ENVIRONMENT__) { window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount } } else { mount() }

3-4、修改vue文件

在这里插入图片描述

3-5、修改路由(子应用1)

在这里插入图片描述

/** When your routing table is too long, you can split it into small modules **/


import Layout from '@/layout'


console.log(' window.__MICRO_APP_BASE_ROUTE__', window.__MICRO_APP_BASE_ROUTE__)
const nestedRouter = {
  path: window.__MICRO_APP_BASE_ROUTE__ || '/nested',
  component: Layout,
  // redirect: '/nested/menu1/menu1-1',
  name: 'Nested',
  meta: {
    title: '子应用',
    icon: 'nested'
  },
  children: [
    {
      path: 'menu1',
      component: () => import('@/views/nested/menu1/index'), // Parent router-view
      name: 'Menu1',
      meta: { title: '子应用菜单11' }
    },
    {
      path: 'menu2',
      name: 'Menu2',
      component: () => import('@/views/nested/menu2/index'),
      meta: { title: '子应用菜单22' }
    }
  ]
}


export default nestedRouter

修改完成后运行子应用1和基座,在基座中看到的子应用1效果如下图所示:

npm run dev

在这里插入图片描述

3-6、问题解决

原以为这种是路由配置有问题,但是改来改去要么404要么嵌套。不管改基座还是子应用。都没有任何效果。后面看到了一个react的文章。虽然语法等不一样,但是看到了和我上图一样的嵌套bug。
上图中子应用全部嵌套在了基座里,包含了基座已有的菜单栏及头部,所以要找到子应用的layout进行判断,如果是基座环境,则只显示主体内容。否则(即子应用)则可以全部显示。具体修改如下所示:
在这里插入图片描述
修改完成后不在有嵌套,但是在基座中点击子应用菜单,只有上方头部菜单栏变化,中间主要部分内容没有变化。要在子应用layout中对数据做一个监听。
在这里插入图片描述
micro-app-element\vue-element-first\src\layout\index.vue完整代码:

<template>
  <app-main v-if="inBase" />
  <div v-else :class="classObj" class="app-wrapper">
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
    <sidebar class="sidebar-container" />
    <div :class="{hasTagsView:needTagsView}" class="main-container">
      <div :class="{'fixed-header':fixedHeader}">
        <navbar />
        <tags-view v-if="needTagsView" />
      </div>
      <app-main />
      <right-panel v-if="showSettings">
        <settings />
      </right-panel>
    </div>
  </div>
</template>


<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'


export default {
  name: 'Layout',
  components: {
    AppMain,
    Navbar,
    RightPanel,
    Settings,
    Sidebar,
    TagsView
  },
  mixins: [ResizeMixin],
  computed: {
    ...mapState({
      sidebar: state => state.app.sidebar,
      device: state => state.app.device,
      showSettings: state => state.settings.showSettings,
      needTagsView: state => state.settings.tagsView,
      fixedHeader: state => state.settings.fixedHeader
    }),
    classObj() {
      return {
        hideSidebar: !this.sidebar.opened,
        openSidebar: this.sidebar.opened,
        withoutAnimation: this.sidebar.withoutAnimation,
        mobile: this.device === 'mobile'
      }
    },
    inBase() { // 判断是不是基座
      console.log('inbase microApp', window.microApp)
      console.log('inbase', window.__MICRO_APP_BASE_APPLICATION__)
      return !!window.microApp
    }
  },
  created() {
    /** 绑定数据【data属性】监听事件 */
    window.microApp && window.microApp.addDataListener(this.dataListener)
  },
  methods: {
    handleClickOutside() {
      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
    },
    /** 监听路径,在基座中点击子应用菜单时,菜单正常切换,但主体部分内容不变 */
    dataListener(data) {
      if (data.name !== this.$route.name) {
        this.$router.push({ name: data.name })
      }
    }
  }
}
</script>


<style lang="scss" scoped>
  @import "~@/styles/mixin.scss";
  @import "~@/styles/variables.scss";


  .app-wrapper {
    @include clearfix;
    position: relative;
    height: 100%;
    width: 100%;


    &.mobile.openSidebar {
      position: fixed;
      top: 0;
    }
  }


  .drawer-bg {
    background: #000;
    opacity: 0.3;
    width: 100%;
    top: 0;
    height: 100%;
    position: absolute;
    z-index: 999;
  }


  .fixed-header {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 9;
    width: calc(100% - #{$sideBarWidth});
    transition: width 0.28s;
  }


  .hideSidebar .fixed-header {
    width: calc(100% - 54px)
  }


  .mobile .fixed-header {
    width: 100%;
  }
</style>

修改完成后,micro-app在vue-element-admin中的效果就算实现了。效果图如下:
在这里插入图片描述

4、子应用2配置

子应用2配置(基本和子应用1配置一致,只需微改即可)
子应用2为vue-element-second。接下来的配置都是在vue-element- second下进行的配置。

4-1、修改vue.config.js

修改vue.config.js文件,设置允许跨域
在这里插入图片描述

headers: { // 设置本地运行的跨域权限
  'Access-Control-Allow-Origin': '*'
},

4-2、配置micro

和基座一样,配置micro。新建在src下新建文件夹micro。并在micro下新建index.js文件
在这里插入图片描述

// 设置 webpack 的公共路径
if (window.__MICRO_APP_ENVIRONMENT__) {
  // eslint-disable-next-line
  __webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'
}

4-3、修改main.js

在这里插入图片描述
main.js

// 引入 publicPath 设置
import './micro'
import Vue from 'vue'


import Cookies from 'js-cookie'


import 'normalize.css/normalize.css' // a modern alternative to CSS resets


import Element from 'element-ui'
import './styles/element-variables.scss'


import '@/styles/index.scss' // global css


import App from './App'
import store from './store'
import router from './router'


import i18n from './lang' // internationalization
import './icons' // icon
import './permission' // permission control
import './utils/error-log' // error log


import * as filters from './filters' // global filters


/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
  const { mockXHR } = require('../mock')
  mockXHR()
}


Vue.use(Element, {
  size: Cookies.get('size') || 'medium', // set element-ui default size
  i18n: (key, value) => i18n.t(key, value)
})


// register global utility filters
Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})


Vue.config.productionTip = false


// new Vue({
//   el: '#app',
//   router,
//   store,
//   i18n,
//   render: h => h(App)
// })
let app


/**
* 挂载函数
*/
function mount() {
  app = new Vue({
    el: '#app',
    router,
    store,
    i18n,
    render: function(h) { return h(App) }
  })
}


/**
* 卸载函数
*/
function unmount() {
  app.$destroy()
  app.$el.innerHTML = ''
  app = null
}


/** 微前端环境下,注册mount和unmount方法 */
if (window.__MICRO_APP_ENVIRONMENT__) {
  window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount }
} else {
  mount()
}

4-4、修改vue文件

在这里插入图片描述

4-5、修改路由(子应用2)

在这里插入图片描述

/** When your routing table is too long, you can split it into small modules **/


import Layout from '@/layout'


const tableRouter = {
  path: window.__MICRO_APP_BASE_ROUTE__ || '/table',
  component: Layout,
  // redirect: '/table/complex-table',
  name: 'Table',
  meta: {
    title: '子应用2',
    icon: 'table'
  },
  children: [
    {
      path: 'dynamic-table',
      component: () => import('@/views/table/dynamic-table/index'),
      name: 'DynamicTable',
      meta: { title: '子应用2菜单111' }
    },
    {
      path: 'drag-table',
      component: () => import('@/views/table/drag-table'),
      name: 'DragTable',
      meta: { title: '子应用2菜单222' }
    },
    {
      path: 'inline-edit-table',
      component: () => import('@/views/table/inline-edit-table'),
      name: 'InlineEditTable',
      meta: { title: 'inlineEditTable' }
    },
    {
      path: 'complex-table',
      component: () => import('@/views/table/complex-table'),
      name: 'ComplexTable',
      meta: { title: 'complexTable' }
    }
  ]
}
export default tableRouter

接下来浏览器效果和搭建子应用1时一样,是嵌套的,如下:
在这里插入图片描述

4-6、问题解决

需要对子应用的layout进行判断,如果是基座环境,则只显示主体内容。否则(即子应用)则可以全部显示。至于为什么修改,看子应用1即可,不多说了具体修改如下所示:
在这里插入图片描述
micro-app-element\vue-element-second\src\layout\index.vue完整代码:

<template>
  <app-main v-if="inBase" />
  <div v-else :class="classObj" class="app-wrapper">
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
    <sidebar class="sidebar-container" />
    <div :class="{hasTagsView:needTagsView}" class="main-container">
      <div :class="{'fixed-header':fixedHeader}">
        <navbar />
        <tags-view v-if="needTagsView" />
      </div>
      <app-main />
      <right-panel v-if="showSettings">
        <settings />
      </right-panel>
    </div>
  </div>
</template>


<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'


export default {
  name: 'Layout',
  components: {
    AppMain,
    Navbar,
    RightPanel,
    Settings,
    Sidebar,
    TagsView
  },
  mixins: [ResizeMixin],
  computed: {
    ...mapState({
      sidebar: state => state.app.sidebar,
      device: state => state.app.device,
      showSettings: state => state.settings.showSettings,
      needTagsView: state => state.settings.tagsView,
      fixedHeader: state => state.settings.fixedHeader
    }),
    classObj() {
      return {
        hideSidebar: !this.sidebar.opened,
        openSidebar: this.sidebar.opened,
        withoutAnimation: this.sidebar.withoutAnimation,
        mobile: this.device === 'mobile'
      }
    },
    inBase() { // 判断是不是基座
      // console.log('inbase microApp', window.microApp)
      // console.log('inbase', window.__MICRO_APP_BASE_APPLICATION__)
      return !!window.microApp
    }
  },
  created() {
    /** 绑定数据【data属性】监听事件 */
    window.microApp && window.microApp.addDataListener(this.dataListener)
  },
  methods: {
    handleClickOutside() {
      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
    },
    /** 监听路径,在基座中点击子应用菜单时,菜单正常切换,但主体部分内容不变 */
    dataListener(data) {
      if (data.name !== this.$route.name) {
        this.$router.push({ name: data.name })
      }
    }
  }
}
</script>


<style lang="scss" scoped>
  @import "~@/styles/mixin.scss";
  @import "~@/styles/variables.scss";


  .app-wrapper {
    @include clearfix;
    position: relative;
    height: 100%;
    width: 100%;


    &.mobile.openSidebar {
      position: fixed;
      top: 0;
    }
  }


  .drawer-bg {
    background: #000;
    opacity: 0.3;
    width: 100%;
    top: 0;
    height: 100%;
    position: absolute;
    z-index: 999;
  }


  .fixed-header {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 9;
    width: calc(100% - #{$sideBarWidth});
    transition: width 0.28s;
  }


  .hideSidebar .fixed-header {
    width: calc(100% - 54px)
  }


  .mobile .fixed-header {
    width: 100%;
  }
</style>

修改完成后,浏览器实现效果图如下:
在这里插入图片描述
到此对于micro-app在vue-element-admin中的使用就介绍完了。

5、打包

关于打包vue-element-admin貌似已经配置好了,直接打包即可

npm run build:prod

打包结果又是这样的,跟之前一样报错:
在这里插入图片描述
本地运行不起来,按照网上找的方法修改都没用。所以后面直接部署了,部署下来没有问题。所以打包这边注意以下两点就好了。

1、vue.config.js中的publicPath要修改。基座和子应用都要修改。如下图所示:
在这里插入图片描述

2、修改router/index.js。基座和子应用都要修改。修改路由方式。如下图所示:
在这里插入图片描述
打包结束后对应基座和子应用下都会生成对应的dist文件夹,如下图所示。单独打包单独部署就是基座和子应用都要打包。
在这里插入图片描述

6、部署

使用nginx部署,之前已经研究过了,部署这边就很快。如果不懂可参考部署相关内容。

6-1、dist放置

将打包好的dist文件分别放入对应好的文件夹中,当然不一定像我这样,只要后期目录地址写对即可
在这里插入图片描述

6-2、配置

主要是对nginx.conf的配置
在这里插入图片描述
主要配置代码:

server {
        listen       9527;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root base/dist;
            add_header Access-Control-Allow-Origin *;
            if ( $request_uri ~* ^.+.(js|css|jpg|png|gif|tif|dpg|jpeg|eot|svg|ttf|woff|json|mp4|rmvb|rm|wmv|avi|3gp)$ ){
              add_header Cache-Control max-age=7776000;
              add_header Access-Control-Allow-Origin *;
            }
            try_files $uri $uri/ /index.html;
        }   
    }


    server {
        listen       9528;
        server_name  localhost;
        location / {
            root first-child/dist;
            add_header Access-Control-Allow-Origin *;
            if ( $request_uri ~* ^.+.(js|css|jpg|png|gif|tif|dpg|jpeg|eot|svg|ttf|woff|json|mp4|rmvb|rm|wmv|avi|3gp)$ ){
              add_header Cache-Control max-age=7776000;
              add_header Access-Control-Allow-Origin *;
            }
            try_files $uri $uri/ /index.html;
        }
     }
     
     server {
        listen       9529;
        server_name  localhost;
        location / {
            root second-child/dist;
            add_header Access-Control-Allow-Origin *;
            if ( $request_uri ~* ^.+.(js|css|jpg|png|gif|tif|dpg|jpeg|eot|svg|ttf|woff|json|mp4|rmvb|rm|wmv|avi|3gp)$ ){
              add_header Cache-Control max-age=7776000;
              add_header Access-Control-Allow-Origin *;
            }
            try_files $uri $uri/ /index.html;
        }
     }

6-3、浏览器地址

部署完之后可以在浏览器中输入:

http://127.0.0.1:9527/      // 基座地址
http://127.0.0.1:9528/    // 子应用1地址
http://127.0.0.1:9529/    // 子应用2地址

6-4、部署效果

部署后浏览器显示效果:
在这里插入图片描述

总结

到此micro-app在vue-element-admin中的使用框架就算搭完了,关于micro-app在vue-element-admin中的其他使用,还需后续在研究。

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

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

相关文章

二、Spring Cloud Alibaba环境搭建

一、依赖环境 SpringCloud Alibaba 依赖 Java 环境来运行。还需要为此配置 Maven环境&#xff0c;请确保是在以下版本环境中安装使用。 64 bit JDK 1.8;Maven 3.2.x。 spring-cloud-alibaba相关网址&#xff1a; 地址&#xff1a;https://github.com/alibaba/spring-cloud-…

常用HTML标签分享系列一

前言 HTML,超文本标记语言,由标签组成,分为单标签和双标签,每个标签的属性id唯一,但name不唯一,其基本结构为Dom(Document Object Mode 文档对象模型)树,如图: <html lang"en"> <head><!-- 头部内容 --> </head> <body><!-- 身体内…

Spark 任务执行流程

Driver启动&#xff0c;创建SparkContextSparkContext 向资源管理器注册&#xff0c;并向资源管理器申请运行 Executor资源管理器分配资源&#xff0c;然后资源管理器启动 ExecutorExecutor 发送心跳至资源管理器Executor 向 SparkContext 注册自己SparkContext 构建 DAG 有向无…

图神经网络:在自定义数据集上动手实现图神经网络

文章说明&#xff1a; 1)参考资料&#xff1a;PYG官方文档。超链。 2)博主水平不高&#xff0c;如有错误还望批评指正。 文章目录 自定义数据集动手实现图神经网络自定义数据集训验测集拆分&#xff0c;创建Data的数据结构&#xff0c;观察Data的基本信息&#xff0c;可视化图网…

【Golang项目实战】用Go写一个学生信息管理系统,真的太酷啦| 保姆级详解,附源码——建议收藏

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;数据结构、Go&#xff0c;Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: Go语言核心编程近期目标&#xff1a;写好专栏的每一篇文章 学习了Go的基…

Java 基础进阶篇(十)—— Java集合详细总结

文章目录 一、集合类体系结构二、Collection系列集合2.1 Collection 集合体系2.2 Collection 集合体系特点2.3 Collection 常用API2.4 Collection 集合的遍历方式2.4.1 方式一&#xff1a;迭代器2.4.2 方式二&#xff1a;foreach&#xff08;增强for循环&#xff09;2.4.3 方式…

Python系列之Windows环境安装配置

目录 一、Python安装 1.1下载 1.2 安装 1.3增加环境变量 二、PyCharm安装 2.1 PyCharm简介 2.2 PyCharm下载安装 一、Python安装 1.1下载 python 官网The official home of the Python Programming Languagehttps://www.python.org/downloads/ 1.2 安装 要勾选选项 Ad…

校园兼职平台系统的设计与实现

技术栈&#xff1a; Spring、SpringMVC、MyBatis、HikariCP、fastjson、slf4j、EL和JSTL 系统功能&#xff1a; 前台&#xff1a; &#xff08;1&#xff09;用户注册&#xff1a;这里的用户分为职位发布者和职位应聘者&#xff0c;他们都需要注册本大学生兼职管理系统才能进…

为什么 OpenAI 团队采用 Python 开发他们的后端服务?

Python&#xff0c;年龄可能比很多读者都要大&#xff0c;但是它在更新快速的编程界却一直表现出色&#xff0c;甚至有人把它比作是编程界的《葵花宝典》&#xff0c;只是Python的速成之法相较《葵花宝典》有过之而无不及。 Python简洁&#xff0c;高效的特点&#xff0c;大大…

196页11万字智慧水务平台建设方案

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 业务需求分析 3.1 主要业务描述 &#xff08;1&#xff09;调度中心主要业务描述 配套工程调度中心为一级调度机构&#xff0c;同时也是水务集团原水供水的统一调度中心。…

python-pandas库

目录 目录 目录 1.pandas库简介&#xff08;https://www.gairuo.com/p/pandas-overview&#xff09; 2.pandas库read_csv方法&#xff08;https://zhuanlan.zhihu.com/p/340441922?utm_mediumsocial&utm_oi27819925045248&#xff09; 1.pandas库简介&#xff08;http…

第七章 使用ssh服务管理远程主机

第七章 使用ssh服务管理远程主机 一、配置网卡服务 1、配置网卡参数 &#xff08;1&#xff09;、执行nmtui命令运行网络配置工具 [rootcentos ~]# nmtui&#xff08;2&#xff09;、选择编辑连接并按回车 &#xff08;3&#xff09;、选择以太网中网卡名称并编辑 &#xf…

JavaWeb06(三层架构连接数据库)

目录 三层架构 1.什么是三层架构 三层架构 就是将整个业务划分为三层&#xff1a;表示层、业务逻辑层、数据访问层。 2. 层与层之间的关系 3.怎么理解三层架构 4.为什么需要三层架构 区分层次的目的是为了“高内聚&#xff0c;低耦合”的思想&#xff1b; 简单来说&…

从零开始学习Linux运维,成为IT领域翘楚(五)

文章目录 &#x1f525;Linux打包压缩与搜索命令&#x1f525;Linux常用系统工作命令&#x1f525;Linux管道符、重定向与环境变量&#x1f525;管道命令符 &#x1f525;Linux打包压缩与搜索命令 tar 命令 语法&#xff1a; tar [选项] [文件]选项: &#x1f41f; -c 产生.t…

牛客网---CM11 链表分割 代码详解+哨兵位的比较

文章目录 前言CM11 链表分割链接&#xff1a;方法一&#xff1a;尾插(带哨兵位)1.1 思路&#xff1a;1.2 代码&#xff1a;1.3 流程图1.4 注意点 方法二&#xff1a;尾插(不带哨兵位)2.1代码&#xff1a; 对比&#xff1a; 总结 前言 独处未必孤独喜欢就是自由 本章的内容是牛…

Chapter4:频率响应法(上)

第四章:频率响应法 Exercise4.1 已知微分网络和积分网络电路图如下图所示,求网络的频率特性。 解: 【图 ( a ) ({\rm a}) (a)微分网络】 由微分网络电路图可得:

c# 运算符重载

1.概要 1.1可重载运算符 可重载运算符说明 x, -x, !x, ~x, , --, true, falsetrue和 false 运算符必须一起重载。 x y, x - y, x * y, x / y, x % y, x & y, x | y, x ^ y, x << y, x >> y, x >>> y x y, x ! y, x < y, x > y, x < y,…

使用NNI对BERT模型进行粗剪枝、蒸馏与微调

前言 模型剪枝&#xff08;Model Pruning&#xff09;是一种用于减少神经网络模型尺寸和计算复杂度的技术。通过剪枝&#xff0c;可以去除模型中冗余的参数和连接&#xff0c;从而减小模型的存储需求和推理时间&#xff0c;同时保持模型的性能。模型剪枝的一般步骤&#xff1a…

OpenAI文本生成器-怎么解决openai只写一半

openai写文案写一半没了怎么解决 如果您正在使用 OpenAI 写文案的服务&#xff0c;在撰写文案的过程中遇到了意外中断或者其他问题导致文案未保存&#xff0c;以下是一些有用的解决方法&#xff1a; 重新调用 API 去生成文案。您可以调用 OpenAI 的 API 重新获取您所需的文案…

Three.js--》几何体顶点知识讲解

目录 几何体顶点位置数据 点线定义几何体顶点数据 网格模型定义几何体顶点数据 顶点法线数据 实现阵列立方体与相机适配 常见几何体简介 几何体的旋转、缩放、平移方法 几何体顶点位置数据 本篇文章主要讲解几何体的顶点概念&#xff0c;相对偏底层一些&#xff0c;不过…