package.json 中的 dependencies 是否都会被下载?|Angular 回归笔记 02

package.json 中的 dependencies ,不会因为被列在依赖清单中,就全部被用户的浏览器下载。

浏览器最终下载什么,主要取决于两个方面:

  1. 构建阶段: build 过程中生成了哪些资源,包括打包了哪些代码、复制了哪些静态文件。
  2. 访问阶段: 页面如何引用这些资源,以及应用运行时何时加载它们。

这里说的"下载"是指用户浏览器下载网站资源 ,需要与开发时执行 npm install 下载依赖包区分开。

本文以未启用 SSR 的 Angular 应用及其生产构建为例。

1. dependencies 和 devDependencies 管什么?

它们描述依赖的用途,并影响安装和分发时如何处理这些包。

分类 Angular 项目中的示例 用途
dependencies @angular/core、@angular/router 提供应用功能
devDependencies @angular/cli、typescript、vitest 创建、编译和测试应用

普通开发环境下执行:

复制代码
npm install

通常会安装两类依赖。执行下面的命令,则不安装开发依赖:

ini 复制代码
npm install --omit=dev

发布 npm 库时,分类也有作用:别人安装你的库,npm 会处理它声明的运行依赖,但不会连带安装这个库自己的开发依赖。

因此,依赖分类有实际意义,但它不是控制浏览器下载内容的开关。

2. 构建阶段:哪些资源进入产物?

Angular 构建工具会从 main.ts 等配置入口出发,沿着代码引用关系分析依赖:

css 复制代码
main.ts
  └── 根组件
        └── 学习卡片组件
              └── 工具库

如果一个日期库虽然写在 dependencies 中,却没有被应用直接或间接引用,也没有通过构建配置额外引入,它通常不会进入浏览器构建产物。

反过来,应用引用了某个放在 devDependencies 中的包,只要它已经安装且适用于浏览器构建,其中的代码仍可能被打包。

这并不意味着分类可以随意填写:分类影响包是否被安装,构建工具则根据入口、引用关系和配置处理已经可用的代码。

引用了一个包,也不一定保留整个包

假设一个工具模块提供两个函数:

javascript 复制代码
export function double(value: number) {
  return value * 2;
}

export function triple(value: number) {
  return value * 3;
}

应用只使用:

sql 复制代码
import { double } from './math';

console.log(double(5));

生产构建时,工具可以移除未被使用的 triple。这类优化叫 Tree Shaking(摇树优化) 。

不过,实际效果取决于代码写法和模块格式。如果代码有副作用,或者工具无法证明删除是安全的,就可能保留。引用一个函数,不保证只打包这一个函数。

保留下来的代码还会经过编译、压缩和拆分等处理。图片等静态资源则可能按配置直接复制到输出目录,并不需要被 JavaScript 引用。

构建产物可能类似:

css 复制代码
index.html
main-ABC123.js
chunk-DEF456.js
styles-GHI789.css
logo.png

这些文件名仅作示意。一个 JavaScript 文件可能混合了业务代码和多个依赖库的代码,已经不是 npm 包原来的结构。

3. 访问阶段:浏览器如何加载资源?

构建生成了文件,不代表浏览器会立即下载全部文件。

浏览器首先根据 HTML 中的引用加载资源,例如:

ini 复制代码
<link rel="stylesheet" href="styles-GHI789.css">
<script src="main-ABC123.js" type="module"></script>

应用运行后,还可能继续请求其他资源:

资源 可能的加载时机
入口 JavaScript、全局样式 浏览器解析 HTML 时
懒加载页面的代码 访问对应页面时,或被预加载时
图片 对应元素出现并满足加载条件时
未被任何页面或代码引用的静态文件 即使部署在服务器上,也不一定被请求

所以, "进入构建产物"和"被浏览器下载"是两回事。

浏览器不会根据 package.json 去安装 npm 包。它根据页面引用和应用运行时的加载行为,请求实际需要的资源。

4. 为什么生产构建还需要 devDependencies?

因为生成生产文件,也需要开发工具。

Angular CLI、构建工具和 TypeScript 编译器虽然属于 devDependencies,但它们参与构建过程。用户访问构建好的网站时,才不再需要运行这些工具。

整个过程可以串成:

markdown 复制代码
npm 根据依赖声明安装包
    ↓
构建工具分析代码和配置,生成资源
    ↓
将构建产物部署到服务器
    ↓
浏览器根据页面引用和运行时逻辑加载资源

判断一个依赖是否会被用户下载,需要沿着后两个环节看:它的哪些代码进入了构建产物?包含这些代码的文件,又会在什么情况下被浏览器加载?

参考资料:

相关推荐
starrysky8101 小时前
同一个 submit(),两条报错——ThreadPoolExecutor 在解释器退出时的竞态(附 4 组可复现实验)
angular.js
starrysky8101 小时前
30 个 CPU 全在内核态,只回收了 32 个页——per-memcg 内存回收的 mmap_lock 活锁
angular.js
starrysky81014 天前
一个 NameError 掩盖了真根因:IPython 补全在 Django shell 里二次崩溃——从 jedi 版本错位查到 CPython LOAD_GLOBAL
angular.js
starrysky81014 天前
SQL 注入 + msgpack 反序列化 = RCE:LangGraph Checkpointer 三洞连爆——Agent 的记忆层就是攻击面
angular.js
starrysky81014 天前
NVD 9.8、官方 7.5:Redis TLS use-after-free 的评分之争——tlsProcessPendingData 悬指针踩空全解析
angular.js
巴勒个啦20 天前
2026 年 CSS 选型真相:我用 Tailwind v4 + 原生新特性重构了一个组件库
前端·angular.js
starrysky81022 天前
服务全绿、队列却 15 天没人消费?redis-py 8.0 默认切 RESP3 的阻塞命令坑
angular.js
starrysky81022 天前
写个管道就被 BrokenPipeError 打爆?先看 CPython 把 SIGPIPE 藏哪了
angular.js
starrysky8101 个月前
画像空不是故障:Honcho peer card 观察者视角源码拆解——1956 条结论为何换不来一张卡
angular.js