micro-app使用(基于vue3)

1. 说明

使用微前端,需要使用一个项目作为基座,其余的项目为子应用,创建两个新项目为例

1. 创建vite + vue3 + ts 项目 base

1.1 先创建base应用作为基座

`yarn create @vitejs/app`   安装vite环境

`yarn create @vitejs/app base`  使用vite初始化vue+ts项目

micro-app vite

1.2 vite.config.ts

import { defineConfig, searchForWorkspaceRoot } from "vite";
import vue from "@vitejs/plugin-vue";
import * as path from 'path'

export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) => /^micro-app/.test(tag),
        },
      },
    }),
  ],
  server: {
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    port: 3000,
    open: true,
    fs: {
      allow: [
        searchForWorkspaceRoot(process.cwd()),
        "/mygit/micro-zoe/micro-app/",
      ],
    },
  },
  resolve: {          // 类型:Record | Array<{ find: string | RegExp, replacement: string }> 将会被传递到 @rollup/plugin-alias 作为它的 entries。
    alias: {
      '~': path.resolve(__dirname, './'),
      '@': path.resolve(__dirname, 'src')
    },
    extensions: ['.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.mjs'] // 类型: string[] 导入时想要省略的扩展名列表。
  },
  base: "/",
  build: {
    outDir: "dist",
  },
});

1.3 router

export const staticRouter: RouteRecordRaw[] = [
	{
		path: '/',
    redirect: '/base',
	},
  {
    path: '/base',
    name: 'base',
    meta: {
      title: '基座App'
    },
    component: () => import('@/components/HelloWorld.vue')
  },
  {
    path: "/app1",
    name: "app1",
    meta: {
      title: '子App'
    },
    component: () => import("@/views/app1/index.vue"),
  },
  {
    path: "/app2",
    name: "app2",
    meta: {
      title: '子App'
    },
    component: () => import("@/views/app2/index.vue"),
  },
]

1.4 main.ts

import { createApp } from 'vue'
import App from './App.vue'
import microApp from '@micro-zoe/micro-app'

// @ts-ignore
import router from '@/routers/index'

microApp.start({
  plugins: {
    modules: {
      "app1": [ // /basename/
        {
          loader(code) {
            if (process.env.NODE_ENV === "development") {
              // 这里 /basename/ 需要和子应用vite.config.js中base的配置保持一致
              code = code.replace(
                /(from|import)(\s*['"])(\/child\/app1\/)/g,
                (all) => {
                  return all.replace(
                    "/child/app1/",
                    "http://localhost:4007/child/app1/"
                  );
                }
              );
            }
            return code;
          },
        },
      ],
    },
  },
})

const app = createApp(App)
app.use(router)
app.mount('#base-root')

2. 创建vite + vue3 + ts 项目 app1

2.1 main.ts

import { createApp, App as AppInstance } from "vue";

import App from "./App.vue";

declare global {
  interface Window {
    eventCenterForAppNameVite: any;
    __MICRO_APP_NAME__: string;
    __MICRO_APP_ENVIRONMENT__: string;
    __MICRO_APP_BASE_APPLICATION__: string;
  }
}


const app = createApp(App);
app.mount("#vite-app");

console.log("微应用child-vite渲染了");

// 监听卸载操作
window.addEventListener("unmount", function () {
  app.unmount();
  // 卸载所有数据监听函数
  window.eventCenterForAppNameVite?.clearDataListener();
  console.log("微应用child-vite卸载了");
});

2.2 vite.config.ts

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { join } from "path";
import { writeFileSync } from "fs";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    (function () {
      let basePath = "";
      return {
        name: "vite:micro-app",
        apply: "build",
        configResolved(config) {
          basePath = `${config.base}${config.build.assetsDir}/`;
        },
        // writeBundle 钩子可以拿到完整处理后的文件,但已经无法修改
        writeBundle(options, bundle) {
          for (const chunkName in bundle) {
            if (Object.prototype.hasOwnProperty.call(bundle, chunkName)) {
              const chunk = bundle[chunkName];
              if (chunk.fileName && chunk.fileName.endsWith(".js")) {
                chunk.code = chunk.code.replace(
                  /(from|import\()(\s*['"])(\.\.?\/)/g,
                  (all, $1, $2, $3) => {
                    return all.replace($3, new URL($3, basePath));
                  }
                );
                const fullPath = join(options.dir, chunk.fileName);
                writeFileSync(fullPath, chunk.code);
              }
            }
          }
        },
      };
    })() as any,
  ],
  server: {
    port: 4007,
  },
  base: `${
    process.env.NODE_ENV === "production" ? "http://www.micro-zoe.com" : ""
  }/child/app1`,
  build: {
    outDir: "dist",
  },
});

你可能感兴趣的:(微前端,javascript,前端,前端框架,vue)