# 六.其他功能(微前端)

前言

使用乾坤开发一套由 Vue3.x 基座、Vue3.x 子项目、React 子项目组成的微前端项目

qiankun 官网 (opens new window)

# 1.创建项目

在 micro 文件夹下创建 3 个项目

├── micro
     ├── base        # 作为微前端的基座(vue3.x技术栈)
     ├── sub1        # 作为微前端的子项目sub1(vue3.x技术栈)
     ├── sub2        # 作为微前端的子项目sub2(react17.x技术栈)
1
2
3
4

# 2.配置基座

配置入口文件

// src/main.js
import { createApp } from "vue"
import App from "./App.vue"
import router from "./router"
import store from "./store"
import ElementPlus from "element-plus"
import "element-plus/dist/index.css"
import { registerMicroApps, start } from "qiankun"
import microApps from "./micro-app"

const app = createApp(App)
app.use(ElementPlus)
app.use(store).use(router).mount("#app")

const config = {
  // 挂载前回调
  beforeLoad: [
    (app) => {
      console.log("beforeload", app)
    },
  ],
  // 挂载后回调
  beforeMount: [
    (app) => {
      console.log("beforeMount", app)
    },
  ],
  // 卸载后回调
  afterUnmount: [
    (app) => {
      console.log("afterMount", app)
    },
  ],
}

registerMicroApps(microApps(ElementPlus), config)
start({
  prefetch: false,
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

配置子项目

// src/micro-app.js
const microApps = [
  {
    name: "sub1",
    entry: "http://localhost:5501",
    activeRule: "sub1",
    container: "#sub1",
    props: {
      data: "来自基座的数据1",
      fns: [
        function LOGOUT_(data) {
          alert("父应用返回信息:" + data)
        },
      ],
    },
  },
  {
    name: "sub2",
    entry: "http://localhost:5052",
    activeRule: "sub2",
    container: "#sub2",
    props: {
      data: "来自基座的数据2",
      fns: [
        function LOGOUT_(data) {
          alert("父应用返回信息:" + data)
        },
      ],
    },
  },
]
const apps = (ui) =>
  microApps.map((item) => {
    item.props.ui = ui
    return {
      ...item,
      // props: {
      //   routerBase: item.activeRule,
      // },
    }
  })
export default apps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

配置路由

// src/router/index.js
import { createRouter, createWebHistory } from "vue-router"
import Home from "../views/Home.vue"

const routes = [
  {
    path: "/",
    redirect: "/base",
  },
  {
    path: "/base",
    name: "Home",
    component: Home,
  },
  {
    path: "/base/about",
    name: "About",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue"),
  },
]

const router = createRouter({
  base: "/base",
  history: createWebHistory(),
  routes,
})

export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 3.配置 sub1

配置入口文件

// src/main.js
import { createApp } from "vue"
import App from "./App.vue"
import router from "./router"
import store from "./store"

let app = null

function render(props = {}) {
  const { container } = props
  console.log(container)
  app = createApp(App)
  app.use(store)
  app.use(router)
  app.mount("#vue")
}
if (window.__POWERED_BY_QIANKUN__) {
  window.__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
  console.log("1111111111", window.__webpack_public_path__)
} else {
  console.log("2222222222")
  render()
}

export async function bootstrap(props) {
  console.log(props)
}
export async function mount(props) {
  render(props)
  app.use(props.ui)
  // props.fns.forEach(fn => fn('加载完成'))
}
export async function unmount() {
  app.unmount()
  console.log(app, "app")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

配置路由

// src/router/index.js
import { createRouter, createWebHistory } from "vue-router"
import Home from "../views/Home.vue"
import About from "../views/About.vue"

const routes = [
  {
    path: "/",
    redirect: "/sub1/about1",
  },
  {
    path: "/sub1",
    name: "Home",
    component: Home,
  },
  {
    path: "/sub1/about1",
    name: "About",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: About,
  },
]

const router = createRouter({
  base: "/sub1",
  history: createWebHistory(),
  routes,
})

export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

配置 webpack

// vue.config.js
module.exports = {
  devServer: {
    port: 5501,
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
  configureWebpack: {
    output: {
      library: "sub1",
      libraryTarget: "umd",
    },
  },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4.配置 sub2

配置入口文件

// src/index.js
import React from "react"
import ReactDOM from "react-dom"
import "./index.css"
import App from "./App"
import reportWebVitals from "./reportWebVitals"

reportWebVitals()

function render(props = {}) {
  const { container } = props
  console.log(container)
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById("root")
  )
}
if (window.__POWERED_BY_QIANKUN__) {
  window.__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
  console.log("1111111111", window.__webpack_public_path__)
} else {
  console.log("2222222222")
  render()
}

export async function bootstrap(props) {
  console.log(props)
}
export async function mount(props) {
  render(props)
  // props.fns.forEach(fn => fn('加载完成'))
}
export async function unmount() {
  ReactDOM.unmountComponentAtNode(document.getElementById("root"))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

配置 webpack

// config-overrides.js
module.exports = {
  webpack: (config) => {
    config.output.library = `sub2`
    config.output.libraryTarget = "umd"
    config.output.publicPath = "http://localhost:5052/"
    return config
  },
  devServer: function (configFunction) {
    return function (proxy, allowedHost) {
      const config = configFunction(proxy, allowedHost)
      config.headers = {
        "Access-Control-Allow-Origin": "*",
      }
      return config
    }
  },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 5.效果

代码案例

TIP

可以使用通用的规则