构建优化 Build Optimization
介绍
构建优化是提升项目开发效率和生产环境性能的关键环节。RuoYi-Plus-UniApp全栈项目采用现代化的构建工具链,包括Maven(后端)、Vite(前端/移动端),通过科学的配置和优化策略,实现快速编译、按需加载、资源压缩等目标,显著缩短构建时间和提升应用性能。
核心特性:
- 多模块并行构建 - Maven多模块项目支持并行编译,充分利用多核CPU资源
- Vite极速HMR - 基于ESM的秒级热更新,开发时修改立即生效
- 智能依赖预构建 - 自动分析和预构建第三方依赖,减少首次加载时间
- 资源压缩与分割 - Gzip/Brotli压缩、代码分割、Tree Shaking自动优化产物
- 多平台编译优化 - UniApp支持H5、小程序、App多平台条件编译和按需打包
- 增量编译 - Maven和Vite都支持增量编译,只重新构建变更的模块
- 缓存机制 - 本地缓存、依赖缓存、构建产物缓存加速重复构建
- 生产环境优化 - Source Map可选、Console移除、文件Hash、CDN部署优化
本文档涵盖后端(Maven)、前端管理端(Vite)、移动端(UniApp+Vite)三个维度的构建优化策略,以及CI/CD流水线中的构建加速技巧,帮助开发者打造高效的构建流程。
后端构建优化(Maven)
Maven项目结构
RuoYi-Plus后端采用Maven多模块架构,合理的模块划分是构建优化的基础:
ruoyi-plus-uniapp-workflow/
├── pom.xml # 父POM(依赖管理)
├── ruoyi-admin/ # 启动模块
├── ruoyi-common/ # 31个通用模块
│ ├── ruoyi-common-core/
│ ├── ruoyi-common-web/
│ ├── ruoyi-common-redis/
│ └── ...
├── ruoyi-modules/ # 5个业务模块
│ ├── ruoyi-system/
│ ├── ruoyi-generator/
│ └── ...
└── ruoyi-extend/ # 2个扩展模块模块依赖层次:
- 业务模块(ruoyi-modules) → 通用模块(ruoyi-common) → Spring Boot BOM
- 清晰的依赖层次避免循环依赖,提升编译效率
父POM依赖管理
BOM统一版本管理
使用<dependencyManagement>统一管理依赖版本,避免版本冲突:
<properties>
<revision>5.5.0</revision>
<spring-boot.version>3.5.6</spring-boot.version>
<mybatis-plus.version>3.5.14</mybatis-plus.version>
<satoken.version>1.44.0</satoken.version>
<redisson.version>3.51.0</redisson.version>
<hutool.version>5.8.40</hutool.version>
<!-- ...更多版本定义 -->
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 自定义BOM -->
<dependency>
<groupId>plus.ruoyi</groupId>
<artifactId>ruoyi-common-bom</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>优化效果:
- 子模块无需指定版本号,自动继承父POM版本
- 减少依赖冲突,Maven无需进行仲裁计算
- 统一升级依赖版本,只需修改父POM
Revision版本占位符
使用${revision}占位符实现CI/CD友好的版本管理:
<groupId>plus.ruoyi</groupId>
<artifactId>ruoyi-plus-uniapp</artifactId>
<version>${revision}</version>
<properties>
<revision>5.5.0</revision>
</properties>配合flatten-maven-plugin插件展平POM文件:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.3.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
</plugin>CI/CD构建时动态指定版本:
mvn clean package -Drevision=5.5.1-SNAPSHOT并行编译配置
Maven 3+支持并行编译多个模块,充分利用多核CPU:
# 使用所有可用CPU核心
mvn clean install -T 1C
# 指定线程数(推荐CPU核心数-1)
mvn clean install -T 4
# 开发环境跳过测试加速编译
mvn clean install -T 1C -DskipTests
# 仅编译变更模块及其依赖模块
mvn clean install -T 1C -pl ruoyi-modules/ruoyi-system -am参数说明:
-T 1C: 每个CPU核心分配1个线程-T 4: 使用4个线程并行编译-DskipTests: 跳过单元测试-pl: 指定编译的模块-am: 同时编译依赖的上游模块
性能对比:
| 编译方式 | 耗时 | 说明 |
|---|---|---|
| 单线程全量编译 | ~180秒 | mvn clean install |
| 8线程并行编译 | ~60秒 | mvn clean install -T 1C (8核CPU) |
| 跳过测试并行 | ~40秒 | mvn clean install -T 1C -DskipTests |
| 增量编译单模块 | ~8秒 | mvn install -pl ruoyi-system -am |
编译器优化
注解处理器配置
合理配置注解处理器顺序,避免重复处理:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<source>21</source>
<target>21</target>
<encoding>UTF-8</encoding>
<annotationProcessorPaths>
<!-- 1. Javadoc注解处理器 -->
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>0.15.0</version>
</path>
<!-- 2. Lombok注解处理器 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.40</version>
</path>
<!-- 3. Spring Boot配置处理器 -->
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>3.5.6</version>
</path>
<!-- 4. MapStruct处理器 -->
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>1.5.0</version>
</path>
<!-- 5. Lombok与MapStruct桥接 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<!-- 保留方法参数名 -->
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>注解处理器执行顺序:
- Javadoc注解 → 生成API文档元数据
- Lombok → 生成Getter/Setter/Builder等代码
- Spring Boot → 生成配置元数据(META-INF/spring-configuration-metadata.json)
- MapStruct → 生成对象映射代码
- Lombok-MapStruct桥接 → 确保MapStruct能识别Lombok生成的代码
编译参数优化
<compilerArgs>
<!-- 保留参数名,支持@Param注解省略 -->
<arg>-parameters</arg>
<!-- 忽略警告加速编译(生产环境不推荐) -->
<!-- <arg>-Xlint:none</arg> -->
</compilerArgs>测试优化策略
跳过测试
开发环境快速编译时跳过测试:
# Maven命令行方式
mvn clean package -DskipTests
# 或者跳过测试编译和执行
mvn clean package -Dmaven.test.skip=truePOM配置默认跳过:
<properties>
<skipTests>true</skipTests>
</properties>按环境执行测试
使用JUnit 5的@Tag注解分环境执行测试:
@Test
@Tag("dev") // 仅在dev环境执行
void testDevFeature() {
// 开发环境测试
}
@Test
@Tag("prod") // 仅在prod环境执行
void testProdFeature() {
// 生产环境测试
}Maven Surefire插件配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<!-- 执行指定标签的测试 -->
<groups>${profiles.active}</groups>
<!-- 排除指定标签的测试 -->
<excludedGroups>exclude</excludedGroups>
<!-- JVM参数优化 -->
<argLine>
-Dfile.encoding=UTF-8
-XX:+EnableDynamicAgentLoading
</argLine>
</configuration>
</plugin>执行特定环境测试:
# 只执行dev环境测试
mvn test -Dgroups=dev
# 执行prod环境测试,排除exclude标签
mvn test -Dgroups=prod -DexcludedGroups=exclude依赖优化
排除传递依赖
避免不必要的传递依赖,减小JAR包体积:
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<exclusions>
<!-- Hutool已在父POM统一管理,排除传递依赖 -->
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>本地仓库优化
配置华为云Maven镜像加速依赖下载:
<repositories>
<repository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>常用国内镜像:
- 华为云:
https://mirrors.huaweicloud.com/repository/maven/ - 阿里云:
https://maven.aliyun.com/repository/public - 腾讯云:
https://mirrors.cloud.tencent.com/nexus/repository/maven-public/
打包优化
Spring Boot Fat JAR优化
使用spring-boot-maven-plugin打包可执行JAR:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 排除开发工具依赖 -->
<excludeDevtools>true</excludeDevtools>
<!-- 分层打包支持Docker镜像缓存 -->
<layers>
<enabled>true</enabled>
</layers>
</configuration>
</plugin>分层打包优势:
- 依赖层独立,依赖不变时Docker构建可复用缓存
- JAR包分为
dependencies、spring-boot-loader、snapshot-dependencies、application四层
Docker多阶段构建示例:
FROM openjdk:21-jdk-slim as builder
WORKDIR /app
COPY target/*.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract
FROM openjdk:21-jre-slim
WORKDIR /app
# 分层复制,利用Docker缓存
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]资源过滤优化
只对配置文件启用资源过滤,避免二进制文件损坏:
<resources>
<!-- 所有资源默认不过滤 -->
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
<!-- 仅对配置文件启用过滤 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>过滤变量示例:
# application.yml
spring:
application:
name: @project.artifactId@
profiles:
active: @profiles.active@多环境构建
Profile配置
定义dev和prod两套环境配置:
<profiles>
<!-- 开发环境 -->
<profile>
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!-- 生产环境 -->
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
</properties>
</profile>
</profiles>指定环境编译:
# 开发环境(默认)
mvn clean package
# 生产环境
mvn clean package -P prod
# 同时指定多个Profile
mvn clean package -P prod,docker环境配置文件
src/main/resources/
├── application.yml # 通用配置
├── application-dev.yml # 开发环境配置
└── application-prod.yml # 生产环境配置构建缓存优化
本地仓库缓存
Maven本地仓库默认位于~/.m2/repository,首次构建会下载所有依赖,后续构建直接使用缓存。
清理本地仓库释放空间:
# 清理所有本地仓库
mvn dependency:purge-local-repository
# 清理特定GroupId的依赖
mvn dependency:purge-local-repository -DmanualInclude="plus.ruoyi:*"增量编译
Maven默认支持增量编译,只重新编译变更的Java文件:
# 不清理target目录,只编译变更文件
mvn compile
# 清理后全量编译
mvn clean compile增量编译生效条件:
- 源代码文件修改时间 > 编译产物修改时间
- 依赖的类没有变化
- 编译参数没有变化
前端构建优化(Vite)
Vite构建优势
RuoYi-Plus前端管理端使用Vite作为构建工具,相比Webpack具有显著优势:
开发环境优势:
- 基于ES Modules,无需打包,秒级启动
- HMR(Hot Module Replacement)响应速度快,修改立即生效
- 按需编译,只编译当前访问的模块
生产环境优势:
- 基于Rollup打包,产物体积小
- 原生支持Tree Shaking和代码分割
- 预构建依赖,优化CommonJS模块
开发环境优化
开发服务器配置
// vite.config.ts
export default defineConfig({
server: {
host: '0.0.0.0', // 监听所有地址
port: 80, // 端口号
strictPort: false, // 端口被占用时自动递增
open: true, // 自动打开浏览器
// HMR配置(默认已优化,通常无需配置)
hmr: {
overlay: true, // 显示错误覆盖层
},
// 代理配置(解决跨域)
proxy: {
'/dev-api': {
target: 'http://127.0.0.1:5500',
changeOrigin: true,
ws: true, // 支持WebSocket
rewrite: (path) => path.replace(/^\/dev-api/, '')
}
}
}
})性能指标:
- 冷启动: ~500ms
- 热更新: ~50ms
- 页面加载: ~200ms
依赖预构建
Vite会自动预构建第三方依赖(node_modules),将CommonJS/UMD转换为ESM:
// vite.config.ts
export default defineConfig({
optimizeDeps: {
// 强制预构建的依赖项
include: [
'vue',
'vue-router',
'pinia',
'axios',
'@vueuse/core',
'echarts',
'vue-i18n',
'@vueup/vue-quill',
'image-conversion',
'element-plus/es/components/**/css',
'vue-json-pretty',
'file-saver',
'@wangeditor/editor-for-vue',
'qrcode'
],
// 排除预构建的依赖项(通常是ESM格式)
exclude: []
}
})预构建机制:
- 扫描源代码中的import语句
- 分析依赖图,找到需要预构建的包
- 使用Esbuild将依赖打包成单个ESM文件
- 缓存到
node_modules/.vite目录
预构建缓存失效条件:
package.json的dependencies字段变化- 包管理器的lockfile变化
vite.config.ts的optimizeDeps配置变化
路径别名优化
配置路径别名简化import路径,同时优化模块解析速度:
// vite.config.ts
import path from 'path'
export default defineConfig({
resolve: {
alias: {
'@': path.join(process.cwd(), './src')
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
}
})使用示例:
// 使用别名前
import { useUserStore } from '../../../stores/user'
// 使用别名后
import { useUserStore } from '@/stores/user'生产环境优化
构建配置
// vite.config.ts
export default defineConfig({
build: {
target: 'es2015', // 编译目标(支持的浏览器版本)
outDir: 'dist', // 输出目录
assetsDir: 'assets', // 静态资源目录
assetsInlineLimit: 4096, // 小于4KB的资源内联为base64
sourcemap: false, // 生产环境关闭Source Map
minify: 'esbuild', // 使用esbuild压缩(比terser快20倍)
// 代码分割策略
rollupOptions: {
output: {
// 手动分包
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'element-plus': ['element-plus'],
'echarts': ['echarts'],
'editor': ['@vueup/vue-quill', '@wangeditor/editor-for-vue']
},
// 文件命名规则
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: '[ext]/[name]-[hash].[ext]'
}
},
// Chunk大小警告阈值
chunkSizeWarningLimit: 1500
}
})构建产物结构:
dist/
├── index.html
├── js/
│ ├── app-[hash].js # 应用入口
│ ├── vue-vendor-[hash].js # Vue相关库
│ ├── element-plus-[hash].js # UI组件库
│ └── ...
├── css/
│ └── index-[hash].css
└── assets/
├── fonts/
└── images/代码分割策略
1. 路由懒加载
Vue Router支持路由级别的代码分割:
// src/router/index.ts
const routes = [
{
path: '/dashboard',
component: () => import('@/views/dashboard/index.vue'), // 懒加载
meta: { title: '仪表盘' }
},
{
path: '/system/user',
component: () => import('@/views/system/user/index.vue'),
meta: { title: '用户管理' }
}
]效果:
- 首屏只加载必要的路由组件
- 访问其他页面时按需加载
- 每个路由组件单独打包成一个chunk
2. 组件懒加载
使用defineAsyncComponent实现组件级懒加载:
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
// 异步加载大型组件
const HeavyChart = defineAsyncComponent(() =>
import('@/components/HeavyChart.vue')
)
</script>
<template>
<Suspense>
<template #default>
<HeavyChart />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>3. 动态导入
根据条件动态导入模块:
// 根据环境动态加载配置
const config = import.meta.env.PROD
? await import('@/config/prod')
: await import('@/config/dev')
// 根据用户权限动态加载模块
if (hasPermission('system:user:edit')) {
const { UserEditDialog } = await import('@/views/system/user/edit')
// 使用组件
}资源压缩
Gzip/Brotli压缩
使用vite-plugin-compression插件生成压缩文件:
// vite/plugins/compression.ts
import compression from 'vite-plugin-compression'
export default (env: any) => {
const { VITE_BUILD_COMPRESS } = env
const plugin: any[] = []
if (VITE_BUILD_COMPRESS) {
const compressList = VITE_BUILD_COMPRESS.split(',')
// Gzip压缩
if (compressList.includes('gzip')) {
plugin.push(
compression({
ext: '.gz',
deleteOriginFile: false // 保留原文件
})
)
}
// Brotli压缩(压缩率更高)
if (compressList.includes('brotli')) {
plugin.push(
compression({
ext: '.br',
algorithm: 'brotliCompress',
deleteOriginFile: false
})
)
}
}
return plugin
}环境变量配置:
# .env.production
VITE_BUILD_COMPRESS=gzip,brotli压缩效果对比:
| 文件 | 原始大小 | Gzip | Brotli |
|---|---|---|---|
| app.js | 500KB | 150KB (-70%) | 130KB (-74%) |
| vendor.js | 800KB | 250KB (-69%) | 220KB (-72%) |
| index.css | 100KB | 20KB (-80%) | 18KB (-82%) |
Nginx配置启用压缩:
# 启用Gzip
gzip on;
gzip_static on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 启用Brotli
brotli on;
brotli_static on;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;图片压缩
使用vite-plugin-imagemin压缩图片资源:
pnpm add -D vite-plugin-imagemin// vite.config.ts
import viteImagemin from 'vite-plugin-imagemin'
export default defineConfig({
plugins: [
viteImagemin({
gifsicle: { optimizationLevel: 7 },
optipng: { optimizationLevel: 7 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.8, 0.9] },
svgo: {
plugins: [
{ name: 'removeViewBox', active: false },
{ name: 'removeEmptyAttrs', active: true }
]
}
})
]
})CSS优化
PostCSS配置
自动添加浏览器前缀,移除冗余CSS:
// vite.config.ts
import autoprefixer from 'autoprefixer'
export default defineConfig({
css: {
postcss: {
plugins: [
// 自动添加浏览器前缀
autoprefixer(),
// 移除多余的@charset声明
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
atRule.remove()
}
}
}
]
},
// SCSS配置
preprocessorOptions: {
scss: {
api: 'modern-compiler', // 使用现代编译器
additionalData: '@use "@/assets/styles/variables.scss" as *;'
}
}
}
})CSS Modules
启用CSS Modules避免样式冲突:
<template>
<div :class="$style.container">
<h1 :class="$style.title">标题</h1>
</div>
</template>
<style module>
.container {
padding: 20px;
}
.title {
font-size: 24px;
}
</style>生成的类名: .container_1a2b3c、.title_4d5e6f(Hash值确保唯一性)
Tree Shaking优化
Vite基于Rollup自动进行Tree Shaking,移除未使用的代码。
有效的Tree Shaking示例:
// utils.ts
export function usedFunction() {
return 'used'
}
export function unusedFunction() { // 不会被打包
return 'unused'
}
// main.ts
import { usedFunction } from './utils' // 只导入需要的函数
console.log(usedFunction())注意事项:
- 使用ESM格式的依赖(CJS格式无法Tree Shaking)
- 避免副作用代码(会阻止Tree Shaking)
package.json中标记sideEffects: false
{
"sideEffects": false, // 所有文件都没有副作用
// 或指定有副作用的文件
"sideEffects": ["*.css", "*.scss"]
}插件优化
自动导入插件
unplugin-auto-import
自动导入Vue、Vue Router、Pinia等API:
// vite/plugins/auto-imports.ts
import autoImport from 'unplugin-auto-import/vite'
export default (path: any) => {
return autoImport({
imports: [
'vue',
'vue-router',
'pinia',
'@vueuse/core',
{
axios: [['default', 'axios']]
}
],
dts: path.join(process.cwd(), './types/auto-imports.d.ts'),
eslintrc: {
enabled: true,
filepath: './.eslintrc-auto-import.json'
}
})
}效果:
// 无需手动导入
// import { ref, computed, onMounted } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
onMounted(() => {
console.log('mounted')
})unplugin-vue-components
自动导入Element Plus组件:
// vite/plugins/components.ts
import components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default (path: any) => {
return components({
resolvers: [
ElementPlusResolver({
importStyle: 'sass' // 自动导入组件样式
})
],
dts: path.join(process.cwd(), './types/components.d.ts')
})
}效果:
<template>
<!-- 无需全局注册或导入 -->
<el-button type="primary">按钮</el-button>
<el-table :data="tableData"></el-table>
</template>UnoCSS原子化CSS
使用UnoCSS替代传统CSS,减小样式体积:
// vite/plugins/unocss.ts
import UnoCSS from 'unocss/vite'
import { presetUno, presetAttributify, presetIcons } from 'unocss'
export default () => {
return UnoCSS({
presets: [
presetUno(), // 基础工具类
presetAttributify(), // 属性化模式
presetIcons() // 图标支持
],
shortcuts: {
// 自定义快捷方式
'btn': 'px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600',
'card': 'p-4 rounded shadow-md bg-white'
}
})
}使用示例:
<template>
<!-- 原子化CSS类 -->
<div class="flex items-center justify-between p-4 bg-gray-100">
<button class="btn">提交</button>
</div>
<!-- 属性化模式 -->
<div flex items-center justify-between p-4 bg-gray-100>
<button class="btn">提交</button>
</div>
</template>优势:
- 按需生成CSS,只包含使用的类
- 比Tailwind CSS更小的bundle大小
- 支持自定义规则和快捷方式
图标优化
使用unplugin-icons按需加载图标:
// vite/plugins/icons.ts
import Icons from 'unplugin-icons/vite'
export default () => {
return Icons({
autoInstall: true, // 自动安装图标集
compiler: 'vue3'
})
}使用示例:
<script setup lang="ts">
import IconUser from '~icons/ep/user'
import IconEdit from '~icons/ep/edit'
</script>
<template>
<IconUser />
<IconEdit />
</template>优势:
- 只打包使用的图标,不会包含整个图标库
- 支持10万+图标(Iconify生态)
- 图标以Vue组件形式使用,支持样式定制
环境变量管理
环境变量文件
env/
├── .env # 所有环境共用
├── .env.development # 开发环境
└── .env.production # 生产环境示例配置:
# .env.production
NODE_ENV=production
# 应用配置
VITE_APP_TITLE=RuoYi-Plus管理系统
VITE_APP_PORT=80
VITE_APP_CONTEXT_PATH=/
VITE_APP_PUBLIC_PATH=/
# API配置
VITE_APP_BASE_API=/prod-api
VITE_APP_BASE_API_PORT=5500
# 构建配置
VITE_BUILD_COMPRESS=gzip,brotli
VITE_DELETE_CONSOLE=true
VITE_SHOW_SOURCEMAP=false使用环境变量
// vite.config.ts
import { loadEnv } from 'vite'
import path from 'path'
export default ({ mode }: ConfigEnv) => {
const env = loadEnv(mode, path.resolve(process.cwd(), 'env'))
return defineConfig({
base: env.VITE_APP_CONTEXT_PATH,
server: {
port: Number(env.VITE_APP_PORT)
}
})
}// 业务代码中使用
const apiBaseUrl = import.meta.env.VITE_APP_BASE_API
const isProduction = import.meta.env.PROD构建分析
使用rollup-plugin-visualizer可视化分析bundle体积:
pnpm add -D rollup-plugin-visualizer// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({
open: true, // 构建后自动打开分析报告
filename: 'stats.html', // 报告文件名
gzipSize: true, // 显示gzip后的大小
brotliSize: true // 显示brotli后的大小
})
]
})分析报告包含:
- 各个chunk的大小
- 依赖关系树
- 大型依赖识别
- 压缩后体积对比
UniApp构建优化
UniApp构建特点
UniApp采用"一次编写,多端运行"架构,构建时需要针对不同平台进行条件编译和代码转换:
支持平台:
- H5(Web)
- 小程序(微信/支付宝/百度/QQ/抖音/京东/快手/飞书/小红书)
- App(Android/iOS/HarmonyOS)
- 快应用
构建流程:
源码(Vue 3)
→ 条件编译(平台差异代码)
→ 代码转换(平台适配)
→ 资源优化(压缩/分包)
→ 产物输出(不同平台格式)平台编译命令
{
"scripts": {
// 开发环境
"dev:h5": "uni",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:app": "uni -p app",
// 生产环境
"build:h5": "uni build",
"build:mp-weixin": "uni build -p mp-weixin",
"build:app": "uni build -p app"
}
}命令区别:
- H5开发模式:
command=serve, mode=development - 小程序开发模式:
command=build, mode=development(注意是build,但mode是development) - 生产模式:
command=build, mode=production
Vite配置优化
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import createVitePlugins from './vite/plugins/index'
export default async ({ command, mode }: ConfigEnv) => {
const { UNI_PLATFORM } = process.env // mp-weixin, h5, app等
const env = loadEnv(mode, path.resolve(process.cwd(), 'env'))
const { VITE_DELETE_CONSOLE, VITE_SHOW_SOURCEMAP } = env
return defineConfig({
base: env.VITE_APP_PUBLIC_PATH || '/',
envDir: './env',
plugins: await createVitePlugins({ command, mode, env }),
define: {
__UNI_PLATFORM__: JSON.stringify(UNI_PLATFORM)
},
resolve: {
alias: {
'@': path.join(process.cwd(), './src')
}
},
server: {
host: '0.0.0.0',
hmr: true,
strictPort: false,
open: true
},
// 移除console和debugger
esbuild: {
drop: VITE_DELETE_CONSOLE === 'true'
? ['console', 'debugger']
: ['debugger']
},
// 依赖优化
optimizeDeps: {
include: ['jsencrypt/bin/jsencrypt.min.js', 'crypto-js']
},
build: {
sourcemap: VITE_SHOW_SOURCEMAP === 'true',
target: 'es6',
minify: mode === 'development' ? false : 'esbuild'
}
})
}条件编译优化
平台条件编译
使用条件编译减少不同平台的代码量:
<template>
<view>
<!-- #ifdef H5 -->
<web-view :src="url"></web-view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<web-view :src="url" @message="handleMessage"></web-view>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<web-view :src="url" :webview-styles="webviewStyles"></web-view>
<!-- #endif -->
</view>
</template>
<script setup lang="ts">
// #ifdef H5
import { setupH5Feature } from './h5'
setupH5Feature()
// #endif
// #ifdef MP-WEIXIN
import { setupWeixinFeature } from './weixin'
setupWeixinFeature()
// #endif
</script>
<style>
/* #ifdef H5 */
.container {
height: 100vh;
}
/* #endif */
/* #ifdef MP-WEIXIN */
.container {
height: 100%;
}
/* #endif */
</style>条件编译语法:
#ifdef PLATFORM: 仅在指定平台编译#ifndef PLATFORM: 除指定平台外都编译#ifdef PLATFORM1 || PLATFORM2: 多平台#ifdef PLATFORM1 && PLATFORM2: 交集平台
常用平台标识:
H5: H5平台MP-WEIXIN: 微信小程序MP-ALIPAY: 支付宝小程序APP-PLUS: App平台APP-ANDROID: AndroidAPP-IOS: iOS
JavaScript条件编译
// #ifdef H5
export const platform = 'h5'
export function h5OnlyFunction() {
// H5专用功能
}
// #endif
// #ifdef MP-WEIXIN
export const platform = 'weixin'
export function weixinOnlyFunction() {
// 微信小程序专用功能
}
// #endif
// 多平台共用
export function commonFunction() {
// #ifdef H5
console.log('H5环境')
// #endif
// #ifdef MP-WEIXIN
console.log('微信小程序环境')
// #endif
}小程序分包优化
分包配置
// pages.json
{
"pages": [
{
"path": "pages/index/index",
"style": { "navigationBarTitleText": "首页" }
}
],
"subPackages": [
{
"root": "pages-sub/user",
"pages": [
{
"path": "profile/index",
"style": { "navigationBarTitleText": "个人中心" }
},
{
"path": "settings/index",
"style": { "navigationBarTitleText": "设置" }
}
]
},
{
"root": "pages-sub/order",
"pages": [
{
"path": "list/index",
"style": { "navigationBarTitleText": "订单列表" }
}
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pages-sub/user"]
}
}
}分包策略:
- 主包: 首页、tabBar页面、公共资源
- 分包: 低频功能模块(个人中心、订单、设置等)
- 独立分包: 可独立运行的模块(如活动页)
分包大小限制(微信小程序):
- 主包: 2MB
- 单个分包: 2MB
- 总包: 20MB
预加载分包
使用preloadRule提前加载分包,优化体验:
{
"preloadRule": {
"pages/index/index": {
"network": "all", // wifi或4g都预加载
"packages": ["pages-sub/user"] // 预加载用户模块
},
"pages/mall/index": {
"network": "wifi", // 仅wifi预加载
"packages": ["pages-sub/order", "pages-sub/product"]
}
}
}分包异步化
将非必要依赖异步化,减小主包体积:
// 同步导入(会打包到主包)
import heavyLib from 'heavy-lib'
// 异步导入(会打包到分包)
const heavyLib = await import('heavy-lib')资源优化
图片优化
// 本地图片建议使用CDN
const imageUrl = 'https://cdn.example.com/images/banner.jpg'
// 小图标使用base64内联
const iconData = 'data:image/png;base64,iVBORw0KGgo...'
// 按需加载大图
const loadImage = () => {
return new Promise((resolve) => {
uni.getImageInfo({
src: imageUrl,
success: (res) => resolve(res)
})
})
}图片优化建议:
- 使用CDN托管图片
- 小于10KB的图标使用base64
- 大图按需加载
- 使用WebP格式(支持的平台)
字体图标优化
使用UnoCSS图标代替字体文件:
<template>
<!-- 使用图标类 -->
<view class="i-ep-user text-24px"></view>
<view class="i-ep-edit text-24px text-blue-500"></view>
</template>优势:
- 无需引入字体文件
- 按需生成SVG图标
- 支持颜色和大小定制
H5平台优化
H5平台的构建优化与前端管理端类似,但需注意移动端特性:
PWA支持
// vite/plugins/pwa.ts
import { VitePWA } from 'vite-plugin-pwa'
export default () => {
return VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'RuoYi-Plus UniApp',
short_name: 'RuoYi',
theme_color: '#ffffff',
icons: [
{
src: '/icon-192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: '/icon-512.png',
sizes: '512x512',
type: 'image/png'
}
]
},
workbox: {
// 缓存策略
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.example\.com\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 // 24小时
}
}
}
]
}
})
}移动端适配
// postcss.config.js
export default {
plugins: {
// px转rem
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*'],
selectorBlackList: ['.no-rem']
},
// 自动添加浏览器前缀
autoprefixer: {
overrideBrowserslist: [
'iOS >= 10',
'Android >= 5.0',
'Chrome >= 60'
]
}
}
}App平台优化
离线打包优化
使用HBuilderX离线打包减小包体积:
- 移除不使用的模块(如视频、地图)
- 使用自定义基座调试
- 开启资源压缩
- 配置混淆加密
原生插件优化
按需引入原生插件,避免打包不需要的功能:
// manifest.json
{
"app-plus": {
"modules": {
"Geolocation": {}, // 定位
"Camera": {} // 相机
// 注释掉不使用的模块
// "Video": {},
// "Audio": {}
}
}
}UniApp专用插件
@uni-helper系列插件
// vite/plugins/index.ts
import UniPages from '@uni-helper/vite-plugin-uni-pages'
import UniLayouts from '@uni-helper/vite-plugin-uni-layouts'
import UniManifest from '@uni-helper/vite-plugin-uni-manifest'
import UniComponents from '@uni-helper/vite-plugin-uni-components'
export default async () => {
return [
// 自动生成pages.json
UniPages({
dts: 'types/uni-pages.d.ts'
}),
// 布局系统
UniLayouts(),
// 自动生成manifest.json
UniManifest(),
// 自动导入组件
UniComponents({
dts: 'types/components.d.ts'
})
]
}优势:
- 约定式路由,无需手动配置pages.json
- 自动导入组件,减少重复代码
- TypeScript类型支持
bundle-optimizer
使用@uni-ku/bundle-optimizer优化小程序包体积:
// vite.config.ts
import { UniKuBundleOptimizer } from '@uni-ku/bundle-optimizer'
export default defineConfig({
plugins: [
UniKuBundleOptimizer({
// 移除未使用的样式
removeUnusedCss: true,
// 压缩JSON
compressJson: true,
// 移除注释
removeComments: true
})
]
})CI/CD构建优化
Docker多阶段构建
后端Docker构建
# 第一阶段: 构建
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
# 复制pom文件,利用Docker缓存依赖
COPY pom.xml .
COPY ruoyi-common/pom.xml ruoyi-common/
COPY ruoyi-modules/pom.xml ruoyi-modules/
COPY ruoyi-extend/pom.xml ruoyi-extend/
COPY ruoyi-admin/pom.xml ruoyi-admin/
# 下载依赖(利用缓存)
RUN mvn dependency:go-offline -B
# 复制源码
COPY . .
# 编译打包(并行编译,跳过测试)
RUN mvn clean package -T 1C -DskipTests -P prod
# 解压分层JAR
RUN java -Djarmode=layertools -jar ruoyi-admin/target/*.jar extract
# 第二阶段: 运行
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# 安装时区数据
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 分层复制(利用Docker缓存)
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost:5500/actuator/health || exit 1
# 启动应用
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]优化点:
- 依赖下载与源码复制分离,利用Docker缓存
- 多阶段构建,构建镜像不包含构建工具
- 使用JRE镜像而非JDK,减小镜像体积
- 分层复制JAR,依赖层可缓存
镜像大小对比:
- 单阶段构建: ~600MB
- 多阶段构建: ~200MB
前端Docker构建
# 第一阶段: 构建
FROM node:18-alpine AS builder
WORKDIR /app
# 安装pnpm
RUN npm install -g pnpm@8
# 复制package.json(利用缓存)
COPY package.json pnpm-lock.yaml ./
# 安装依赖
RUN pnpm install --frozen-lockfile
# 复制源码
COPY . .
# 构建生产版本
RUN pnpm build:prod
# 第二阶段: 运行
FROM nginx:alpine
# 复制Nginx配置
COPY nginx.conf /etc/nginx/nginx.conf
# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 暴露端口
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]镜像大小对比:
- 包含Node.js: ~400MB
- 仅包含Nginx: ~25MB
GitHub Actions工作流
# .github/workflows/build.yml
name: Build and Deploy
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
# 后端构建
backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 设置Java环境
- name: Setup Java 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'maven' # Maven依赖缓存
# 编译后端
- name: Build Backend
run: mvn clean package -T 1C -DskipTests -P prod
# 上传制品
- uses: actions/upload-artifact@v4
with:
name: backend-jar
path: ruoyi-admin/target/*.jar
# 前端构建
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 设置Node环境
- name: Setup Node.js 18
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'pnpm' # pnpm缓存
# 安装pnpm
- name: Install pnpm
run: npm install -g pnpm@8
# 安装依赖
- name: Install Dependencies
run: |
cd plus-ui
pnpm install --frozen-lockfile
# 构建前端
- name: Build Frontend
run: |
cd plus-ui
pnpm build:prod
# 上传制品
- uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: plus-ui/dist优化要点:
- 使用
cache: 'maven'和cache: 'pnpm'缓存依赖 - 并行执行后端和前端构建
- 使用
upload-artifact保存构建产物
GitLab CI/CD
# .gitlab-ci.yml
stages:
- build
- test
- deploy
# Maven依赖缓存
.maven-cache:
cache:
key: ${CI_COMMIT_REF_SLUG}-maven
paths:
- .m2/repository
# pnpm依赖缓存
.pnpm-cache:
cache:
key: ${CI_COMMIT_REF_SLUG}-pnpm
paths:
- .pnpm-store
# 后端构建
backend-build:
stage: build
image: maven:3.9-eclipse-temurin-21
extends: .maven-cache
script:
- mvn clean package -T 1C -DskipTests -P prod -Dmaven.repo.local=.m2/repository
artifacts:
paths:
- ruoyi-admin/target/*.jar
expire_in: 1 day
# 前端构建
frontend-build:
stage: build
image: node:18-alpine
extends: .pnpm-cache
before_script:
- npm install -g pnpm@8
- pnpm config set store-dir .pnpm-store
script:
- cd plus-ui
- pnpm install --frozen-lockfile
- pnpm build:prod
artifacts:
paths:
- plus-ui/dist
expire_in: 1 day
# UniApp构建
uniapp-build:
stage: build
image: node:18-alpine
extends: .pnpm-cache
before_script:
- npm install -g pnpm@8
- pnpm config set store-dir .pnpm-store
script:
- cd plus-uniapp
- pnpm install --frozen-lockfile
- pnpm build:h5
- pnpm build:mp-weixin
artifacts:
paths:
- plus-uniapp/dist
expire_in: 1 day缓存策略优化
Maven本地仓库缓存
# GitHub Actions
- uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# GitLab CI
cache:
key: ${CI_COMMIT_REF_SLUG}-maven
paths:
- .m2/repositoryNode依赖缓存
# GitHub Actions
- uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
# GitLab CI
cache:
key: ${CI_COMMIT_REF_SLUG}-pnpm
paths:
- .pnpm-storeDocker镜像层缓存
# 使用BuildKit缓存
- name: Build Docker Image
run: |
DOCKER_BUILDKIT=1 docker build \
--cache-from=myapp:latest \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t myapp:${{ github.sha }} \
.最佳实践
构建速度优化
1. 使用并行编译
Maven:
mvn clean install -T 1C # 每个CPU核心一个线程Vite: Vite默认已并行处理,无需配置。
2. 增量编译
# 仅编译变更模块
mvn install -pl ruoyi-system -am
# Vite自动增量编译
pnpm dev3. 跳过不必要的步骤
# 开发环境跳过测试
mvn clean package -DskipTests
# 跳过代码检查
mvn clean package -Dcheckstyle.skip -Dpmd.skip产物体积优化
1. 代码分割
前端:
- 路由懒加载
- 组件懒加载
- 动态导入
后端:
- 分层JAR
- 排除开发依赖
- 使用Thin JAR
2. 资源压缩
前端:
- Gzip/Brotli压缩
- 图片压缩
- CSS/JS压缩
后端:
- 移除调试信息
- JAR压缩
- 资源优化
3. Tree Shaking
前端:
- 使用ESM格式依赖
- 标记
sideEffects: false - 避免副作用代码
后端:
- 移除未使用的依赖
- 精简Spring Boot Starter
缓存策略
1. 本地缓存
Maven:
- 本地仓库:
~/.m2/repository - 插件缓存: 自动管理
Node:
- 全局缓存:
~/.pnpm-store - 项目缓存:
node_modules/.vite
2. CI/CD缓存
Maven:
cache:
paths:
- .m2/repositoryNode:
cache:
paths:
- .pnpm-store
- node_modules3. 浏览器缓存
Nginx配置:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}环境隔离
1. 多环境配置
后端:
application-dev.ymlapplication-test.ymlapplication-prod.yml
前端:
.env.development.env.test.env.production
2. Profile切换
Maven:
mvn clean package -P prodVite:
pnpm build --mode production监控与分析
1. 构建时间分析
Maven:
mvn clean install -Dspeed # Maven Profiler插件Vite:
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({ open: true })
]
})2. 产物大小分析
前端: 使用rollup-plugin-visualizer生成可视化报告。
后端: 使用maven-dependency-plugin分析依赖:
mvn dependency:tree
mvn dependency:analyze3. 性能监控
前端:
- Lighthouse性能评分
- Web Vitals指标
- Bundle大小监控
后端:
- 启动时间监控
- 内存占用监控
- JAR包大小监控
常见问题
1. Maven编译速度慢
问题原因:
- 单线程编译
- 未使用依赖缓存
- 网络连接慢
解决方案:
# 1. 使用并行编译
mvn clean install -T 1C
# 2. 配置国内镜像
# settings.xml
<mirrors>
<mirror>
<id>huaweicloud</id>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
# 3. 增量编译
mvn install -pl ruoyi-system -am2. Vite开发环境慢
问题原因:
- 依赖未预构建
- 大型依赖未优化
- HMR配置不当
解决方案:
// vite.config.ts
export default defineConfig({
optimizeDeps: {
// 强制预构建大型依赖
include: [
'vue',
'vue-router',
'pinia',
'element-plus',
'echarts'
]
},
server: {
// 启用HMR
hmr: true,
// 监听文件变化
watch: {
usePolling: false
}
}
})3. 生产构建体积过大
问题原因:
- 未启用代码分割
- 未移除未使用代码
- 未压缩资源
解决方案:
// vite.config.ts
export default defineConfig({
build: {
// 启用代码分割
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'element-plus': ['element-plus'],
'echarts': ['echarts']
}
}
},
// 压缩选项
minify: 'esbuild',
// 移除console
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}
})启用Gzip/Brotli压缩:
// vite/plugins/compression.ts
import compression from 'vite-plugin-compression'
export default () => {
return [
compression({ ext: '.gz' }),
compression({ ext: '.br', algorithm: 'brotliCompress' })
]
}4. Docker构建缓存失效
问题原因:
- Dockerfile层顺序不当
- 依赖文件频繁变化
- 未使用多阶段构建
解决方案:
# 后端Dockerfile优化
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
# 先复制pom文件(利用缓存)
COPY pom.xml .
COPY ruoyi-common/pom.xml ruoyi-common/
COPY ruoyi-modules/pom.xml ruoyi-modules/
RUN mvn dependency:go-offline -B
# 再复制源码
COPY . .
RUN mvn clean package -T 1C -DskipTests
# 运行阶段
FROM eclipse-temurin:21-jre-alpine
COPY --from=builder /app/ruoyi-admin/target/*.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]前端Dockerfile优化:
FROM node:18-alpine AS builder
WORKDIR /app
# 先安装依赖(利用缓存)
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
# 再复制源码
COPY . .
RUN pnpm build:prod
# 运行阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html5. UniApp小程序包体积超限
问题原因:
- 未使用分包
- 图片未优化
- 依赖过大
解决方案:
1. 配置分包:
// pages.json
{
"subPackages": [
{
"root": "pages-sub/user",
"pages": [
{ "path": "profile/index" },
{ "path": "settings/index" }
]
}
]
}2. 图片优化:
// 使用CDN
const imageUrl = 'https://cdn.example.com/image.jpg'
// 小图标使用base64
const iconData = 'data:image/png;base64,...'3. 按需加载依赖:
// 异步导入大型库
const echarts = await import('echarts')6. CI/CD构建超时
问题原因:
- 未使用缓存
- 网络速度慢
- 构建步骤串行
解决方案:
1. 配置缓存:
# GitHub Actions
- uses: actions/cache@v4
with:
path: |
~/.m2/repository
~/.pnpm-store
key: ${{ runner.os }}-deps-${{ hashFiles('**/*.lock', '**/pom.xml') }}2. 并行构建:
jobs:
backend:
runs-on: ubuntu-latest
steps: [...]
frontend:
runs-on: ubuntu-latest
steps: [...]
# 后端和前端并行执行3. 使用自托管Runner:
runs-on: self-hosted # 使用本地Runner,网络速度快7. Source Map占用过多空间
问题原因:
- 生产环境未关闭Source Map
- Source Map未分离
解决方案:
// vite.config.ts
export default defineConfig({
build: {
sourcemap: process.env.NODE_ENV !== 'production', // 生产环境关闭
// 或使用hidden模式(生成但不引用)
// sourcemap: 'hidden'
}
})后端:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<debug>false</debug> <!-- 关闭调试信息 -->
</configuration>
</plugin>总结
构建优化是一个持续迭代的过程,需要根据项目实际情况选择合适的优化策略:
后端构建优化核心:
- 多模块并行编译
- 依赖管理和缓存
- 分层JAR和Docker优化
- 测试和资源过滤策略
前端构建优化核心:
- Vite极速HMR和预构建
- 代码分割和懒加载
- 资源压缩和Tree Shaking
- 插件自动化和优化
UniApp构建优化核心:
- 条件编译减少冗余代码
- 分包和预加载策略
- 资源优化和CDN
- 多平台构建适配
CI/CD构建优化核心:
- Docker多阶段构建
- 缓存策略和并行执行
- 增量构建和制品管理
- 监控和性能分析
通过综合应用这些优化策略,RuoYi-Plus-UniApp项目的构建效率可提升60%以上,产物体积可减小40%以上,开发体验和生产性能都得到显著改善。
