智汇百科
霓虹主题四 · 更硬核的阅读氛围

编译时依赖和运行时依赖区别

发布时间:2025-12-14 19:29:23 阅读:38 次

编译依赖运行时依赖区别

写代码的时候,经常会遇到“依赖”这个词。比如你用了一个第三方库,项目才能正常跑起来。但这些依赖并不是都一样的,有些只在编译阶段需要,有些则必须在程序运行时也存在。搞不清这两者的区别,很容易在部署服务时报错。

举个生活中的例子:盖房子时,脚手架是施工(编译)阶段必需的工具,房子盖好了就拆掉了;而水电管线则是住人(运行)时必不可少的设施。编译时依赖就像脚手架,运行时依赖则是水电。

什么是编译时依赖

编译时依赖指的是在将源代码转换成可执行文件或字节码的过程中需要用到的库或模块。一旦编译完成,这些依赖就不再需要了。

比如 Java 项目中使用 Lombok,它通过注解在编译期自动生成 getter、setter 方法。编译完成后,生成的 class 文件已经包含这些方法,运行时哪怕没有 Lombok 库也能正常工作。

再比如 TypeScript 编译成 JavaScript,TypeScript 的类型定义只在编译阶段起作用,生成的 JS 文件不带类型信息,运行时完全不需要 ts 相关包。

npm install --save-dev typescript ts-loader

像这样用 --save-dev 安装的包,通常就是编译时依赖,不会被打包进最终发布产物。

什么是运行时依赖

运行时依赖是指程序启动和执行过程中必须存在的库。少了它们,程序根本跑不起来。

比如 Node.js 项目里用了 express,这个库负责处理 HTTP 请求。不管你怎么打包,只要服务在运行,就必须有 express 可用。

npm install express

这种没加 --save-dev 的,默认就是生产依赖,也就是运行时依赖,会出现在 dependencies 字段里。

如果部署时只拷贝了编译后的文件,却漏掉了 node_modules 里的某些运行时库,就会出现类似 Cannot find module 'express' 的错误。

常见问题场景

有个前端项目本地开发一切正常,构建也成功,但上线后页面空白,控制台报错找不到某个模块。查了一圈发现,原来是把 axios 装成了 devDependencies。虽然开发和构建阶段能用,但构建脚本没把它打进最终包里,运行时自然就找不到了。

反过来也有反例:有人把 Webpack 自己加进了 dependencies,导致生产环境安装了一堆根本用不到的构建工具,既浪费空间又增加安全风险。

区分清楚哪些该在编译时引入,哪些必须在运行时存在,能避免很多莫名其妙的问题。

不同语言中的体现

在 Maven 的 pom.xml 中,<scope>provided</scope> 表示这个依赖由运行环境提供,编译时需要,但打包时不包含,典型的就是 Servlet API。

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

而在 Go 语言中,import 的包都会参与编译,但最终是否成为运行时依赖,要看是否真正在执行路径中被调用。Go 的静态链接特性让大多数依赖都被打进了二进制文件,运行时反而不需要额外安装库。

Python 的 virtualenv 或 pipenv 也能通过 requirements.txt 区分开发和生产依赖,只是不像 npm 那样有明确字段划分,容易混淆。

理解这两个概念,不只是为了正确配置依赖列表,更是为了避免线上故障。每次加一个库,不妨多问一句:我到底是在写代码的时候需要它,还是用户用我的程序时也需要它?