前言:
随着技术的不断升级,及新老技术的在项目中的衔接,亦或者是不同技术栈之间的组合,微前端应时而出, 以下是无界微前端配置及部署方案
主工程:
构建脚本配置
import { defineConfig } from 'vite';
const mastername = '主工程产物目录' // 如 master
export default defineConfig({
build: {
outDir: `../../dist/${mastername}`
}
});
hostMap配置:
enum SubDomain {
MAIN= 'master'
SUB_1 = 'sub-1',
SUB_2 = 'sub-2',
}
const isDev = import.meta.env.DEV; // vite 判断是否是本地开发环境
const maps: Record<MainDomain | SubDomain, string> = {
[Domain.MAIN]: isDev ? '//localhost:9000/' : `//${location.host}/`,
[SubDomain.SUB_1]: isDev ? '//localhost:9100/' : `//${location.host}/sub-child-1/`,
[SubDomain.SUB_2]: isDev ? '//localhost:9200/' : `//${location.host}/sub-child-2/`,
};
此处的 sub-child-1,sub-child-2 与 nginx 中的 location 匹配要一致 并且与 子工程中创建路由时的 base 要一致 并且 与 子工程 vite.config.ts base 值一致
router配置
import { createRouter, createWebHistory } from 'vue-router';
import child1Component from '../views/child1Component.vue';
import child2Component from '../views/child2Component.vue';
const router = createRouter({
history: createWebHistory('/'),
routes: [
{
path: `/child-1/:path+`,
name: 'child-1',
component: child1Component
},
{
path: `/child-2/:path+`,
name: 'child-2',
component: child2Component
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
meta: {
title: 'NotFound'
},
component: Error404
}]
});
注意:routes 中的 path (child-1 与 hostMap 中的 sub-child-1 不能完全相等, 否则 nginx 配置会出现资源加载异常问题)
子工程
构建脚本如下配置
// vite.config.ts
import { defineConfig } from 'vite';
const subname = '子工程产物目录' // 如 sub1
export default defineConfig({
base: '/sub-child-1/',
build: {
outDir: `../../dist/${subname}`
}
});
// vue.config.ts
const subname = '子工程产物目录' // 如 sub2
module.exports = {
publicPath: process.env.NODE_ENV === 'local' ? '/' : '/sub-child-2/',
// build时构建文件的目录
outputDir: `../../dist/${subname}`,
}
子项目 base 设置的路径和 Nginx.conf 配置的子项目监听路径不一致页面刷新会报如下错:Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
router配置
// sub-1
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';
const basename = import.meta.env.DEV ? import.meta.env.BASE_URL : '/sub-child-1/';
export function create(routes: Readonly<Array<RouteRecordRaw>>) {
return createRouter({
history: createWebHistory(basename),
routes: []
});
}
// sub-2
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';
const basename = import.meta.env.DEV ? import.meta.env.BASE_URL : '/sub-child-2/';
export function create(routes: Readonly<Array<RouteRecordRaw>>) {
return createRouter({
history: createWebHistory(basename),
routes: []
});
}
nginx 配置(2 种方案)
第一种方案
server {
listen 80;
server_name localhost;
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' *;
add_header 'Access-Control-Allow-Headers' *;
location / {
root /usr/share/nginx/html/master/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /sub-child-1 {
proxy_pass http://localhost:81/;
}
location /sub-child-2 {
proxy_pass http://localhost:82/;
}
location /api/ {
proxy_pass http://127.0.0.1:3000/;
}
}
server {
listen 81;
location / {
root /usr/share/nginx/html/sub1/;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
}
server {
listen 82;
location / {
root /usr/share/nginx/html/sub2/;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
}
第二种方案
server {
listen 80;
server_name localhost;
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' *;
add_header 'Access-Control-Allow-Headers' *;
location / {
root /usr/share/nginx/html/master/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /sub-child-1 {
alias /usr/share/nginx/html/sub1/;
try_files $uri $uri/ /sub-child-1/index.html;
index index.html index.htm;
}
location /sub-child-2 {
alias /usr/share/nginx/html/sub2/;
try_files $uri $uri/ /sub-child-2/index.html;
index index.html index.htm;
}
location /api/ {
proxy_pass http://127.0.0.1:3000/;
}
}
注意: 1、子项 base 设置的路径和 Nginx.conf 配置的子项目监听路径不一致页面刷新会报如下错:Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
2、主项目 location 的是 root,而子项目中的是 alias;
3、子项目 try_files index.html 需要配置前缀路径 /sub。