vue3.x

Vue与Qiankun微前端组合

2022-02-17  本文已影响0人  WebGiser

参考:https://blog.csdn.net/qq_42268364/article/details/116127872
https://gitee.com/zhihua0123/qiankun-demo/tree/master
https://blog.csdn.net/weixin_48726650/article/details/106905193

主应用 main-app

创建新项目 main-app
// 创建项目
vue  create  main-app
// 安装qiankun
npm  i  qiankun  -S
image.png
改造项目

1、修改 App.vue
我们要在app.vue中创建一个容器,负责把获取到的子应用加载到这里容器里面

    <div id="app">
        <div id="nav">
            <router-link to="/">Home</router-link> |
            <router-link to="/about">About</router-link> | 
            <router-link to="/hello-app">hello-app</router-link>
        </div>
        <router-view />
        <!-- id为appContainer就是放置子应用的容器 -->
        <div id="appContainer"></div>
    </div>

2、新建 arc/qiankun.js文件,引用qiankun并且封装好

import { registerMicroApps, start } from "qiankun";

export const useQiankun = () => {
    const apps = [
        {
            // 必填,微应用的名称,必须保证唯一
            name: "hello-app",
            // 必填,微应用的入口
            entry: "http://localhost:8082",
            // 必填,微应用的容器节点的选择器或者Element实例
            container: "#appContainer",
            // 必填,微应用的激活规则
            activeRule: "/hello-app",
            // 可填,主应用需要传递给微应用的数据
            props: {
                msg: "我是main-app传过来的值,传递给hello-app应用。",
            },
        },
    ];

    registerMicroApps(apps, {
        beforeLoad: [
            (app) => {
                console.log(`${app.name}的beforeLoad阶段`);
            },
        ],
        beforeMount: [
            (app) => {
                console.log(`${app.name}的beforeMount阶段`);
            },
        ],
        afterMount: [
            (app) => {
                console.log(`${app.name}的afterMount阶段`);
            },
        ],
        beforeUnmount: [
            (app) => {
                console.log(`${app.name}的beforeUnmount阶段`);
            },
        ],
        afterUnmount: [
            (app) => {
                console.log(`${app.name}的afterUnmount阶段`);
            },
        ]
    })

    start({
        experimentalStyleIsolation: true,
        prefetch: "all",
    })
}

3、修改 main.js

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

import {useQiankun} from './qiankun'

Vue.config.productionTip = false

const vueApp = new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

vueApp.$nextTick(()=>{
  useQiankun()
})

4、修改 src/views/Home.vue

<div class="home">
    <h1>main-app的Home页面</h1>
  </div>

5、修改 src/views/About.vue

<div class="home">
    <h1>main-app的About页面</h1>
  </div>

6、新建 vue.config.js

"use strict";
const path = require("path");
function resolve(dir) {
    return path.join(__dirname, dir);
}

const port = 8011; // 端口配置
const name = "main-app";

module.exports = {
    // hash 模式下可使用
    publicPath: process.env.NODE_ENV === "development" ? "/" : "/main-app/",
    outputDir: "dist",
    assetsDir: "static",
    lintOnSave: process.env.NODE_ENV === "development",
    productionSourceMap: false,
    devServer: {
        port: port,
        open: false, // 启动项目以后自动打开浏览器
        hot: true, // 模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度
        hotOnly: false, // hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
    },

    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,
        resolve: {
            alias: {
                "@": resolve("src"),
            },
        },
    },
};

子应用 hello-app

创建新项目 hello-app
// 创建项目
vue  create  hello-app
image.png
改造项目

1、新增 src/public-path.js

if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

2、修改main.js
在main.js,引入public-path.js 并配合主项目导出single-spa需要的三个生命周期。
注意:路由实例化需要在main.js里面完成,以便于路由的销毁,所以路由文件只需要导出路由配置即可(原模板导出的是路由实例)

import Vue from "vue";
import App from "./App.vue";
import routes from "./router";
import store from "./store";

import "./public-path";
import VueRouter from "vue-router";
let router = null;
let instance = null;

function render({ container, parentStore } = {}) {
    router = new VueRouter({
        base: window.__POWERED_BY_QIANKUN__
            ? "/hello-app"
            : process.env.BASE_URL,
        mode: "history",
        routes,
    });

    instance = new Vue({
        router,
        store,
        data() {
            return {
                parentStore,
            };
        },
        render: (h) => h(App),
    }).$mount(container ? container.querySelector("#hello-app") : "#hello-app");
}

if (!window.__POWERED_BY_QIANKUN__) {
    // 全局变量来判断环境
    render();
}

export async function bootstrap() {
    console.log("现在进入子应用hello-app的bootstraped阶段");
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
    if (props.parentStore) {
        await props.parentStore.dispatch("getResource", {
            name: "hello-app应用的资源",
        });
    }
    console.log("现在进入子应用hello-app的mount周期", props);
    render(props);
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
    console.log("现在进入子应用hello-app的unmount阶段");
    instance.$destroy();
    instance.$el.innerHTML = "";
    instance = null;
    router = null;
}

/**
 * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {
    console.log("update props", props);
}

3、vue.config.js

"use strict";
const path = require("path");
function resolve(dir) {
    return path.join(__dirname, dir);
}

const sysName = "hello-app";
const port = 8082; // 端口配置
const { name } = require("./package");

module.exports = {
    publicPath: process.env.NODE_ENV === "development" ? "/" : "/hello-app/",
    outputDir: "dist",
    assetsDir: "static",
    lintOnSave: process.env.NODE_ENV === "development",
    productionSourceMap: false,
    devServer: {
        port: port,
        open: false, // 启动项目以后自动打开浏览器
        hot: true,
        hotOnly: false,
        headers: {
            "Access-Control-Allow-Origin": "*",
        },
    },

    configureWebpack: {
        name: name,
        resolve: {
            alias: {
                "@": resolve("src"),
            },
        },
        output: {
            // 把子应用打包成 umd 库格式
            library: `${sysName}`, // 微应用的包名,这里与主应用中注册的微应用名称一致
            libraryTarget: "umd", // 将你的 library 暴露为所有的模块定义下都可运行的方式
            jsonpFunction: `webpackJsonp_${sysName}`, // 按需加载相关,设置为 webpackJsonp_vue-projec 即可
        },
    }
};

4、修改 src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/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 = new VueRouter({
//   mode: 'history',
//   base: process.env.BASE_URL,
//   routes
// })
// export default router

export default routes

5、修改 src/views/Home.vue

<div class="home">
    <h1>hello-app的Home页面</h1>
  </div>

6、修改 src/views/About.vue

<div class="home">
    <h1>hello-app的About页面</h1>
  </div>

7、修改 public/index.html

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

测试

分别启动 main-app 和 hello-app 项目,然后访问main-app的


image.png
上一篇 下一篇

猜你喜欢

热点阅读