使用微前端,需要使用一个项目作为基座,其余的项目为子应用,创建两个新项目为例
`yarn create @vitejs/app` 安装vite环境
`yarn create @vitejs/app base` 使用vite初始化vue+ts项目
micro-app vite
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",
},
});
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"),
},
]
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')
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卸载了");
});
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",
},
});