前言
这是 umi3.x+qiankun+模块联邦 搭建微前端应用系列的最后一章,先来回顾一下:上一章节我们主要是集成了webpack5 中的 module-federation 实现了各应用间公共组件和公共方法的实时共享,并解决了模块联邦与umi3.x框架的兼容问题。那么这一章节主要讲讲如何把一个微前端项目部署上线。
主要用到了gitlab CI/CD 、docker等技术,在此之前需要各位看官了解相关的基础知识,这里有我之前写的一篇关于搭建gitlab私库的文章,传送门在这里
系列文章传送门:
【实战】umi3.x+qiankun+模块联邦 搭建微前端应用(一)— 项目初始化
【实战】umi3.x+qiankun+模块联邦 搭建微前端应用(二)— 集成qiankun
部署阶段
在项目根目录下新建 .gitlab-ci.yml 文件
image: node:latest
stages:
- deploy
job_deploy:
image: docker
stage: deploy
tags:
- vitepro3
script:
- docker build -t citestimages1 .
- if [ $(docker ps -aq --filter name=citest-container1) ]; then docker rm -f citest-container1;fi
- docker run -d -p 80:80 --name citest-container1 citestimages1
复制代码
在项目根目录下新建 Dockerfile 文件
# 注意这里的node镜像版本 最新的17.x在安装依赖的时候会有问题
FROM node:14.15.0-alpine as builder
WORKDIR /app
COPY package.json pnpm-lock.yaml /app/
RUN npm config set registry --registry=http://registry.npm.taobao.org
RUN npm install -g pnpm@7.8.0
RUN pnpm install
COPY . .
RUN pnpm run deploy
FROM nginx:latest
COPY --from=builder /app/dist /usr/share/nginx/html
复制代码
修改主、子应用配置
主要涉及两个地方:打包输出的路径、静态资源请求路径
打包输出的路径
我们期望打包后主、子应用的包结构是这样的:
dist
├── index.html
├── sub_projects
│ ├── app1
│ └── app2
├── umi.css
└── umi.js
复制代码
配置子应用打包输出的路径
app1 项目
// vite.config.ts文件
build: {
outDir: '../../dist/sub_projects/app1',
},
复制代码
app2 项目
// config/config.ts
outputPath: '../../dist/sub_projects/app2',
复制代码
配置 publicPath
app1 项目
// vite.config.ts文件
base: process.env.NODE_ENV === 'development' ? './' : `//yourhost/sub_projects/app1/`,
复制代码
app2 项目
// config/config.ts
base: process.env.NODE_ENV === 'development' ? './' : `//yourhost/sub_projects/app2/`,
复制代码
部署脚本
在主应用根目录新建:
scripts
├── build.js
├── utils.js
复制代码
// scripts/build.js
const { resolve } = require('path');
const { run, subProjectDirs, subProjectDir, projRoot } = require('./utils');
const buildSubProjects = async (index = 0) => {
const projects = subProjectDirs();
const projectsPath = resolve(projRoot, subProjectDir, projects[index]);
await run('pnpm install', projectsPath);
await run('pnpm run build', projectsPath);
if (projects.length - 1 > index) {
buildSubProjects((index += 1));
}
};
const main = async () => {
await run('pnpm run build');
buildSubProjects();
};
main();
复制代码
// utils.js
const { spawn } = require("child_process");
const { resolve } = require("path");
const fs = require("fs");
// 项目根目录
const projRoot = resolve(__dirname, "..");
// 子应用目录
const subProjectDir = resolve(__dirname, "../sub-projects");
const subProjectDirs = () => fs.readdirSync(subProjectDir);
const run = async (command, cwd = projRoot) =>
new Promise((resolve, reject) => {
const [cmd, ...args] = command.split(" ");
const app = spawn(cmd, args, {
cwd,
stdio: "inherit",
shell: process.platform === "win32",
});
const onProcessExit = () => app.kill("SIGHUP");
app.on("close", (code) => {
process.removeListener("exit", onProcessExit);
if (code === 0) resolve();
else
reject(
new Error(`Command failed. \n Command: ${command} \n Code: ${code}`)
);
});
process.on("exit", onProcessExit);
});
module.exports = {
projRoot,
run,
subProjectDir,
subProjectDirs,
};
复制代码
ok! 最后将我们的代码提交至远程,自动触发 ci/cd,构建成功如图:
最后访问下吧:
总结
这一章讲了整个应用的部署,主要涉及到打包的目录结构划分、publicPath路径的配置、以及打包脚本的编写,这些可以根据各位看官的实际情况而定,欢迎讨论。当然过程中还有很多不足,比如每次上线都是一次全量打包部署的过程,其实这个地方可以集成 jenkins,在每次上线时勾选需要打包部署的应用,真正做到微前端提出的子应用可独立发布。最后,这个系列也算告一段落了,过程中的不足,欢迎各位指出,菜鸟作者一定虚心接受。