angular.json 是 Angular 工作区的说明书:CLI 的每条命令(serve、build、test)都先读它再干活。读懂这份文件,就能精确回答”开发与生产差在哪""包体积红线在哪""静态资源从哪来”这类工程问题。本文自顶向下拆解它,并说明 v22 的精简趋势。
它在配置体系中的位置
| 文件 | 管什么 |
|---|---|
| angular.json | 工作区、项目、构建目标、预算、资源 |
| tsconfig.json | TypeScript 编译选项(strict 系列、paths) |
| package.json | 依赖与 npm scripts |
| proxy.conf.json | dev server 代理 |
分工清晰:与”构建什么、怎么构建”相关的进 angular.json,与”语言层”相关的进 tsconfig。
顶层结构
一份典型的 v22 工作区配置:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"analytics": false,
"schematicCollections": ["@angular/cli"]
},
"projects": {
"my-app": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"targets": { "...": "见下文" }
}
}
}
$schema:让编辑器获得字段补全与校验,别删。newProjectRoot:后续ng generate application/library的默认落点。cli:CLI 自身行为(分析统计、默认蓝图参数)。projects:工作区内的项目集合,应用与类库都算项目。
projects 与 targets
每个 project 节点描述四件事:
| 字段 | 含义 |
|---|---|
| projectType | application 或 library |
| root / sourceRoot | 项目根与源码根 |
| prefix | 生成组件/指令时的选择器前缀 |
| targets | 构建目标集合 |
targets 在旧文档里叫 architect,两者是同一概念的新旧名称,v22 统一用 targets。每个 target 由三部分组成:
"build": {
"builder": "@angular/build:application",
"options": { "基础选项": "所有配置共享" },
"configurations": {
"production": { "生产覆盖": "" },
"development": { "开发覆盖": "" }
},
"defaultConfiguration": "production"
}
builder:真正干活的构建器。v22 默认@angular/build:application(esbuild 系),dev server 对应@angular/build:dev-server。options:基线选项。configurations:按环境覆盖(不是替换,是同名键覆盖合并)。defaultConfiguration:ng build不带参数时使用的配置。
三层合并语义可以用一张图表示:
flowchart LR
A["options<br/>基线"] --> C["最终生效配置"]
B["configurations:production<br/>覆盖项"] --> C
D["命令行参数<br/>--define / 覆盖"] --> C
build target 常用选项
"build": {
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/my-app",
"index": "src/index.html",
"browser": "src/main.ts",
"tsConfig": "tsconfig.app.json",
"assets": [{ "glob": "**/*", "input": "public" }],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
}
几个字段值得展开:
browser:浏览器端入口,对应旧版main字段;SSR 场景还有server入口。outputHashing:生产默认all,文件名带内容哈希,配合 CDN 长缓存。scripts:不参与打包的第三方脚本(直接 script 标签引入的老库),能用 npm 包就别用它。
configurations:生产与开发覆盖
新增自定义环境只需要加一个键。比如加一个 staging:
"configurations": {
"production": { "...": "" },
"staging": {
"budgets": [{ "type": "initial", "maximumError": "2MB" }],
"outputHashing": "all",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
]
},
"development": { "...": "" }
}
使用:ng build --configuration staging。注意新版 CLI 默认不再生成 src/environments 目录——当构建期就存在差异时,用 fileReplacements 自建环境文件仍然是最直接的方案:
// src/environments/environment.ts(开发时被加载)
export const environment = { apiUrl: 'http://localhost:8080/api' };
// src/environments/environment.staging.ts
export const environment = { apiUrl: 'https://staging.example.com/api' };
serve target 同理可以有配置,ng serve --configuration development 就是这么来的:
"serve": {
"builder": "@angular/build:dev-server",
"options": {},
"configurations": {
"production": { "buildTarget": "my-app:build:production" },
"development": { "buildTarget": "my-app:build:development" }
},
"defaultConfiguration": "development"
}
budgets:体积预算
budgets 是构建期的”体重秤”,超线即失败,把治理前移到 CI:
| type | 衡量对象 |
|---|---|
| initial | 初始加载的 JS/CSS 总量 |
| anyComponentStyle | 单个组件样式文件 |
| allScript / anyScript | 所有脚本 / 单个脚本 |
| bundle / all | 单个 bundle / 一切产物 |
每档阈值分 maximumWarning(警告)与 maximumError(失败),也支持 minimumWarning 防止产物”意外变小”(常用于发现误删依赖)。典型报错:
Error: initial exceeded maximum budget. Budget 1MB was exceeded by 240kB.
默认值对多数应用够用;组件样式预算(默认较紧)是新手最常撞的红线——要么拆样式,要么按需放宽。
assets 与 styles 的数组语义
两者的数组元素都支持”字符串简写”与”对象全量”两种形态:
"assets": [
"public",
{
"glob": "**/*",
"input": "src/assets-shared/",
"output": "/assets/"
}
],
"styles": [
"src/styles.css",
"node_modules/@angular/material/prebuilt-themes/azure-blue.css",
{
"input": "src/styles/print.css",
"inject": false,
"bundleName": "print"
}
]
- assets 字符串形态等价于
{ glob: "**/*", input: <字符串>, output: "/" }。 - 对象形态用于”从任意目录拷贝到产物任意路径”,类库场景常见。
- styles 的对象形态中,
inject: false+bundleName会生成独立样式文件而不自动注入 index.html——打印样式、主题切换就是这么做的。
v22:单 project 的扁平化趋势
近几个版本 angular.json 有一个明确方向:单应用工作区的配置越来越短。原因有二:一是默认值越来越多(优化、chunk 策略、哈希都不必显式写),二是新构建器把许多过去必须配置的事项(如 index 输出细节)内化。v22 新建的单项目工作区,options 里常见字段的缺省已足够,文件主要剩下”骨架 + 预算 + 覆盖”。
示意(省略号代表大量可缺省项):
{
"version": 1,
"projects": {
"my-app": {
"projectType": "application",
"targets": {
"build": {
"builder": "@angular/build:application",
"configurations": {
"production": { "budgets": ["..."] }
}
},
"serve": { "builder": "@angular/build:dev-server" }
}
}
}
}
多项目(monorepo 中一应用多类库)仍保持完整嵌套结构,projects 映射不受影响。原则很简单:能在代码或默认值里解决的,别堆进配置文件;angular.json 只留”因环境而异”的部分。
实战:给项目加 staging 环境
把前文内容串成一个可操作清单:
- 创建
src/environments/environment.staging.ts,导出与开发版同构的常量。 - 在
angular.json的 build target 增加stagingconfiguration:outputHashing、放宽的 budgets、fileReplacements。 - 在 package.json 加脚本:
"build:staging": "ng build --configuration staging"。 - CI 流水线按环境调用对应脚本;本地验证:
ng build --configuration staging后检查产物与环境文件替换是否生效。
小结
- angular.json 管”构建什么、怎么构建”:projects → targets → options/configurations 三层。
- configurations 是覆盖合并而非替换,自定义环境只需新增一个键。
- budgets 默认拦截体积失控,
anyComponentStyle是最常撞的红线。 - assets/styles 支持字符串与对象两种形态,对象形态负责跨目录拷贝与独立 bundle。
fileReplacements承担构建期环境差异;v22 单项目配置持续精简,默认值能省则省。