JAiRouter单仓一体架构深解:前后端分离开发与Maven一体化构建的最佳实践


1. 背景与目标

云原生时代,交付物逐渐向容器镜像收敛,研发流程要求"一键出包、快速迭代、可重复构建"。JaiRouter 项目采用 前后端分离架构(Vue3 + Vite 作为 Console,Spring Boot 作为 API 网关),但源码仓库保持 mono-repo 形态以降低认知负荷与 CI/CD 复杂度。

本文旨在阐述如何利用 frontend-maven-plugin 将两套异构工具链(Node/NPM 与 Maven)串联成 single-command build,并兼顾:

  • 开发期 热更新代理
  • 构建期 缓存最大化
  • 发布期 多架构 OCI 镜像

2. 整体架构与目录布局

在这里插入图片描述

关键路径说明

  • frontend:Vue3 + TypeScript + Element Plus + Vite
  • backend:Spring Boot 3 + Java 17(主 pom 所在)
  • static/admin:Servlet 容器静态资源映射前缀,对应 Vite base: '/admin/'

3. 核心构建流程拆解

Phase Plugin / Goal Output Cache Key
generate-resources install-node-and-npm target/node/ node-version + os.detected.classifier
generate-resources npm (install) frontend/node_modules/ package-lock.json hash
generate-resources npm (run build) frontend/dist/ src/**/* hash
process-resources copy-resources static/admin/ -
package spring-boot:build-image OCI image tarball layer digest

通过 mode=max 与 GitHub Actions actions/cache@v3 实现 跨工作流 中间层复用,平均节省 65% 构建耗时。


4. 深度技巧揭秘

4.1 开发期零跨域

// vite.config.ts
server: {
  proxy: {
    '/api': { target: 'http://localhost:8080', changeOrigin: true },
    '/ws': { target: 'ws://localhost:8080', ws: true }
  }
}

浏览器仍访问 http://localhost:3000/admin,但 XHR/WebSocket 被 Vite dev-server 反向代理至后端,无 CORS 且保持 Cookie 同源。

4.2 构建期版本对齐

<execution>
  <id>npm-run-build</id>
  <phase>generate-resources</phase>
</execution>

Maven 生命周期保证:任何早于 process-resources 的测试或代码生成任务均能拿到最新静态文件,确保可重复构建(reproducible build)

4.3 跳过开关(backward compatibility)

mvn clean package -Dskip.frontend.build=true

对于仅修改 Java 代码的场景,可完全跳过前端阶段,平均再节省 30-40 s

4.4 多架构 OCI 镜像

- uses: docker/build-push-action@v5
  with:
    platforms: linux/amd64,linux/arm64
    cache-from: type=gha
    cache-to: type=gha,mode=max

层缓存与 QEMU 仿真结合,同一次 push 即可产出双架构镜像,无需自建 ARM 节点。


5. 常见问题 FAQ

现象 根本原因 解决方案
执行 mvn 报错 “npm: not found” 插件尚未完成 Node 自举 保证宿主机可访问外网,重跑一次即可触发下载
访问 /admin 出现 404 frontend/dist 未被拷入 jar 检查 maven-resources-plugin<directory> 是否指向 frontend/dist
arm64 构建耗时 >10 min 纯 QEMU 软件模拟效率低 引入云端 ARM 实例或自托管 ARM Runner
前端热更新失灵(WSL) bind-mount 性能差 升级至 WSL2,或在 Linux 原生环境开发
SNAPSHOT 包体积异常增大 历史 dist 未清理 执行 mvn clean 或在 vite.config.ts 开启 emptyOutDir: true
想单独升级 Node 版本 仅需修改 nodeVersion 标签 删除 target/node 目录触发重新下载

6. Benchmark & 效果

Metric Before* After
首次克隆构建耗时 5 min 20 s 2 min 45 s
仅后端改动耗时 1 min 10 s 35 s
镜像体积 184 MB 142 MB(dist 压缩+layer dedup)
跨架构构建 手动分两次 单任务 6 min(含缓存)

*Before:独立前端仓库 + 手动 scp dist + 单架构 buildx


7. 一键模板

            <!-- 多模块前端构建插件配置 -->
            <!-- Frontend Maven Plugin -->
            <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>1.15.0</version>
                <configuration>
                    <workingDirectory>frontend/</workingDirectory>
                    <installDirectory>target</installDirectory>
                    <!-- 添加跳过配置 -->
                    <skip>${skip.frontend.build}</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                        <configuration>
                            <nodeVersion>v18.17.0</nodeVersion>
                            <npmVersion>9.6.7</npmVersion>
                        </configuration>
                    </execution>
                    <execution>
                        <id>npm install</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>
                    <execution>
                        <id>npm run build</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <arguments>run build</arguments>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Copy frontend build to static resources -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-frontend-build</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}/static/admin</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>frontend/dist</directory>
                                    <filtering>false</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

  • mvn clean package 直出可运行 jar
  • 自带 /admin 管理后台
  • CI 层缓存加速 & 多架构镜像

8. 结语

通过 frontend-maven-plugin 将 Node 生态嵌入 Maven 生命周期,我们兼顾了前后端分离的开发敏捷性mono-repo 的构建一致性,实现了真正的 “code together, ship together”
该范式已应用于 JaiRouter 主干分支。

关注 JAiRouter 获取最新源码与最佳实践。
项目全文档托管点击即可查看JAirouter

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐