Maven / Gradle / Node 构建
本文范围
平时我们说“把项目打个包”,听起来像一句命令的事,真到现场会发现它其实要解决三个问题:
- 依赖能不能稳定下载下来。
- 同一份代码在开发机、CI、内网机器上能不能打出同一个结果。
- 打出来的 jar、war、
dist目录能不能交给部署系统,并且出问题时能回滚。
所以这一篇不把 Maven、Gradle、Node 当成零散命令背一遍,而是按一次真实构建来走:先确认工具版本,再配置仓库,再执行构建,再看产物,最后排查失败。
这里重点讲这些内容:
- Maven 怎么走 lifecycle,
settings.xml怎么配私服,依赖冲突怎么查,target/里哪些文件才是制品。 - Gradle 为什么优先用 Wrapper,任务怎么跑,依赖怎么查,
build/libs/怎么交给部署。 - Node、npm、pnpm 怎么锁版本、锁依赖、读环境变量,怎么产出
dist/build。 - 中国大陆公网、企业内网、离线环境下,依赖怎么闭环,缓存怎么准备,失败怎么定位。
这里不讲 Jenkins 完整流水线,也不展开 Java / Spring Boot 业务开发,不展开 Vue / React 框架写法,不展开 Docker、K8S、Nginx 的完整部署。我们只把构建这一步讲透:源码进来,制品出去,中间每一步都能解释、能验证、能排障。
截至 2026-07-09,官方页面显示的关键版本参考是:
| 工具 | 当前官方状态 | 本文建议 |
|---|---|---|
| Maven | Maven 3.9.16 是官方推荐的最新稳定版;Maven 4.0.0-rc-5 仍是预览版 | 生产主线用 Maven 3.9.x;Maven 4 先做兼容验证 |
| Gradle | Gradle 9.6.1 是官方 release 页面上的最新版本 | 项目使用 Wrapper 固定版本,不依赖机器全局 Gradle |
| Node.js | Node.js v24.18.0 LTS,v26.5.0 Current | 生产构建优先 LTS,Current 只用于验证新特性 |
| npm | npm 官方文档当前主线为 CLI 11.x | CI 使用 npm ci,不要用会改 lockfile 的安装方式 |
| pnpm | pnpm 官方文档当前主线为 11.x | CI 使用 lockfile 和 frozen install;离线环境预热 store |
版本每天都可能变,真正落地时要以你安装当天的官方 release、企业基础镜像、私服兼容矩阵和安全基线为准。
前置条件
你需要一份 Java 或前端项目源码,至少能区分它使用 Maven、Gradle、npm 还是 pnpm。后端构建要先确认 JDK 版本和构建工具版本;前端构建要先确认 Node.js 版本、包管理器、lockfile 和环境变量。CI 节点、开发机、内网构建机应该使用同一套版本约束。
先检查:
java -version
mvn -v 2>/dev/null || true
./gradlew --version 2>/dev/null || true
node -v 2>/dev/null || true
npm -v 2>/dev/null || true
pnpm -v 2>/dev/null || true生产构建优先使用 Active LTS 或 Maintenance LTS 的 Node.js,Maven/Gradle 版本以项目约束和企业基础镜像为准。企业内网需要提前准备 Maven 私服、Gradle distributionUrl、npm registry、CA 证书、代理、缓存和离线包;离线环境不能现场临时下载依赖,要先在有网环境把依赖闭环验证出来。
先别急着打包,先把环境验明白
拿到一个项目,很多人第一反应是直接敲:
mvn clean package
npm run build如果一次成功还好;如果失败,日志一长就不知道从哪里看。更稳的做法是先把工具链验一遍。这里就像进机房先看电源、网络、磁盘一样,构建也要先看 JDK、Maven、Gradle、Node、仓库配置。
后端 Maven 项目先执行:
java -version
mvn -v这里要看两个点:JDK 版本是不是项目要求的版本,Maven 版本是不是团队统一的版本。如果这里显示的是一套很老的 Maven,后面报插件下载失败、编译参数不兼容,就不要先怀疑代码。
Gradle 项目先不要装全局 Gradle,先看项目里有没有 Wrapper:
ls -l gradlew gradle/wrapper/gradle-wrapper.properties
./gradlew --version如果能看到 Gradle 版本、JVM 信息和操作系统信息,说明 Wrapper 能正常工作。失败时先看 gradle-wrapper.properties 里的 distributionUrl 能不能访问。
前端项目先看 Node 和包管理器:
node -v
npm -v
pnpm -v如果项目里有 .nvmrc、.node-version 或 package.json 的 engines,先按项目要求切版本。很多前端构建失败,不是依赖错了,而是 Node 版本比项目要求高一代或低一代。
环境没问题后,再进入正式构建链路。一个稳定构建不是只执行一条 mvn package 或 npm run build。它至少包括这几步:
确认工具版本 -> 解析依赖 -> 执行测试和检查 -> 产出制品 -> 记录元数据 -> 上传制品仓库 -> 部署系统取制品 -> 发布后验证把 Java 和前端放在一起看,差异主要在工具与仓库,交付链路是一致的。
统一构建链路总览
所以构建排障要同时看工具版本、依赖来源、lockfile 或 Wrapper、制品元数据和部署取包路径。
对应到常见项目:
| 项目 | 依赖输入 | 构建命令 | 输出目录 | 交付制品 |
|---|---|---|---|---|
| Maven Java | pom.xml、settings.xml、本地/远程仓库 | mvn clean verify、mvn clean package | target/ | *.jar、*.war、测试报告 |
| Gradle Java | settings.gradle、build.gradle、Wrapper、仓库 | ./gradlew clean build、./gradlew bootJar | build/、build/libs/ | *.jar、*.war、测试报告 |
| npm 前端 | package.json、package-lock.json、.npmrc | npm ci、npm run build | dist/、build/ | 静态资源目录 |
| pnpm 前端 | package.json、pnpm-lock.yaml、.npmrc | pnpm install --frozen-lockfile、pnpm run build | dist/、build/ | 静态资源目录 |
生产上最怕的是“我本机能打包”。构建必须能在一台干净机器、一个固定版本的 CI 节点或一个受控内网环境里复现。复现依赖四件事:
- 工具链版本固定,例如 JDK、Maven、Gradle、Node、npm、pnpm。
- 依赖来源固定,例如 Maven 私服、npm 私服、Gradle 插件仓库。
- 依赖解析结果固定,例如 lockfile、BOM、dependency management、Gradle lock。
- 制品元数据固定,例如 Git commit、构建时间、构建号、工具版本、目标环境。
依赖解析与制品流图
发布评审不要只问“构建命令是什么”,还要问依赖从哪里来、缓存是否可信、lockfile 是否能约束结果、制品是否进入可追踪仓库。下面这张图把 Maven、Gradle、npm、pnpm 放在同一个构建控制面里看,适合上线前确认依赖闭环,也适合排查“本地能打包,CI 不行”的问题。
如果构建不可复现,就顺着图查输入差异:mvn dependency:tree 看传递依赖和 BOM,./gradlew dependencies / dependencyInsight 看 Gradle 解析结果,npm ci 和 pnpm install --frozen-lockfile 看锁定文件是否漂移。缓存只作为提速层,不能替代 Nexus、registry、lockfile、checksum 和制品版本追踪;一旦怀疑缓存污染,先清项目输出,再按 Maven local repository、Gradle dependency cache、npm cache、pnpm store 的顺序定位,不要直接把整台 CI 机器的缓存一把删光。
Maven 基础和 lifecycle
先从 Maven 开始。Maven 项目最核心的文件是 pom.xml,它里面写了项目坐标、依赖、插件、profile、打包方式和发布仓库。你可以把它理解成这个项目的“构建说明书”。
先验证环境:
java -version
mvn -v如果 mvn -v 显示的 Maven 版本不是团队要求的版本,先不要打包。很多构建失败不是代码问题,而是 PATH 里用了另一套 Maven。
Maven 默认有三个内置 lifecycle:
| lifecycle | 用途 |
|---|---|
clean | 清理上一次构建输出 |
default | 编译、测试、打包、验证、安装、部署 |
site | 生成项目站点 |
日常最常用的是 default lifecycle 的几个 phase:
| phase | 作用 | 常用命令 |
|---|---|---|
validate | 校验项目信息 | mvn validate |
compile | 编译主代码 | mvn compile |
test | 执行测试 | mvn test |
package | 打出 jar / war | mvn package |
verify | 执行集成检查和质量门禁 | mvn verify |
install | 安装到本机 .m2 仓库 | mvn install |
deploy | 上传到远程制品仓库 | mvn deploy |
Maven phase 是顺序执行的。执行 mvn package 时,前面的 validate、compile、test 也会先执行。执行 mvn deploy 时,前面的编译、测试、打包、安装都会先跑。
常用构建命令:
mvn clean verify
mvn clean package
mvn clean install
mvn clean deploy这几条命令不要混着用,先记住场景:
mvn clean verify:适合本地提交前和 CI,目标是把编译、测试、检查都跑一遍。mvn clean package:适合只想拿到 jar / war,成功后去target/目录找制品。mvn clean install:适合多模块本地联调,会把当前模块装进本机.m2仓库。mvn clean deploy:适合 CI 上传制品到 Maven 私服,普通开发机一般不要随手执行。
比如我们先打一遍包:
mvn clean package
ls -lh target/正常情况下,终端最后应该看到 BUILD SUCCESS,target/ 下面应该有 xxx.jar 或 xxx.war。如果没有制品,先看 pom.xml 的 packaging 是不是 pom;聚合父工程本身通常不会产出业务 jar。
多模块项目常用:
# 只构建 order-service,并自动构建它依赖的同仓库模块
mvn -pl order-service -am clean package
# 从某个模块开始继续构建
mvn -rf :order-service clean package
# 多线程构建,1C 表示按 CPU 核数
mvn -T 1C clean package多线程构建不是越大越好。插件线程不安全、测试争用端口、数据库初始化冲突、前端插件调用外部命令时,都可能让 -T 变成不稳定来源。CI 初期建议先保证串行稳定,再逐步加线程。
这里要注意,多模块构建失败时不要一上来全量重跑。先看失败模块,然后用 -rf 从失败模块继续,这样能省不少时间:
mvn -rf :order-service clean package如果继续失败,再回到根目录全量跑一次,确认不是前面模块留下的状态问题。
Maven settings.xml 和私服
Maven 有两个常见配置位置:
$MAVEN_HOME/conf/settings.xml
$HOME/.m2/settings.xml团队里建议不要让每个人手工改全局 Maven 安装目录。更稳的方式是给 CI 和开发者提供一份标准 settings.xml 模板,放到用户目录,或者在构建命令里显式指定:
mvn -s ./ci/settings.xml clean deploy如果用户目录下还没有 Maven 配置,就新建:
mkdir -p ~/.m2
vi ~/.m2/settings.xmlWindows 上一般在用户目录的 .m2 下面新建 settings.xml。不要把带密码的 settings.xml 放进项目仓库,尤其不要为了“方便大家构建”把私服账号提交上去。
先看 Maven 实际用了什么配置:
mvn help:effective-settings
mvn help:effective-pom这两条命令很实用。effective-settings 用来看镜像、私服、server 账号到底有没有生效;effective-pom 用来看父 POM、BOM、profile 合并之后最终 Maven 看到的项目长什么样。排查“我明明配了私服为什么还去外网下载”时,先看这里。
企业内网常见结构是:
开发机 / CI -> Maven 私服 group 仓库 -> proxy Maven Central / 国内镜像 / 内部 releases / snapshotssettings.xml 的关键是 mirrors、servers、profiles。
一个通用私服镜像示例:
<settings>
<mirrors>
<mirror>
<id>company-maven-public</id>
<name>Company Maven Public</name>
<url>https://repo.example.com/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<servers>
<server>
<id>company-releases</id>
<username>${env.MAVEN_REPO_USER}</username>
<password>${env.MAVEN_REPO_PASSWORD}</password>
</server>
<server>
<id>company-snapshots</id>
<username>${env.MAVEN_REPO_USER}</username>
<password>${env.MAVEN_REPO_PASSWORD}</password>
</server>
</servers>
<profiles>
<profile>
<id>company-repo</id>
<repositories>
<repository>
<id>company-releases</id>
<url>https://repo.example.com/repository/maven-releases/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>company-snapshots</id>
<url>https://repo.example.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>company-repo</activeProfile>
</activeProfiles>
</settings>注意几个细节:
mirrorOf=*表示所有远程仓库都走这个镜像。企业内网闭环时很常用。- 不要配置多个互相冲突的
mirrorOf=*。Maven 对同一个远程仓库只会选择一个 mirror。 servers.server.id必须和pom.xml或settings.xml中仓库的id对上,否则认证不会生效。- 密码不要提交到代码仓库。可以由 CI 凭据注入、构建镜像模板渲染,或使用 Maven 的密码加密机制。
- 如果使用
${env.xxx}这类占位方式,必须用mvn help:effective-settings在你的 Maven 版本里验证确实被解析。
项目里发布仓库通常写在 pom.xml:
<distributionManagement>
<repository>
<id>company-releases</id>
<url>https://repo.example.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>company-snapshots</id>
<url>https://repo.example.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>发布命令:
mvn -s ./ci/settings.xml clean deploy执行成功后,终端应该看到上传到 releases 或 snapshots 仓库的日志。失败时先不要改 POM,先看 HTTP 状态:
401一般是账号密码没生效。403一般是账号没有发布权限。409常见于 release 版本重复发布,私服不允许覆盖。404多半是仓库地址、repository id 或代理路径写错。
验证私服里是否有制品:
mvn dependency:get \
-Dartifact=com.example:order-service:1.0.0 \
-DremoteRepositories=company::default::https://repo.example.com/repository/maven-public/Maven 依赖管理和冲突排查
Maven 依赖冲突常见表现:
- 编译时报
package xxx does not exist。 - 启动时报
ClassNotFoundException。 - 运行时报
NoSuchMethodError或NoClassDefFoundError。 - 本地能跑,CI 或服务器不能跑。
- 升级一个依赖后,另一个组件行为异常。
先看依赖树:
mvn dependency:tree
mvn dependency:tree -Dincludes=org.slf4j
mvn dependency:tree -Dincludes=com.fasterxml.jackson.core
mvn dependency:tree -Dverbose查看有效 POM:
mvn help:effective-pom分析未使用或未声明依赖:
mvn dependency:analyzeMaven 依赖版本选择的高频规则:
- 直接依赖优先于传递依赖。
- 路径更近的依赖优先。
- 路径一样近时,先声明的依赖可能胜出。
dependencyManagement只管理版本,不会自动引入依赖。- BOM 本质上是导入一组 dependency management。
推荐用 BOM 或父 POM 统一版本:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>排除冲突依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>legacy-client</artifactId>
<version>1.2.0</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>生产建议:
- 不要在业务模块里散落一堆不同版本的 Jackson、Netty、Guava、日志组件。
- 公司公共组件要有清晰版本策略,SNAPSHOT 只用于开发联调,不进生产发布基线。
- 多模块项目里,底层模块先
mvn install,或者统一从根目录-am构建,避免 IDE 缓存造成误判。 - 构建服务器要从干净环境验证,不要依赖某个人本机
.m2里历史安装过的包。
Maven profile 和跳过测试
Maven profile 适合处理构建差异,例如不同仓库、不同插件开关、不同打包参数。它不适合把所有运行时配置都编译进 jar。数据库密码、外部服务地址、生产密钥应由部署环境注入,而不是靠打不同 jar 解决。
POM profile 示例:
<profiles>
<profile>
<id>prod</id>
<properties>
<build.env>prod</build.env>
</properties>
</profile>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.env>dev</build.env>
</properties>
</profile>
</profiles>使用:
mvn clean package -Pprod
mvn help:active-profiles跳过测试有两个常见参数:
# 跳过测试执行,但仍编译测试代码
mvn clean package -DskipTests
# 跳过测试编译和测试执行
mvn clean package -Dmaven.test.skip=true生产建议:
- 本地临时打包可以
-DskipTests,但发布制品前应至少跑一次mvn verify。 -Dmaven.test.skip=true风险更高,因为测试代码也不编译,可能掩盖接口变更。- 如果测试慢,应该拆单元测试、集成测试和冒烟测试,而不是永久跳过。
- CI 里如果允许跳过测试,要让构建日志和制品元数据能看出来。
Maven 制品目录和部署交接
Maven 默认输出目录是:
target/常见文件:
target/order-service-1.0.0.jar
target/order-service-1.0.0.war
target/surefire-reports/
target/failsafe-reports/验证 jar:
ls -lh target/*.jar
jar tf target/order-service-1.0.0.jar | head
java -jar target/order-service-1.0.0.jar --version如果是 Spring Boot 可执行 jar:
java -jar target/order-service-1.0.0.jar --spring.profiles.active=prod交给部署链路时,不要只丢一个文件名。至少记录:
app=order-service
version=1.0.0
git_commit=a1b2c3d
build_time=2026-07-09T15:30:00+08:00
build_tool=maven-3.9.16
jdk=17.0.x
artifact=order-service-1.0.0.jar
sha256=...生成校验值:
sha256sum target/order-service-1.0.0.jar > target/order-service-1.0.0.jar.sha256部署系统拿到 jar 后要验证:
sha256sum -c order-service-1.0.0.jar.sha256
java -jar order-service-1.0.0.jar --versionGradle 基础:优先使用 Wrapper
Gradle 项目先记住一句话:优先用项目里的 Wrapper,不要先去机器上装全局 gradle。原因很简单,Wrapper 会把 Gradle 版本跟项目绑在一起,别人拿到代码后执行同一条命令,下载同一个 Gradle 发行包,结果更容易一致。
先看项目里有没有这些文件:
gradlew
gradlew.bat
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties验证:
./gradlew --version
./gradlew tasks执行 ./gradlew --version 后,应该能看到 Gradle 版本、Kotlin/Groovy 版本、JVM 版本和操作系统。执行 ./gradlew tasks 后,应该能看到 build、clean、test 这类任务。这里如果卡在下载 Gradle,先看网络和 distributionUrl,不要急着改业务代码。
Windows:
.\gradlew.bat --version
.\gradlew.bat tasks升级 Wrapper:
./gradlew wrapper --gradle-version 9.6.1如果项目没有 Wrapper,一般需要在一台可以使用 Gradle 的机器上生成一次 Wrapper,再把 gradlew、gradlew.bat 和 gradle/wrapper/ 提交到仓库。不要只提交 build.gradle,让每个人自己装 Gradle。
检查 gradle/wrapper/gradle-wrapper.properties:
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip企业内网建议把 distributionUrl 指向内部可信地址:
distributionUrl=https\://repo.example.com/gradle/distributions/gradle-9.6.1-bin.zip同时保存官方 ZIP 的校验值。不要让每次 CI 构建都临时访问外网下载 Gradle。
Gradle 仓库、依赖和常用命令
Gradle 常见文件:
settings.gradle
settings.gradle.kts
build.gradle
build.gradle.kts
gradle.properties仓库配置建议集中在 settings.gradle:
pluginManagement {
repositories {
maven { url = uri("https://repo.example.com/repository/gradle-plugins/") }
maven { url = uri("https://repo.example.com/repository/maven-public/") }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven { url = uri("https://repo.example.com/repository/maven-public/") }
}
}
rootProject.name = "order-platform"
include "order-service"Java 项目最小构建:
plugins {
id "java"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
dependencies {
implementation "org.apache.commons:commons-lang3:3.18.0"
testImplementation "org.junit.jupiter:junit-jupiter:5.11.0"
}
test {
useJUnitPlatform()
}常用命令:
# 清理、测试、打包
./gradlew clean build
# 只打 jar
./gradlew jar
# Spring Boot 项目常见可执行 jar
./gradlew bootJar
# 跳过测试
./gradlew build -x test
# 查看任务
./gradlew tasks --all
# 输出更多日志和异常栈
./gradlew clean build --info --stacktrace正常构建成功时,最后应该看到 BUILD SUCCESSFUL,制品一般在 build/libs/。如果失败,先加 --stacktrace 看完整异常,再决定查依赖、插件还是代码编译问题。
CI 中常见写法:
./gradlew clean build --no-daemon --stacktraceGradle Daemon 对开发机很友好,但 CI 容器或一次性构建节点中常用 --no-daemon,减少后台进程残留和缓存锁问题。
这里要注意,-x test 只是跳过测试,不代表项目真的可以发布。临时排查可以用,发布制品前至少要有一次完整的 ./gradlew clean build 或团队规定的质量门禁。
Gradle 依赖冲突、缓存和离线构建
查看依赖:
./gradlew dependencies
./gradlew dependencies --configuration runtimeClasspath定位某个依赖为什么进来:
./gradlew dependencyInsight --dependency guava --configuration runtimeClasspath
./gradlew dependencyInsight --dependency slf4j --configuration runtimeClasspath刷新依赖:
./gradlew build --refresh-dependencies离线构建:
./gradlew build --offline常见缓存位置:
$HOME/.gradle/caches
$HOME/.gradle/wrapper
项目目录/.gradle
项目目录/build缓存使用建议:
- CI 可以缓存
$HOME/.gradle/caches和$HOME/.gradle/wrapper,缓存 key 要包含 Gradle Wrapper 版本、JDK 版本、构建脚本和 lock 文件。 - 不建议跨分支长期缓存项目
build/目录,容易把旧 class、旧资源或旧前端产物带进来。 - 遇到诡异编译问题,先
./gradlew clean build,再考虑清理项目.gradle。 - 不要一上来删除整个
$HOME/.gradle,那会让下一次构建重新下载所有依赖。
启用本地构建缓存:
org.gradle.caching=truegradle.properties 常见配置:
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
org.gradle.caching=true
org.gradle.parallel=true如果团队要更强的可复现性,可以启用 Gradle dependency locking:
dependencyLocking {
lockAllConfigurations()
}生成或更新 lock:
./gradlew dependencies --write-locksGradle 制品目录
Gradle 默认输出目录是:
build/Java jar 常见位置:
build/libs/order-service-1.0.0.jar测试报告:
build/reports/tests/test/index.html
build/test-results/test/验证:
ls -lh build/libs/
jar tf build/libs/order-service-1.0.0.jar | head
java -jar build/libs/order-service-1.0.0.jar --version生成校验:
sha256sum build/libs/order-service-1.0.0.jar > build/libs/order-service-1.0.0.jar.sha256Gradle 和 Maven 的交付原则一样:部署链路拿 jar / war 和元数据,不拿构建目录、IDE 缓存、开发机本地依赖。
Node 构建:先固定版本
前端构建第一件事不是 npm install,而是确认 Node 版本。Node 版本不一致,会引起依赖解析、原生模块、构建工具、语法支持和产物差异。现场排查前端构建问题时,第一眼就看 node -v,这一步很土,但特别有效。
验证:
node -v
npm -v如果项目用 pnpm,再看:
pnpm -v这里要和项目里的 .nvmrc、.node-version、package.json 对上。比如项目要求 Node 24 LTS,你本机是 Node 26 Current,构建工具能跑不代表产物一定稳定。
项目里建议放一个版本约束:
.nvmrc
.node-version
package.json.nvmrc 示例:
24.18.0package.json 示例:
{
"engines": {
"node": ">=24 <25"
},
"packageManager": "pnpm@11.0.0"
}生产建议:
- CI 镜像、构建机或构建容器中固定 Node LTS 版本。
- 不要让不同项目混用全局 Node 和全局包管理器。
- 如果使用 pnpm,固定 pnpm 版本;不要只依赖某个人开发机的全局 pnpm。
- 原生模块要关注操作系统、CPU 架构和 libc。Linux glibc、Alpine musl、Windows、macOS 构建出来的依赖不能随便混用。
npm 构建:npm install 和 npm ci 的边界
npm 项目核心文件:
package.json
package-lock.json
.npmrc本地开发新增依赖:
npm install axios
npm install -D viteCI 或干净构建:
npm ci
npm run build这两条命令就是 npm 项目的标准发布前动作。npm ci 成功后应该生成新的 node_modules,但不会改 package-lock.json;npm run build 成功后,应该能看到 dist/、build/ 或框架约定的输出目录。
一般本地新增依赖才用 npm install,CI 不建议用它。CI 如果用 npm install,lockfile 漂移可能被悄悄吞掉,今天构建和明天构建拿到的依赖就可能不一样。
npm ci 和 npm install 的关键差异:
| 命令 | 适合场景 | 行为 |
|---|---|---|
npm install | 本地开发、添加依赖、更新 lockfile | 可能更新 package-lock.json |
npm ci | CI、测试平台、部署前构建 | 要求 lockfile 存在且匹配;会删除已有 node_modules;不会改 lockfile |
如果 CI 报 lockfile 不匹配,正确处理不是在 CI 里改 lockfile,而是在开发机更新并提交:
npm install
git diff package-lock.json
git add package.json package-lock.json
git commit -m "更新前端依赖锁定文件"查看 npm registry:
npm config get registry
npm pingnpm config get registry 要看它是不是指向团队要求的 registry。npm ping 能通,只能说明 registry 可访问;如果安装某个私有包失败,还要继续看 scope、token 和权限。
项目级 .npmrc 示例:
registry=https://registry.npmjs.org/
strict-peer-deps=false
fund=false
audit=false企业私服示例:
registry=https://npm.example.com/
@company:registry=https://npm.example.com/
always-auth=truetoken 不要提交到仓库。CI 可以在构建时注入:
npm config set //npm.example.com/:_authToken "$NPM_TOKEN"
npm ci
npm run build排查依赖:
npm ls
npm ls vite
npm explain vite
npm outdated
npm cache verifypnpm 构建:lockfile、store 和离线能力
pnpm 项目核心文件:
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
.npmrc安装:
pnpm installCI:
pnpm install --frozen-lockfile
pnpm run build这里的 --frozen-lockfile 很关键。它的意思是:依赖必须和 pnpm-lock.yaml 对得上,不能在 CI 里偷偷改锁定文件。成功后再执行 pnpm run build,看输出目录是否生成。
在 CI 环境里,如果 lockfile 存在但需要更新,pnpm 默认会让 frozen install 失败。这是好事,说明代码里的依赖声明和锁定文件不一致。
常用命令:
# 只按 lockfile 下载依赖到 store,适合 Docker/CI 缓存预热
pnpm fetch
# 离线安装,只使用本地 store
pnpm install --offline
# 优先使用本地缓存,缺少时仍会访问 registry
pnpm install --prefer-offline
# 查看 store 位置
pnpm store path
# 清理未引用的 store 内容
pnpm store prune
# 看某个包为什么存在
pnpm why vitepnpm 的性能优势来自内容寻址 store 和链接机制。也因此,离线环境要带的不只是 node_modules,更推荐带 lockfile 和 pnpm store。
离线准备流程:
pnpm install --frozen-lockfile
pnpm store path
pnpm fetch离线目标机:
pnpm install --offline --frozen-lockfile
pnpm run build如果这里提示缺包,说明离线前 pnpm fetch 或 store 打包不完整。不要在客户现场临时改成联网安装,应该回到有网环境补齐 store,再重新生成校验和。
如果 store 损坏或 integrity 不一致,常见处理是先验证来源,再重新拉取。不要在生产环境里随便用会绕过校验的参数。
前端环境变量和构建产物
前端环境变量要分清两类:
- 构建时变量:打包时被替换进静态资源。
- 运行时变量:部署后由 Nginx、配置接口、
config.js或服务端渲染注入。
常见构建命令:
npm run build
pnpm run buildpackage.json 示例:
{
"scripts": {
"dev": "vite --host 0.0.0.0",
"build": "vite build",
"preview": "vite preview"
}
}构建环境变量示例:
NODE_ENV=production npm run build
VITE_API_BASE=/api pnpm run build这里要注意,NODE_ENV=production 是告诉构建工具按生产模式优化;VITE_API_BASE=/api 这类变量通常会被打进静态资源。打进去之后,浏览器里是能看到的,所以不要把密钥、数据库密码、服务端 token 放进去。
不同框架变量前缀不同:
| 构建工具 / 框架 | 常见公开变量前缀 |
|---|---|
| Vite | VITE_ |
| Create React App | REACT_APP_ |
| Next.js 浏览器侧 | NEXT_PUBLIC_ |
凡是打进前端静态资源的变量,都可以被浏览器看到。不要把数据库密码、服务端 token、云厂商密钥放进前端环境变量。
常见输出目录:
dist/
build/
.next/传统单页应用常见交付:
npm ci
npm run build
tar czf web-dist-1.0.0.tar.gz dist/
sha256sum web-dist-1.0.0.tar.gz > web-dist-1.0.0.tar.gz.sha256执行完以后,先不要急着上传服务器,先在本地看一下产物:
验证静态资源:
test -d dist
find dist -maxdepth 2 -type f | head
du -sh dist一般应该能看到 index.html、带 hash 的 JS/CSS 文件和静态资源目录。如果 dist 为空,先看 build 命令实际输出目录;有些框架默认输出 build/,有些输出 .next/,不要把目录名写死到发布脚本里。
如果部署到 Nginx,要重点验证:
index.html是否更新。- JS/CSS hash 文件是否存在。
- base path 是否正确。
- 前端路由刷新是否返回
index.html。 - 浏览器缓存或 CDN 是否仍命中旧资源。
现场常见现象是:构建包已经上传了,页面还是旧的。这时不要只重启 Nginx,先用浏览器 Network 或 curl 看 index.html 的响应时间、缓存头和 JS 文件名有没有变化。很多时候问题不在构建,而在入口缓存或 CDN。
构建缓存怎么用才稳
缓存能提速,也能污染构建。关键是分清哪些能缓存,哪些必须重新生成。
| 工具 | 可缓存 | 谨慎缓存 / 不建议长期缓存 |
|---|---|---|
| Maven | $HOME/.m2/repository | 项目 target/ |
| Gradle | $HOME/.gradle/caches、$HOME/.gradle/wrapper | 项目 build/、项目 .gradle |
| npm | $HOME/.npm | node_modules |
| pnpm | pnpm store | node_modules |
CI 缓存 key 要和这些输入绑定:
操作系统
CPU 架构
JDK / Node 版本
Maven / Gradle / npm / pnpm 版本
pom.xml / build.gradle / package-lock.json / pnpm-lock.yaml
settings.xml / .npmrc 中影响依赖来源的配置遇到构建异常时,清理顺序建议:
# Maven:先清项目输出
mvn clean verify
# Maven:再强制刷新 SNAPSHOT
mvn -U clean verify
# Gradle:先清项目输出
./gradlew clean build
# Gradle:再刷新依赖
./gradlew build --refresh-dependencies
# npm:重新干净安装
rm -rf node_modules
npm ci
# pnpm:重新链接依赖
rm -rf node_modules
pnpm install --frozen-lockfile不要在共享构建机上随便删除整个 Maven 或 Gradle 全局缓存。先定位是某个依赖损坏、SNAPSHOT 过期、lockfile 不一致,还是构建脚本问题。
这里的经验是:先清项目输出,再清依赖缓存;先清当前项目,再动全局目录。全局缓存一删,整台构建机的后续任务都会变慢,而且不一定解决问题。
中国大陆公网、企业内网和离线环境
构建类问题在中国大陆公网和企业内网里会更明显。你在家里能访问 Maven Central,不代表客户机房能访问;你本地能 npm ci,不代表 CI 节点有同样出口。不要把“能联网”当成默认前提。
更稳的依赖闭环是:
开发机 / CI -> 企业私服 -> 受控代理外部仓库 -> 审核后缓存 -> 内网构建复用Maven / Gradle 内网方案
推荐选项:
- Sonatype Nexus Repository。
- JFrog Artifactory。
- 云厂商制品仓库,例如云效 Packages、华为云 CodeArts Artifact。
- 企业自建 Maven 仓库代理。
建议仓库结构:
maven-public group: releases + snapshots + central proxy
maven-releases hosted: 公司正式制品
maven-snapshots hosted: 公司开发快照
gradle-plugins proxy: Gradle Plugin PortalMaven 通过 settings.xml 的 mirrorOf=* 收口。Gradle 通过 pluginManagement 和 dependencyResolutionManagement 收口。不要让项目里到处写公网仓库地址。
一般公司会先建一个 maven-public group 仓库,让开发机和 CI 都只访问这个地址。这样外部仓库不可达时,至少能从私服缓存里继续构建;内部组件发布后,下游也能统一从这个 group 仓库拿。
离线 Maven 包准备:
mvn -s ./ci/settings.xml -DskipTests dependency:go-offline
mvn -s ./ci/settings.xml -DskipTests clean package
tar czf maven-repository-cache.tar.gz ~/.m2/repository
sha256sum maven-repository-cache.tar.gz > maven-repository-cache.tar.gz.sha256离线 Gradle 包准备:
./gradlew --no-daemon clean build
tar czf gradle-cache.tar.gz ~/.gradle/caches ~/.gradle/wrapper
sha256sum gradle-cache.tar.gz > gradle-cache.tar.gz.sha256更推荐在内网搭私服,而不是把个人 .m2 或 .gradle 直接传来传去。个人缓存里可能有过期 SNAPSHOT、临时本地包、错误版本和无来源记录的依赖。
如果确实只能带离线包,至少要带三样东西:依赖缓存、构建脚本、校验文件。到了离线机器上先 sha256sum -c,再构建。不要直接解压就跑,否则包被传坏了也不好定位。
Node / npm / pnpm 内网方案
推荐选项:
- Nexus Repository 或 Artifactory 承接 npm proxy / hosted。
- Verdaccio 承接轻量 npm 私服。
- 云厂商制品仓库。
- 开发机临时使用国内镜像源,但生产构建必须走企业受控仓库。
项目级 .npmrc:
registry=https://npm.example.com/
@company:registry=https://npm.example.com/
always-auth=truenpm 离线缓存不是最稳的交付形态。更稳的是企业 npm 私服加 lockfile。确实离线时,可准备:
npm ci --cache .npm-cache
tar czf npm-cache.tar.gz .npm-cache package.json package-lock.json
sha256sum npm-cache.tar.gz > npm-cache.tar.gz.sha256pnpm 离线更适合带 store:
pnpm install --frozen-lockfile
pnpm fetch
STORE_DIR="$(pnpm store path)"
tar czf pnpm-store.tar.gz "$STORE_DIR" package.json pnpm-lock.yaml
sha256sum pnpm-store.tar.gz > pnpm-store.tar.gz.sha256离线构建包建议包含:
tools/
node-v24.18.0-linux-x64.tar.xz
apache-maven-3.9.16-bin.tar.gz
gradle-9.6.1-bin.zip
cache/
maven-repository-cache.tar.gz
gradle-cache.tar.gz
pnpm-store.tar.gz
source/
source.tar.gz
checksums.txt
build.sh
README.md离线环境要特别注意:
- Node 原生模块和操作系统、CPU 架构、libc 绑定,不能只在 macOS 上装完依赖再拷到 Linux。
- Maven / Gradle 的 SNAPSHOT 要在离线前冻结版本,生产包不要依赖动态快照。
- 所有压缩包要有 sha256 校验。
- 构建脚本要打印工具版本和仓库地址。
- 离线构建失败时,先确认缺哪个依赖,不要现场临时接公网补包。
离线环境的正确节奏是:缺什么,记录下来,回有网环境补齐,再重新打包。现场临时改 registry、临时开公网、临时跳过校验,短期看省事,后面复现和审计都会很麻烦。
制品进入部署链路
构建结束后,真正交给部署系统的是制品,不是开发工作区。
后端 jar / war:
mvn clean package
ls -lh target/*.jar
sha256sum target/*.jarGradle jar:
./gradlew clean build
ls -lh build/libs/*.jar
sha256sum build/libs/*.jar前端静态资源:
npm ci
npm run build
tar czf web-dist-1.0.0.tar.gz dist/
sha256sum web-dist-1.0.0.tar.gz制品交接清单:
应用名称
应用版本
Git commit
构建号
构建时间
构建命令
JDK / Node / Maven / Gradle / npm / pnpm 版本
制品文件名
制品 sha256
目标环境
运行参数或环境变量清单
回滚版本部署系统可以是 Jenkins、GitLab CI、Argo CD、Shell 发布脚本、Docker 镜像构建、Nginx 静态资源发布或 Tomcat 部署。本文不展开这些工具,但构建阶段要给它们提供稳定输入。
不推荐:
把整个项目目录 scp 到服务器
把 node_modules 打进前端部署包
把 target/ 里所有临时文件都上传
发布时现场重新 npm install
生产服务器直接 mvn package推荐:
CI 构建 -> 制品仓库 -> 部署系统按版本拉取 -> 校验 sha256 -> 发布 -> 健康检查 -> 记录版本这里要注意,生产服务器尽量不要承担“编译”职责。生产服务器负责运行制品,构建机负责生成制品。这样出问题时我们能明确区分:是构建产物有问题,还是部署运行环境有问题。
构建失败排障手册
Maven 拉不到依赖
现象:
Could not resolve dependencies
Could not transfer artifact
Non-resolvable parent POM排查:
mvn -v
mvn help:effective-settings
mvn dependency:tree
mvn -U clean package判断:
Unknown host:DNS、代理或仓库地址问题。401:未认证或凭据错误。403:账号无权限。404:坐标、版本、仓库路径或镜像规则错误。checksum failed:仓库文件损坏、代理缓存异常或传输被篡改。
修复后验证:
mvn -s ./ci/settings.xml -U clean verifyMaven SNAPSHOT 不更新
现象:代码已经发布 SNAPSHOT,但下游项目还是旧行为。
排查:
mvn dependency:tree -Dincludes=com.example
mvn -U clean package处理:
- 开发联调可以
-U强制更新 SNAPSHOT。 - 私服检查 SNAPSHOT 是否真的上传成功。
- 生产不要依赖 SNAPSHOT,发布前改成明确版本。
Maven 依赖冲突导致 NoSuchMethodError
排查:
mvn dependency:tree -Dincludes=com.fasterxml.jackson
mvn dependency:tree -Dincludes=io.netty处理:
- 用 BOM 或
dependencyManagement固定版本。 - 排除旧传递依赖。
- 检查运行包里真实包含的 jar。
- 重新打包并在干净环境验证。
Gradle 插件或依赖解析失败
现象:
Plugin was not found
Could not resolve all files for configuration排查:
./gradlew --version
./gradlew build --info --stacktrace
./gradlew dependencies --configuration runtimeClasspath处理:
- 检查
pluginManagement.repositories是否走内网代理。 - 检查
dependencyResolutionManagement是否覆盖了项目仓库。 - 内网预热 Gradle distribution 和插件仓库。
- 需要时
--refresh-dependencies,但不要把它当成常规构建参数。
Gradle Daemon 或缓存异常
现象:
Gradle build daemon disappeared unexpectedly
Timeout waiting to lock artifact cache排查:
./gradlew --stop
./gradlew clean build --no-daemon --stacktrace处理:
- CI 用
--no-daemon。 - 检查构建机内存和磁盘。
- 避免多个构建任务共享同一个不隔离的 Gradle User Home。
- 必要时清理项目
.gradle,最后再处理全局缓存。
npm ci 失败
现象:
npm ci can only install packages when package.json and package-lock.json are in sync排查:
node -v
npm -v
npm config get registry
git diff package.json package-lock.json处理:
npm install
npm ci
git add package.json package-lock.json
git commit -m "同步前端依赖锁定文件"不要在 CI 里用 npm install 掩盖 lockfile 漂移。
npm / pnpm peer dependency 冲突
现象:
ERESOLVE unable to resolve dependency tree
ERR_PNPM_PEER_DEP_ISSUES排查:
npm explain <package>
pnpm why <package>处理:
- 优先升级或降级冲突依赖,让 peer 范围匹配。
- 不要一开始就全局设置
legacy-peer-deps=true。 - 如果必须放宽,写进项目
.npmrc,并说明原因。 - 改完后重新
npm ci或pnpm install --frozen-lockfile验证。
Node 原生模块构建失败
现象:
node-gyp failed
Cannot find module bindings
Unsupported platform排查:
node -p "process.platform + ' ' + process.arch"
node -p "process.versions"
npm config get python处理:
- 确认 Node 版本是否符合项目要求。
- 确认构建环境有 Python、C/C++ 编译工具链。
- Linux 上注意 glibc / musl 差异。
- 不要把其他系统生成的
node_modules直接拷到目标环境。
pnpm lockfile 或 integrity 失败
现象:
ERR_PNPM_OUTDATED_LOCKFILE
ERR_PNPM_TARBALL_INTEGRITY排查:
pnpm install --frozen-lockfile
pnpm store path
pnpm why <package>处理:
- lockfile 过期:在开发环境更新并提交
pnpm-lock.yaml。 - integrity 不一致:先确认 registry 或代理是否改写 tarball。
- 清理或重建 store 前,保留日志和依赖坐标。
- 不要在未确认来源可信前绕过校验。
前端构建成功但页面空白
排查:
find dist -maxdepth 2 -type f | head
grep -R "VITE_API_BASE\\|PUBLIC_URL\\|BASE_URL" dist 2>/dev/null | head浏览器侧看:
- Network 是否 404。
- JS/CSS 路径是否带错 base path。
- API 地址是否指向错误环境。
- CDN / Nginx 是否缓存旧
index.html。 - 前端路由刷新是否被 Nginx 正确回退到
index.html。
处理:
- 修正构建时 base path。
- 区分构建时变量和运行时配置。
- 静态资源使用 hash,
index.html设置较短缓存或禁缓存。 - 发布后用无缓存窗口或 curl 验证资源是否更新。
落地工程深水区
构建链路最容易拖垮交付的地方,是它看起来“只是打包”,但实际连接了代码、依赖、私服、基础镜像、CI、制品仓库和发布系统。
第一是版本基线。JDK、Maven、Gradle Wrapper、Node.js、npm、pnpm 版本都要写入项目约束,不能靠机器默认值。Node 生产构建优先 Active LTS 或 Maintenance LTS;Gradle 项目优先使用 Wrapper,并配置可信 distributionUrl 和 sha256;Maven 项目要固定 settings、mirror、私服策略和插件版本。
第二是依赖来源。中国大陆公网、企业内网、离线环境里,Maven Central、npm registry、Gradle Plugin Portal 都可能不可达。企业要有 Nexus/Artifactory/Verdaccio 或云厂商制品库,CI 只访问受控仓库。离线构建要先在有网环境执行一次依赖预热,再带 lockfile、缓存、store、wrapper distribution 和校验文件进入现场。
第三是可复现性。npm install 可能改 lockfile,npm ci 更适合 CI;pnpm 要用 lockfile 和 frozen install;Maven SNAPSHOT 要限制使用范围;Gradle 动态版本和 changing module 要谨慎。每次构建都要记录 commit id、工具版本、依赖仓库、制品 checksum。
第四是缓存治理。缓存能提速,也能污染构建。Maven 本地仓库、Gradle cache、npm cache、pnpm store 出问题时,不要只会全删。先定位是依赖损坏、代理返回 HTML、证书错误、lockfile 不一致还是原生模块编译失败。CI 缓存要按 JDK/Node/OS/lockfile 维度隔离。
第五是制品边界。部署系统要拿的是明确制品,不是整个工作目录。Jar、war、前端 tar 包、镜像 tag、checksum、构建元数据都要进入制品仓库。生产机器不做临时构建,避免网络、工具版本和临时环境把发布变成不可复现。
第六是团队职责。开发负责声明构建要求,研发效能负责 CI 和缓存,运维负责内网仓库和基础镜像,安全负责依赖漏洞和许可证策略。边界不清时,构建失败会在“代码问题”和“环境问题”之间来回甩锅。
生产最佳实践清单
工具链:
- Maven 使用 3.9.x 稳定版;Maven 4 预览版先做兼容验证。
- Gradle 使用 Wrapper 固定版本,CI 不依赖全局 Gradle。
- Node 使用 LTS,项目记录
.nvmrc、.node-version或engines。 - npm / pnpm 版本要固定,尤其是 pnpm。
依赖:
- Maven 通过私服和
settings.xml收口。 - Gradle 通过
pluginManagement和dependencyResolutionManagement收口。 - npm / pnpm 通过项目
.npmrc和企业 registry 收口。 - CI 使用 lockfile:npm 用
npm ci,pnpm 用--frozen-lockfile。 - 生产制品不依赖 SNAPSHOT、动态版本、
latest或现场下载。
构建:
- 构建命令打印工具版本。
- 构建前清理项目输出目录。
- 发布制品前至少跑一次测试或质量门禁。
- 跳过测试必须可见、可审计。
- 缓存只提速,不参与决定最终结果。
制品:
- Maven 制品取
target/*.jar或target/*.war。 - Gradle 制品取
build/libs/*.jar。 - 前端制品取
dist/或框架约定目录。 - 每份制品记录 Git commit、构建号、工具版本和 sha256。
- 制品上传到私服或制品库,不靠手工拷贝工作区。
内网和离线:
- 国内公网不要依赖随机公共镜像源作为唯一方案。
- 企业内网要有 Maven、npm、Gradle 插件、Node 安装包的闭环。
- 离线包要有依赖清单、校验值、构建脚本和回滚版本。
- 原生依赖按 OS、CPU 架构、libc 分开准备。
- 离线构建失败时按缺失依赖清单补包,不现场临时改仓库。
发布交接:
- 部署系统按版本拉制品。
- 发布前校验 sha256。
- 发布后检查进程、端口、日志、健康接口和静态资源。
- 保留上一版制品和回滚命令。
- 构建失败和发布失败要沉淀为可复用排障项。
常用命令速查
Maven:
mvn -v
mvn help:effective-settings
mvn help:effective-pom
mvn clean verify
mvn clean package -DskipTests
mvn clean package -Dmaven.test.skip=true
mvn -pl order-service -am clean package
mvn dependency:tree
mvn dependency:tree -Dincludes=org.slf4j
mvn -U clean package
mvn -o clean package
mvn clean deployGradle:
./gradlew --version
./gradlew tasks --all
./gradlew clean build
./gradlew bootJar
./gradlew build -x test
./gradlew dependencies --configuration runtimeClasspath
./gradlew dependencyInsight --dependency guava --configuration runtimeClasspath
./gradlew clean build --no-daemon --stacktrace
./gradlew build --refresh-dependencies
./gradlew build --offline
./gradlew wrapper --gradle-version 9.6.1npm:
node -v
npm -v
npm config get registry
npm ping
npm install
npm ci
npm run build
npm ls
npm explain vite
npm cache verifypnpm:
pnpm -v
pnpm install
pnpm install --frozen-lockfile
pnpm fetch
pnpm install --offline
pnpm store path
pnpm store prune
pnpm why vite
pnpm run build制品验证:
ls -lh target/*.jar
ls -lh build/libs/*.jar
find dist -maxdepth 2 -type f | head
sha256sum target/*.jar
sha256sum build/libs/*.jar
tar czf web-dist-1.0.0.tar.gz dist/
sha256sum web-dist-1.0.0.tar.gz官方文档入口
Maven:
- Apache Maven Download: https://maven.apache.org/download.cgi
- Maven Build Lifecycle: https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
- Maven Settings Reference: https://maven.apache.org/settings.html
- Maven Mirrors: https://maven.apache.org/guides/mini/guide-mirror-settings.html
- Maven Dependency Mechanism: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
- Maven Dependency Plugin: https://maven.apache.org/plugins/maven-dependency-plugin/
- Maven Help Plugin: https://maven.apache.org/plugins/maven-help-plugin/
Gradle:
- Gradle Releases: https://gradle.org/releases/
- Gradle Wrapper: https://docs.gradle.org/current/userguide/gradle_wrapper.html
- Gradle Command-Line Interface: https://docs.gradle.org/current/userguide/command_line_interface.html
- Gradle Build Cache: https://docs.gradle.org/current/userguide/build_cache.html
- Gradle Viewing Dependencies: https://docs.gradle.org/current/userguide/viewing_debugging_dependencies.html
Node / npm / pnpm:
- Node.js Download: https://nodejs.org/en/download
- npm ci: https://docs.npmjs.com/cli/v11/commands/npm-ci/
- npm package-lock.json: https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/
- npm scripts: https://docs.npmjs.com/cli/v11/using-npm/scripts/
- npm config: https://docs.npmjs.com/cli/v11/commands/npm-config/
- pnpm install: https://pnpm.io/cli/install
- pnpm production: https://pnpm.io/production
- pnpm store: https://pnpm.io/cli/store
- pnpm npmrc: https://pnpm.io/npmrc
制品仓库和内网方案:
- Sonatype Nexus Repository: https://www.sonatype.com/products/sonatype-nexus-repository
- JFrog Artifactory: https://jfrog.com/artifactory/
- Verdaccio: https://verdaccio.org/
- 阿里云云效 Packages: https://help.aliyun.com/zh/yunxiao/
- 华为云 CodeArts Artifact: https://support.huaweicloud.com/codeartsartifact/
构建这件事最终不是为了“本地能打包”,而是为了让团队在任意受控环境里拿到同一份依赖、同一套命令、同一个制品和同一条回滚路径。能复现、能验证、能排障,才算构建链路真正稳定。
