qiankun - 微前端应用搭建

qiankun 是一个基于 single-spa微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。

主应用

  1. 创建项目(我这里使用的vue2)
// @vue/cli 5.0.4
vue create main-app
  1. 安装 qiankun
yarn add qiankun
  1. 注册微应用

新增文件夹micros,文件夹下新增 app.js

// src/micros/app.js
// 微应用信息
const apps = [
  {
    name: 'vue-app', // 微应用的名称,微应用之间必须确保唯一
    entry: '//localhost:8081/', // 微应用的入口,运行地址
    container: '#micro-container', // 微应用的容器节点
    activeRule: '/vue-app' // 微应用的激活规则
  }, {
    name: 'react-app'
    entry: '//localhost:8082/',
    container: '#micro-container',
    activeRule: '/react-app'
  }
]

export default apps

micros 下新增 index.js

// src/micros/index.js
import { addGlobalUncaughtErrorHandler, registerMicroApps, start } from 'qiankun'
// 微应用的信息
import apps from './app'

/**
 * registerMicroApps(apps, lifeCycles?)
 * apps: 必选,微应用的一些注册信息
 * lifeCycles: 可选,全局的微应用生命周期钩子
 */
registerMicroApps(apps, {
  // 加载前
  beforeLoad: (app) => console.log('before load', app.name),
  // 挂载前
  beforeMount: (app) => console.log('before mount', app.name),
  // 挂载后
  afterMount: (app) => console.log('after mount', app.name),
  // 卸载前
  beforeUnmount: (app) => console.log('before unmount', app.name),
  // 卸载后
  afterMount: (app) => console.log('after unmount', app.name)
})

// 添加全局的未捕获异常处理器
addGlobalUncaughtErrorHandler((event) => {
  console.error(event)
  const { message } = event
  if (message && message .includes('died in status LOADING_SOURCE_CODE')) {
    console.error('微应用加载失败')
  }
})

export default start

main.js 中启动

// src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import start from './micros'

start()
Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
  1. 页面及路由(这里使用的history模式)
<template>
  <div id="app">
    <nav class="menu">
      <router-link to="/">Home</router-link>
      <router-link to="/vue-app">vue-app</router-link>
      <router-link to="/react-app">react-app</router-link>
    </nav>
    <div class="main">
      <router-view></router-view>
      <!-- 微应用的容器 -->
      <div id="micro-container"></div>
    </div>
  </div>
</template>
// src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import(/* webpackChunkName: "home" */ '@/views/home.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router

微应用

vue-app微应用
  1. 创建项目
vue create vue-app
  1. src下新增 public-path.js
// src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
  1. 路由文件修改(这里使用的history模式)
// src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import(/* webpackChunkName: "home" */ '../views/home.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  // base设置,与主应用activeRule规则一致
  base: window.__POWERED_BY_QIANKUN__ ? '/vue-app' : '/',
  routes
})

export default router
  1. main.js文件修改
// src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './public-path'

Vue.config.productionTip = false
let instance = null
function render (props = {}) {
  const { container } = props
  instance = new Vue({
    router,
    store,
    render: (h) => h(App)
  }).$mount(container ? container.querySelector('#app') : '#app')
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}

// 微应用生命周期
// bootstrap 初始化
export async function bootstrap () {
  console.log('vue-app bootstraped')
}
// mount 挂载
export async function mount (props) {
  console.log('vue-app mount', props)
  render(props)
}
// unmount 卸载
export async function unmount () {
  console.log('vue-app unmount')
  instance.$destroy()
  instance.$el.innerHTML = ''
  instance = null
}
  1. vue.config.js 文件修改
// 这里的 name 应为 'vue-app' 与注册名一致
const { name } = require('./package')

module.exports = {
  devServer: {
    port: 8081,
    historyApiFallback: true,
    allowedHosts: 'all',
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },
  configureWebpack: {
    output: {
      library: name,
      // // 把微应用打包成 umd 库格式
      libraryTarget: 'umd',
      chunkLoadingGlobal: `webpackJsonp_${name}`
    }
  }
}

现在就可以访问到微应用vue-app了
在这里插入图片描述

react-app微应用
  1. 创建项目
// create-react-app 5.0.1
create-react-app react-app
  1. src下新增public-path.js
// src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
  1. App.js修改
// src/App.js
import { Routes, Route, BrowserRouter as Router} from 'react-router-dom'
import './App.css'
import Home from './components/Home'

function App() {
  return (
    <div className="App">
      {/* base设置,与主应用activeRule规则一致 */}
      <Router basename={window.__POWERED_BY_QIANKUN__ ? '/react-app' : '/'}>
        <Routes>
          <Route path="/" element={<Home />} />
        </Routes>
      </Router>
    </div>
  )
}

export default App
  1. index.js修改
// src/index.js
import React from 'react'
import { createRoot } from 'react-dom/client' // react18
import App from './App'
import reportWebVitals from './reportWebVitals'
import './public-path'

let instance = null

function render(props) {
  const { container } = props
  const root = createRoot(container ? container.querySelector('#root') : document.querySelector('#root'))
  root.render(<App />)
  instance = root
}

if (!window.__POWERED_BY_QIANKUN__) {
  render({})
}

export async function bootstrap() {
  console.log('react-app bootstraped')
}

export async function mount(props) {
  console.log('react-app mount', props)
  render(props)
}

export async function unmount(props) {
  console.log('react-app unmount')
  instance.unmount()
  instance = null
}

reportWebVitals()
  1. 修改webpack配置

安装插件 react-app-rewired,当然也可以选择其他的插件,例如 @rescripts/cli

yarn add react-app-rewired -D

根目录新增config-overrides.js

const path = require("path")
const resolve = (dir) => path.join(__dirname, dir)
// 这里的 name 应为 'react-app' 与注册名一致
const { name } = require("./package")

module.exports = {
  webpack: (config) => {
    config.output.library = name
    config.output.libraryTarget = 'umd'
    config.output.chunkLoadingGlobal = `webpackJsonp_${name}`
    config.output.globalObject = 'window'

    config.resolve.alias = {
      ...config.resolve.alias,
      '@': resolve('src')
    }
    return config
  },

  devServer: function (configFunction) {
    return function (proxy, allowedHost) {
      const config = configFunction(proxy, allowedHost)
      config.allowedHosts = 'all'
      config.headers = {
        'Access-Control-Allow-Origin': '*',
      }
      config.historyApiFallback = true

      return config
    }
  }
}

修改package.json

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

现在就可以访问到微应用react-app了
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZionHH

落魄前端,在线炒粉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值