• 微前端qiankun接入Vue和React项目


    主应用:Vue3+Webpack

    1、创建主应用:

    npx vue create main-vue3-app

    2、安装qiankun

    npx yarn add qiankun

    3、项目中使用的vue、vue-router、qiankun依赖如下,webpack版本为5.x

    4、在根目录下创建vue.config.js

    1. const { defineConfig } = require('@vue/cli-service');
    2. const packageName = require('./package.json').name;
    3. module.exports = defineConfig({
    4. lintOnSave: false,
    5. devServer: {
    6. // 可以在配置中 配置端口 VUE_APP_PORT = 8080
    7. port: 8080,
    8. headers: {
    9. 'Access-Control-Allow-Origin': '*' // 允许跨域访问子应用页面
    10. }
    11. }
    12. })

    5、入口组件App.vue

    1. <template>
    2. <nav>
    3. <router-link to="/">Homerouter-link> |
    4. <router-link to="/vue2-webpack-app">wepback+vue2Approuter-link> |
    5. <router-link to="/vue3-vite-app">vite+vue3Approuter-link> |
    6. <router-link to="/vue3-webpack-app">wepback+vue3Approuter-link> |
    7. <router-link to="/react-webpack-app">wepback+reactApprouter-link> |
    8. <router-link to="/react-vite-app">vite+reactApprouter-link>
    9. nav>
    10. <router-view/>
    11. template>
    12. <style>
    13. #app {
    14. font-family: Avenir, Helvetica, Arial, sans-serif;
    15. -webkit-font-smoothing: antialiased;
    16. -moz-osx-font-smoothing: grayscale;
    17. text-align: center;
    18. color: #2c3e50;
    19. }
    20. nav {
    21. padding: 30px;
    22. }
    23. nav a {
    24. font-weight: bold;
    25. color: #2c3e50;
    26. }
    27. nav a.router-link-exact-active {
    28. color: #42b983;
    29. }
    30. style>

    6、然后创建微应用对应的路由页面以及注册微应用

    router.ts

    1. import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
    2. const routes: Array<RouteRecordRaw> = [
    3. {
    4. path: '/',
    5. name: 'index',
    6. component: () => import('../views/Index.vue')
    7. },
    8. {
    9. path: '/vue2-webpack-app/:chapters*',
    10. name: 'vue2-webpack-app',
    11. component: () => import('../views/Vue2App.vue')
    12. },
    13. {
    14. path: '/vue3-vite-app/:chapters*',
    15. name: 'vue3-vite-app',
    16. component: () => import('../views/ViteApp.vue')
    17. },
    18. {
    19. path: '/vue3-webpack-app/:chapters*',
    20. name: 'vue3-webpack-app',
    21. component: () => import('../views/Vue3App.vue')
    22. },
    23. {
    24. path: '/react-webpack-app/:chapters*',
    25. name: 'react-webpack-app',
    26. component: () => import('../views/ReactWebpack.vue')
    27. },
    28. {
    29. path: '/react-vite-app/:chapters*',
    30. name: 'react-vite-app',
    31. component: () => import('../views/ReactVite.vue')
    32. }
    33. ]
    34. const router = createRouter({
    35. history: createWebHistory(),
    36. routes
    37. })
    38. export default router

    微应用:Vue2+Webpack

    1、在主应用下创建对应的路由页面 views/Vue2App.vue

    1. <template>
    2. <div id="vue2-webpack-app"/>
    3. template>
    4. <script setup lang="ts">
    5. import { onMounted, ref } from 'vue';
    6. import { registerMicroApps, start } from 'qiankun';
    7. const loading = ref(false);
    8. registerMicroApps([
    9. {
    10. name: 'vue2-webpack-app',
    11. entry: '//localhost:8081/',
    12. container: '#vue2-webpack-app',
    13. activeRule: '/vue2-webpack-app',
    14. }
    15. ]);
    16. onMounted(() => {
    17. if (!window['qiankunStarted']) {
    18. window['qiankunStarted'] = true;
    19. start();
    20. }
    21. });
    22. script>
    23. <style scoped>style>

    2、创建vue2+webpack项目,选2.x版本

    npx vue create vue2-app

    3、项目中使用的vue、vue-router依赖如下,webpack版本为5.x

    4、在根目录下创建vue.config.js

    1. const { defineConfig } = require('@vue/cli-service');
    2. const packageName = require('./package.json').name;
    3. module.exports = defineConfig({
    4. lintOnSave: false,
    5. devServer: {
    6. // 可以在配置中 配置端口 VUE_APP_PORT = 8080
    7. port: 8081,
    8. headers: {
    9. 'Access-Control-Allow-Origin': '*' // 允许跨域访问子应用页面
    10. }
    11. },
    12. configureWebpack: {
    13. output: {
    14. library: `${packageName}-[name]`,
    15. libraryTarget: 'umd',
    16. chunkLoadingGlobal: `webpackJsonp_${packageName}`,
    17. },
    18. }
    19. })

    5、在src根目录下创建public-path.js

    1. if (window.__POWERED_BY_QIANKUN__) {
    2. __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
    3. }

    6、router/index.ts

    1. import Vue from 'vue'
    2. import VueRouter from 'vue-router'
    3. import IndexVue from '../views/Index.vue'
    4. Vue.use(VueRouter)
    5. const routes= [
    6. {
    7. path: '/',
    8. name: 'index',
    9. component: IndexVue
    10. // component: () => import( '@/views/Index.vue')
    11. },
    12. ]
    13. console.log(window.__POWERED_BY_QIANKUN__)
    14. const router = new VueRouter({
    15. mode: 'history',
    16. base: window.__POWERED_BY_QIANKUN__ ? '/vue2-webpack-app' : '/',
    17. routes
    18. })
    19. export default router

    7.入口文件main.ts/main.js

    1. import Vue from 'vue'
    2. import App from './App.vue'
    3. import router from './router';
    4. import './public-path'
    5. Vue.config.productionTip = false
    6. let instance:any = null;
    7. function render(props:any = {}) {
    8. const { container } = props
    9. instance = new Vue({
    10. name: 'root',
    11. router,
    12. render: h => h(App)
    13. }).$mount(container ? container.querySelector('#app') : '#app')
    14. }
    15. if (!window.__POWERED_BY_QIANKUN__) {
    16. render()
    17. }
    18. /**
    19. * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
    20. * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
    21. */
    22. export async function bootstrap() {
    23. console.log('vue2+webpack bootstraped');
    24. }
    25. /**
    26. * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
    27. */
    28. export async function mount(props:unknown) {
    29. // ReactDOM.render(, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
    30. console.log('乾坤子应用容器加载完成,开始渲染 child')
    31. console.log('props from main mount', props)
    32. render(props)
    33. }
    34. /**
    35. * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
    36. */
    37. export async function unmount() {
    38. instance?.$destroy();
    39. }
    40. /**
    41. * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
    42. */
    43. export async function update(props:unknown) {
    44. console.log('update props', props);
    45. }

    微应用:Vue3+Wepback

    1、在主应用下创建对应的路由页面 views/Vue3App.vue

    1. <template>
    2. <div id="vue3-webpack-app" />
    3. template>
    4. <script setup lang="ts">
    5. import { onMounted, ref } from 'vue';
    6. import { registerMicroApps, start } from 'qiankun';
    7. const loading = ref(false);
    8. registerMicroApps([
    9. {
    10. name: 'vue3-webpack-app',
    11. entry: '//localhost:8082/',
    12. container: '#vue3-webpack-app',
    13. activeRule: '/vue3-webpack-app',
    14. }
    15. ]);
    16. onMounted(() => {
    17. if (!window['qiankunStarted']) {
    18. window['qiankunStarted'] = true;
    19. start({
    20. prefetch:false,
    21. sandbox:{experimentalStyleIsolation:true}
    22. });
    23. }
    24. });
    25. script>
    26. <style scoped>style>

    2、创建vue3+webpack项目,选3.x版本

    npx vue create vue3-webpack-app

    3、项目中使用的vue、vue-router依赖如下,webpack版本为5.x

    4、在根目录下创建vue.config.js

    1. const { defineConfig } = require('@vue/cli-service');
    2. const packageName = require('./package.json').name;
    3. const path = require('path');
    4. module.exports = defineConfig({
    5. lintOnSave: false,
    6. devServer: {
    7. // 可以在配置中 配置端口 VUE_APP_PORT = 8080
    8. port: 8082,
    9. headers: {
    10. 'Access-Control-Allow-Origin': '*' // 允许跨域访问子应用页面
    11. }
    12. },
    13. configureWebpack: {
    14. output: {
    15. library: `${packageName}-[name]`,
    16. libraryTarget: 'umd',
    17. chunkLoadingGlobal: `webpackJsonp_${packageName}`,
    18. },
    19. resolve:{
    20. alias:{
    21. '@':path.join(__dirname,'src')
    22. }
    23. }
    24. }
    25. })

    5、在src根目录下创建public-path.js

    1. if (window.__POWERED_BY_QIANKUN__) {
    2. __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
    3. }

    6、router/index.ts

    1. import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
    2. import IndexView from '../views/Index.vue'
    3. const routes: Array<RouteRecordRaw> = [
    4. {
    5. path: '/',
    6. name: 'index',
    7. component: IndexView
    8. // component: () => import('../views/Index.vue')
    9. }
    10. ]
    11. const router = createRouter({
    12. history: createWebHistory(window.__POWERED_BY_QIANKUN__?'/vue3-webpack-app':process.env.BASE_URL),
    13. routes
    14. })
    15. export default router

    7.入口文件main.ts/main.js

    1. import { createApp } from 'vue'
    2. import App from './App.vue'
    3. import router from './router'
    4. import './public-path'
    5. let app: any = null
    6. function render(props: any = {}) {
    7. app = createApp(App)
    8. const { container } = props
    9. app.use(router).mount(container ? container.querySelector('#app') : '#app')
    10. }
    11. if (!window.__POWERED_BY_QIANKUN__) {
    12. render()
    13. }
    14. export async function bootstrap() {
    15. console.log('vue3+webpack bootstraped');
    16. }
    17. /**
    18. * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
    19. */
    20. export async function mount(props: unknown) {
    21. // ReactDOM.render(, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
    22. console.log('乾坤子应用容器加载完成,开始渲染 child')
    23. console.log('props from main mount', props)
    24. render(props)
    25. }
    26. /**
    27. * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
    28. */
    29. export async function unmount() {
    30. console.log('unmount-------------------')
    31. app.unmount()
    32. app = null
    33. }
    34. /**
    35. * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
    36. */
    37. export async function update(props: unknown) {
    38. console.log('update props', props);
    39. }

    微应用:Vue3+Vite

    1、在主应用下创建对应的路由页面 views/ViteApp.vue

    1. <template>
    2. <div id="vue3-vite-app" />
    3. template>
    4. <script setup lang="ts">
    5. import { onMounted, ref } from 'vue';
    6. import { registerMicroApps, start } from 'qiankun';
    7. const loading = ref(false);
    8. registerMicroApps([
    9. {
    10. name: 'vue3-vite-app',
    11. entry: '//localhost:5174/',
    12. container: '#vue3-vite-app',
    13. activeRule: '/vue3-vite-app',
    14. }
    15. ]);
    16. onMounted(() => {
    17. if (!window['qiankunStarted']) {
    18. window['qiankunStarted'] = true;
    19. start();
    20. }
    21. });
    22. script>
    23. <style scoped>style>

    2、创建vue3+vite项目

    npx pnpm create vite vue3-vite-app --template vue-ts

    3、项目中使用的vue、vue-router依赖如下,vite版本为4.x

    4、安装vite-plugin-qiankun插件

    npx pnpm add vite-plugin-qiankun

    在vite.config.ts使用

    1. import { defineConfig } from 'vite'
    2. import vue from '@vitejs/plugin-vue'
    3. import qiankun from 'vite-plugin-qiankun';
    4. // https://vitejs.dev/config/
    5. export default defineConfig({
    6. plugins: [vue() ,qiankun('vue3-vite-app', {
    7. useDevMode: true
    8. })],
    9. server:{
    10. host: '127.0.0.1',
    11. port: 5174,
    12. }
    13. })

    5、router/index.ts

    1. import { createRouter, createWebHistory } from 'vue-router'
    2. import {
    3. qiankunWindow
    4. } from 'vite-plugin-qiankun/dist/helper';
    5. const router = createRouter({
    6. history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vue3-vite-app' : '/'),
    7. routes: [
    8. {
    9. path: '/',
    10. name: 'index',
    11. component: () => import(/* webpackChunkName: "index" */ '../views/Index.vue')
    12. }
    13. ]
    14. })
    15. export default router

    6、在src根目录下创建public-path.js

    1. if (window.__POWERED_BY_QIANKUN__) {
    2. __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
    3. }

    7、main.ts

    1. import { createApp } from 'vue'
    2. import './public-path'
    3. import App from './App.vue'
    4. import router from './router'
    5. import {
    6. renderWithQiankun,
    7. qiankunWindow
    8. } from 'vite-plugin-qiankun/dist/helper';
    9. let app:any;
    10. if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
    11. createApp(App).use(router).mount('#app');
    12. } else {
    13. renderWithQiankun({
    14. mount(props) {
    15. console.log('--mount');
    16. console.log(props)
    17. app = createApp(App);
    18. app
    19. .use(router)
    20. .mount(
    21. (props.container
    22. ? props.container.querySelector('#app')
    23. : document.getElementById('app')) as Element
    24. );
    25. },
    26. bootstrap() {
    27. console.log('--bootstrap');
    28. },
    29. update() {
    30. console.log('--update');
    31. },
    32. unmount() {
    33. console.log('--unmount');
    34. app?.unmount();
    35. }
    36. });
    37. }

    微应用:React 18+Webpack

    1、在主应用下创建对应的路由页面 views/ReactWebpack.vue

    1. <template>
    2. <div id="react-webpack-app"/>
    3. template>
    4. <script setup lang="ts">
    5. import { onMounted, ref } from 'vue';
    6. import { registerMicroApps, start } from 'qiankun';
    7. const loading = ref(false);
    8. registerMicroApps([
    9. {
    10. name: 'react-webpack-app',
    11. entry: '//localhost:3000/',
    12. container: '#react-webpack-app',
    13. activeRule: '/react-webpack-app',
    14. props: {
    15. }
    16. }
    17. ]);
    18. onMounted(() => {
    19. if (!window['qiankunStarted']) {
    20. window['qiankunStarted'] = true;
    21. start();
    22. }
    23. });
    24. script>
    25. <style scoped>style>

    2、创建React+Webpack项目

    npx create-react-app react-app

    3、项目中使用的react、react-dom、react-router-dom依赖如下,webpack版本为5.x

    4、创建config-overrides.js,修改配置

     npm i react-scripts

    修改package.json

    5、封装路由组件,src/router/index.js

    1. import React from 'react'
    2. import Home from '../views/home'
    3. // 导入路由依赖
    4. import { Route,Routes} from 'react-router-dom'
    5. export default function Router(){
    6. return (
    7. // 使用BrowserRouter包裹,配置路由
    8. <Routes >
    9. <Route element={<Home/>} path='/'>Route>
    10. Routes>
    11. )
    12. }

    6、在App.jsx中引入路由组件

    1. import Router from './router/index'
    2. import './App.css';
    3. function App() {
    4. return (
    5. <div>
    6. <Router>Router>
    7. div>
    8. );
    9. }
    10. export default App;

    7、index.js入口

    1. import React from 'react';
    2. import ReactDOM from 'react-dom/client';
    3. import { BrowserRouter } from 'react-router-dom'
    4. import './index.css';
    5. import App from './App';
    6. import './public-path';
    7. import reportWebVitals from './reportWebVitals';
    8. // let root = createRoot(document.querySelector('#root'))
    9. let root = null;
    10. function render (props) {
    11. const { container } = props;
    12. root = root || ReactDOM.createRoot(container ? container.querySelector("#root") : document.getElementById("root") );
    13. root.render(
    14. <BrowserRouter basename={window.__POWERED_BY_QIANKUN__ ? "/react-webpack-app" : "/"}>
    15. <React.StrictMode>
    16. <App />
    17. React.StrictMode>
    18. BrowserRouter>
    19. );
    20. }
    21. if (!window.__POWERED_BY_QIANKUN__) {
    22. render({});
    23. }
    24. export async function bootstrap () {
    25. console.log("[react18] react app bootstraped");
    26. }
    27. export async function mount (props) {
    28. console.log("[react18] props from main framework", props);
    29. render(props);
    30. }
    31. export async function unmount (props) {
    32. root.unmount();
    33. root = null;
    34. }
    35. reportWebVitals();

    微应用:React18+Vite

    1、在主应用下创建对应的路由页面 views/ReactVite.vue

    1. <template>
    2. <div id="react-vite-app"/>
    3. template>
    4. <script setup lang="ts">
    5. import { onMounted, ref } from 'vue';
    6. import { registerMicroApps, start } from 'qiankun';
    7. const loading = ref(false);
    8. registerMicroApps([
    9. {
    10. name: 'react-vite-app',
    11. entry: '//localhost:5175/',
    12. container: '#react-vite-app',
    13. activeRule: '/react-vite-app',
    14. }
    15. ]);
    16. onMounted(() => {
    17. if (!window['qiankunStarted']) {
    18. window['qiankunStarted'] = true;
    19. start();
    20. }
    21. });
    22. script>
    23. <style scoped>style>

    2、创建React18+vite项目

    npx pnpm create vite react-vite-app --template react-ts

    3、项目中使用的react、react-dom 、react-router-dom依赖如下,vite版本为4.x

    4、安装vite-plugin-qiankun插件

    npx pnpm add vite-plugin-qiankun

    在vite.config.ts使用

    1. import { defineConfig } from 'vite'
    2. import react from '@vitejs/plugin-react'
    3. import qiankun from 'vite-plugin-qiankun'
    4. export default defineConfig({
    5. plugins: [
    6. // 在开发模式下需要把react()关掉
    7. // https://github.com/umijs/qiankun/issues/1257
    8. // react(),
    9. qiankun('react-vite-app', { // 微应用名字,与主应用注册的微应用名字保持一致
    10. useDevMode: true
    11. })
    12. ],
    13. server: {
    14. host: '127.0.0.1',
    15. port: 5175,
    16. }
    17. })

    5、封装路由组件,src/router/index.tsx

    1. import React from 'react'
    2. import Home from '../views/home'
    3. // 导入路由依赖
    4. import { Route,Routes} from 'react-router-dom'
    5. export default function Router(){
    6. return (
    7. // 使用BrowserRouter包裹,配置路由
    8. <Routes >
    9. <Route element={<Home/>} path='/'>Route>
    10. Routes>
    11. )
    12. }

     6、在App.tsx中引入路由组件

    1. import Router from './router/index'
    2. import React from 'react';
    3. import './App.css';
    4. function App() {
    5. return (
    6. <div>
    7. <Router>Router>
    8. div>
    9. );
    10. }
    11. export default App;

    7、main.tsx入口

    1. import React from 'react'
    2. import ReactDOM from 'react-dom/client'
    3. import App from './App'
    4. import { BrowserRouter } from 'react-router-dom'
    5. import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
    6. let root:any;
    7. const render = (container:HTMLElement | undefined) => {
    8. // 如果是在主应用的环境下就挂载主应用的节点,否则挂载到本地
    9. root = root || ReactDOM.createRoot(container ? container.querySelector("#root") : document.getElementById("root") );
    10. console.log(qiankunWindow.__POWERED_BY_QIANKUN__)
    11. root.render(
    12. <BrowserRouter basename={qiankunWindow.__POWERED_BY_QIANKUN__ ? "/react-vite-app" : "/"}>
    13. <React.StrictMode>
    14. <App />
    15. React.StrictMode>
    16. BrowserRouter>
    17. );
    18. }
    19. const initQianKun = () => {
    20. renderWithQiankun({
    21. // 当前应用在主应用中的生命周期
    22. // 文档 https://qiankun.umijs.org/zh/guide/getting-started#
    23. mount(props) {
    24. render(props.container)
    25. // 可以通过props读取主应用的参数:msg
    26. // 监听主应用传值
    27. props.onGlobalStateChange((res) => {
    28. console.log(res.count)
    29. })
    30. },
    31. bootstrap() { },
    32. unmount() {
    33. root.unmount();
    34. root = null
    35. },
    36. })
    37. }
    38. // 判断当前应用是否在主应用中
    39. qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render(undefined)

    演示:

    20231027-120328

    issue

    发现使用webpack构建的微应用,不支持路由懒加载的写法,vite就可以

    Vue路由懒加载报错,ChunkLoadError: Loading chunk 0 failed,需要二次进入子应用或者在子应用中刷新才正常。 · Issue #1929 · umijs/qiankun (github.com)

    完整代码:

    UzumakiHan/qiankun-demo (github.com)

  • 相关阅读:
    向毕业妥协系列之机器学习笔记:神经网络(四)Tensorflow实现(中)多分类问题
    深入理解synchronized关键字
    Kubernetes快速部署
    记一次 某智能制造MES系统CPU 爆高分析
    Go 并发编程模型
    ​Vue + Element UI前端篇(二):Vue + Element 案例 ​
    递归时间复杂度分析 && master公式
    Flask高级视图_蓝图模板,静态文件,url_for的实战
    一日一技:用Python做游戏有多简单
    No mapping for GET /swagger-ui.html的解决方法
  • 原文地址:https://blog.csdn.net/Hhjian524/article/details/134060867