1. 这份 Angular CLI 速查表不是“抄完就扔”的纸片,而是你每天打开终端时最该瞄一眼的驾驶舱仪表盘
Angular CLI 是 Angular 开发者每天接触频率最高的工具——它不像 TypeScript 编译器那样藏在构建流程深处,也不像 RxJS 那样只在业务逻辑里露脸。它就坐在你终端窗口最显眼的位置,敲下
ng serve
的瞬间,它就开始调度整个开发环境;执行
ng generate component user-card
的刹那,它已默默创建了 4 个文件、更新了模块声明、注入了样式路径,甚至为你预留好了测试桩。可现实是:90% 的 Angular 开发者只用过其中不到 15 个命令,剩下 80+ 个参数、30+ 个配置项、7 类可扩展钩子,常年处于“知道存在但从未点开文档”的休眠状态。我见过太多团队在 CI 流水线里硬写 shell 脚本去 patch
angular.json
,只因没人意识到
ng config
命令原生支持 JSONPath 更新;也见过工程师花两小时调试
ng build --prod
报错,最后发现只是漏加了
--aot
标志——而这个标志早在 Angular 9 就已默认启用,报错提示里明晃晃写着“
--aot
is required”,却被快速滚动的日志淹没。这份速查表不罗列所有命令的字典式定义,它聚焦于真实工作流中高频、高痛、易错的 23 个核心操作场景,每个条目都标注了 Angular 版本兼容性(从 v12 到 v18)、典型错误响应、底层机制简析,以及我踩坑后总结的“三秒定位法”。它不教你从零搭建项目,而是当你在深夜改完一个组件、想立刻验证效果时,能让你在 5 秒内敲出最精准的命令组合,而不是在 Stack Overflow 里翻找三年前的过期答案。关键词 Angular CLI、Angular、CLI、cheatsheet、reference 不是标签,而是你下次遇到
error: unknown option '--source-map'
或
Cannot find module '@angular-devkit/build-angular'
时,应该本能搜索的救命词。
2.
ng new
:不只是创建项目,而是为未来 6 个月的协作效率埋下第一颗地雷或基石
2.1 为什么
ng new my-app --routing --style=scss
这行命令值得你背下来?
ng new
看似简单,实则是项目生命周期里影响最深远的命令。它生成的不仅是文件,更是一套隐式契约:团队成员对目录结构的预期、CI/CD 脚本对构建入口的依赖、代码审查工具对 ESLint 配置位置的扫描路径。我曾参与一个 12 人团队的遗留项目迁移,原始
ng new
未加
--routing
,导致后期强行引入路由时,开发者手动修改
app.module.ts
并添加
RouterModule.forRoot([])
,却忘了在
app.component.html
中插入
<router-outlet>
——这个疏漏直到 UAT 阶段才暴露,因为本地开发时大家习惯直接访问
/
路径,而测试环境强制走路由守卫。
--routing
参数的价值远超“是否生成
app-routing.module.ts
”:它触发 CLI 在
app.module.ts
中自动导入
AppRoutingModule
,并在
app.component.html
中预置
<router-outlet>
,更重要的是,它让后续所有
ng generate module
命令默认启用
--routing
标志,形成一致性保障。同理,
--style=scss
不仅指定默认样式语言,还决定
angular.json
中
schematics.@schematics/angular:component.style
的初始值,进而影响未来所有
ng g c
生成的组件样式文件后缀。Angular 17+ 引入的
--standalone
标志更是分水岭:它禁用 NgModule 模式,生成的组件、服务、模块全部采用独立模式,这意味着
ng g service
不再向
app.module.ts
注册提供者,而是直接在构造函数中注入
inject(HttpClient)
。若你在 v16 项目中误用
--standalone
,CLI 会直接报错
Standalone components are not supported in this version
,而非静默降级——这是版本兼容性必须前置校验的关键信号。
2.2
--package-manager
参数的隐藏陷阱:npm、yarn、pnpm 的锁文件战争
当团队成员混用包管理器时,
ng new
的
--package-manager
参数就是第一道防线。表面看,
ng new my-app --package-manager=pnpm
只是让 CLI 调用
pnpm install
而非
npm install
,但深层影响在于锁文件生成逻辑与 node_modules 结构。pnpm 使用硬链接+符号链接的存储策略,
node_modules
中的包实际指向全局 store,而 npm 和 yarn v1 则是完整复制。这导致一个致命问题:某些 Angular 插件(如
@angular-builders/custom-webpack
)在解析
node_modules
路径时,会因符号链接跳转失败而报
Cannot find module 'webpack'
。我在 Angular 15 项目中复现过此问题:
ng build
正常,但
ng test
失败,错误堆栈显示
require('webpack')
返回
undefined
。根因是 Karma 配置中的
webpackConfig
路径解析器未正确处理 pnpm 的符号链接层级。解决方案并非放弃 pnpm,而是显式指定
--package-manager=pnpm
并在
angular.json
的
cli.packageManager
字段中锁定值,同时在 CI 脚本中强制执行
pnpm install --no-frozen-lockfile
以规避 lockfile 版本冲突。值得注意的是,Angular 18 已将
pnpm
设为默认包管理器选项之一,但 CLI 不会自动检测系统已安装的 pnpm——你必须显式声明,否则仍会回退到 npm。一个被忽略的细节是:
--package-manager=yarn
在 Angular 17+ 中实际调用的是
yarn berry
(即 v4),而旧项目可能依赖
yarn classic
(v1),此时需额外传入
--skip-install
手动执行
yarn set version classic
。
2.3
--skip-git
和
--commit
的协同逻辑:如何让 Git 提交成为自动化质量门禁
ng new
默认初始化 Git 仓库并提交初始状态,但生产环境往往需要更精细的控制。
--skip-git
看似只是跳过
git init
,实则解耦了代码生成与版本控制两个关注点。例如,在企业私有云环境中,新项目需先推送到内部 GitLab,再由 CI 触发安全扫描,此时
--skip-git
允许你在
ng new
后执行
git remote add origin https://gitlab.internal/my-app
,再
git push -u origin main
。而
--commit
参数则与
--skip-git
形成互补:当你需要自动化脚本批量创建项目时,
ng new my-app --commit --commit-message="chore: init angular project"
可生成带语义化提交信息的初始 commit,避免出现
Initial commit
这类无意义记录。更关键的是,
--commit
会触发
.gitattributes
文件的生成,该文件声明
*.ts linguist-language=TypeScript
,确保 GitHub/GitLab 的代码统计准确。我曾在一个金融客户项目中发现,因未使用
--commit
,
.gitattributes
缺失,导致 SonarQube 将
.spec.ts
文件误判为测试覆盖率数据源,虚高了 12% 的覆盖率报告。Angular CLI 的提交逻辑还内置了 pre-commit hook 注册:当
--commit
启用时,CLI 会检查是否存在
husky
,若存在则自动在
.husky/pre-commit
中注入
ng lint
命令。这解释了为何有些项目
git commit
会卡住——根本原因是
ng lint
配置中启用了
--fix
,而
--fix
在无编辑器上下文时可能引发格式冲突。
3.
ng generate
:代码生成器不是魔法棒,而是你与 Angular 架构约定的具象化契约
3.1 组件生成的四重嵌套:
--flat
、
--inline-style
、
--inline-template
、
--view-encapsulation
的组合爆炸
ng generate component user-card
生成的默认结构(
user-card/
目录含
user-card.component.ts
、
.html
、
.scss
、
.spec.ts
)看似合理,但在微前端或设计系统场景下,这种结构会成为维护噩梦。
--flat
参数强制将所有文件置于同一目录,生成
user-card.component.ts
、
user-card.component.html
等平铺文件。这并非偷懒,而是为 Webpack 的
require.context
动态导入提供便利——当你的组件库需按需加载时,
const req = require.context('./components', true, /\.component\.ts$/)
能直接匹配平铺文件,而嵌套目录需额外正则
\/[^/]+\/[^/]+\.component\.ts$
。
--inline-style
和
--inline-template
则关乎 bundle 体积与可维护性权衡:内联模板将 HTML 内容作为字符串注入组件类,消除单独
.html
文件,但牺牲了 IDE 的 HTML 语法高亮与 Emmet 支持;内联样式同理,
.scss
变成字符串,无法利用 Sass 的
@import
和变量共享。Angular 17+ 新增的
--view-encapsulation
参数直击核心:
--view-encapsulation=Emulated
(默认)通过属性选择器模拟 Shadow DOM,
--view-encapsulation=None
完全关闭封装,
--view-encapsulation=ShadowDom
启用原生 Shadow DOM。选择
None
时,
ng g c button --view-encapsulation=None
生成的组件 CSS 将全局生效,这在构建 Design System 的原子组件时是刚需,但必须配合
:host
伪类约束作用域,否则污染全局样式。一个血泪教训:某电商项目为加速首屏,将所有按钮组件设为
None
封装,却忘记在
button.component.scss
中添加
:host { display: inline-flex; }
,导致按钮在不同父容器中渲染错位,排查耗时 3 人日。
3.2 服务生成的提供者迷宫:
--project
、
--module
、
--skip-import
如何决定依赖注入的生死线
ng generate service api/user
默认在
src/app/api/user.service.ts
创建服务,并在
app.module.ts
的
providers
数组中注册。但这只是最简路径。
--project=admin
将服务生成到
projects/admin/src/app/api/user.service.ts
,并尝试在
projects/admin/src/app/app.module.ts
中注册——前提是该子项目存在
app.module.ts
。若
admin
是独立构建的微应用,其入口模块可能是
AdminModule
,此时 CLI 会报错
Could not find module file for project "admin"
。解决方案是
ng g s api/user --project=admin --module=admin.module
,CLI 将在
projects/admin/src/app/admin.module.ts
的
providers
中注入。更危险的是
--skip-import
:它阻止自动注册,要求开发者手动
import { UserService } from './api/user.service';
并在
providers
中声明。这看似增加工作量,实则是避免循环依赖的利器。例如,
UserService
依赖
AuthService
,而
AuthService
又需调用
UserService
的用户信息接口,此时若两者均自动注册,Angular 的 DI 系统会在构建时抛出
Error: Cannot instantiate cyclic dependency!
。
--skip-import
强制你采用
providedIn: 'root'
的 providedIn 方式,将服务注册提升至根注入器,打破模块级循环。Angular 18 的
--provided-in
参数进一步简化此流程:
ng g s api/user --provided-in=root
直接生成
@Injectable({ providedIn: 'root' })
,无需手动修改。
3.3 模块生成的架构分层术:
--route
、
--routing-scope
、
--lazy
如何塑造应用的加载边界
模块生成是 Angular 架构设计的分水岭。
ng generate module dashboard
创建空模块,而
ng g m dashboard --route=dashboard --module=app-routing
则在
app-routing.module.ts
中添加
{ path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule) }
。这里
--route
指定路由路径,
--module
指定父路由模块,二者缺一不可。
--routing-scope=child
(Angular 17+)则生成子路由模块:
ng g m dashboard --routing-scope=child
会创建
dashboard-routing.module.ts
,其中包含
const routes: Routes = [{ path: '', component: DashboardComponent }]
,并在
dashboard.module.ts
中导入
DashboardRoutingModule
。这种模式强制路由配置与模块解耦,便于单元测试。
--lazy
参数更激进:
ng g m dashboard --lazy
不生成任何路由配置,仅创建模块文件,要求开发者手动编写
loadChildren
函数。这看似繁琐,实则赋予完全控制权——你可以在此函数中加入权限校验:
loadChildren: () => hasPermission('DASHBOARD') ? import('./dashboard/dashboard.module').then(m => m.DashboardModule) : Promise.reject(new Error('No permission'))
。Angular CLI 的路由生成逻辑还隐含一个关键规则:当
--route
路径包含斜杠(如
--route=admin/dashboard
),CLI 会自动创建嵌套目录
admin/dashboard/
,并在
admin-routing.module.ts
中配置子路由。这解释了为何
ng g m admin --route=admin
生成
admin/
目录,而
ng g m admin --route=admin/users
会报错
Path "admin/users" contains multiple segments, use --routing-scope=child instead
——CLI 强制你通过子路由模块来管理多级路径,避免路由配置碎片化。
4.
ng build
与
ng serve
:构建命令不是黑盒,而是你掌控产物体积、启动速度、热更新稳定性的控制台
4.1
--configuration
的真相:它不只是切换环境变量,而是触发整个构建流水线的齿轮组
ng build --configuration=production
表面是加载
environment.prod.ts
,实则激活
angular.json
中
configurations.production
下的全套参数组合。这些参数构成一个精密齿轮组:
optimization: true
启用 Terser 压缩,
outputHashing: 'all'
为所有输出文件添加内容哈希,
sourceMap: false
禁用源码映射,
namedChunks: false
关闭命名 chunk,
aot: true
强制 AOT 编译。但最关键的齿轮是
buildOptimizer: true
(Angular 12+ 默认启用),它执行深度优化:移除未使用的 RxJS 操作符、折叠常量表达式、内联简单函数。当
buildOptimizer
与
aot
协同工作时,会触发 Ivy 编译器的
ngtsc
阶段,将模板编译为高效 JS 代码。一个经典陷阱是:
ng build --configuration=staging
若未在
angular.json
中明确定义
staging
配置,CLI 会静默回退到
development
配置,导致构建产物未压缩、源码映射开启,体积暴增 300%。解决方案是
ng build --configuration=staging --base-href=/staging/
,但更健壮的做法是在
angular.json
中声明:
"staging": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": true,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
其中
budgets
是隐形守护者:当初始包超过 2MB 时,构建仅警告;超过 5MB 则直接失败。这迫使团队在
ng build
阶段就直面性能债务,而非等到上线后被监控告警轰炸。
4.2
ng serve
的热更新机制:
--live-reload
、
--hmr
、
--poll
如何影响你的开发节奏
ng serve
的默认行为是启用 LiveReload:文件变更时,浏览器自动刷新。但
--hmr
(Hot Module Replacement)是质变——它只替换变更的模块,保留应用状态。例如,修改
user-card.component.ts
的模板,HMR 仅更新该组件的视图,而
user-list.component.ts
的滚动位置、表单输入值均保持不变。启用 HMR 需两步:
ng serve --hmr
启动,且在
main.ts
中添加:
if (module['hot']) {
module['hot'].accept();
module['hot'].dispose(() => {
// 清理资源
});
}
--poll=1000
参数则解决 NFS 或 Docker 挂载卷的文件监听失效问题。Linux 系统的 inotify 机制在容器内常受限,
--poll
强制 CLI 每秒轮询文件修改时间戳。但轮询有代价:
--poll=100
(每 100ms)会使 CPU 占用飙升至 80%,而
--poll=2000
(每 2s)则可能导致热更新延迟。最佳实践是
--poll=500
,平衡响应性与资源消耗。另一个隐藏开关是
--disable-host-check
:当通过
localhost:4200
访问正常,但通过
192.168.1.100:4200
访问报
Invalid Host header
时,此参数解除主机头校验。但这不是安全漏洞,而是 Webpack Dev Server 的默认防护——生产环境绝不可启用。
4.3
--source-map
的三重人格:
scripts
、
styles
、
vendor
如何决定调试体验的颗粒度
--source-map
参数接受布尔值或对象,其细粒度控制直接影响调试效率。
--source-map=true
为所有资源生成源码映射,但
--source-map='{"scripts":true,"styles":false,"vendor":true}'
则精准调控。
scripts: true
使 TS 代码可断点调试,
styles: false
禁用 CSS 源码映射(因 SCSS 错误通常在编译时报出,运行时 CSS 调试价值低),
vendor: true
为第三方库(如
rxjs
、
lodash
)生成映射,便于追踪
Observable.pipe()
内部错误。Angular CLI 的源码映射生成逻辑还依赖
sourceRoot
配置:若
angular.json
中
sourceRoot
设为
src
,则映射文件中的
sources
字段为
["./app/app.component.ts"]
;若设为
src/app
,则变为
["./app.component.ts"]
。这影响 Chrome DevTools 的断点定位——当
sources
路径与实际文件路径不匹配时,断点会显示为灰色“未绑定”。一个修复技巧是:在
angular.json
的
build.options
中添加
"sourceRoot": "src"
,并确保所有
import
路径以
src/
开头,如
import { UserService } from 'src/app/api/user.service';
。
5.
ng test
与
ng e2e
:测试命令不是仪式,而是你交付质量的最终仲裁者与用户体验的守门员
5.1 Karma 配置的隐形战场:
--browsers
、
--code-coverage
、
--watch
如何左右测试执行的可靠性
ng test
默认启动 Chrome 浏览器执行单元测试,但
--browsers=ChromeHeadless
启用无头模式,这对 CI 环境至关重要。
--code-coverage
不仅生成
coverage/
报告,更在
karma.conf.js
中注入
coverageIstanbulReporter
,其
reports
配置决定报告格式:
['html', 'lcovonly', 'text-summary']
生成 HTML 页面、LCOV 文件、文本摘要。
--watch
参数开启文件监听,但其底层依赖
karma-webpack
的
watchOptions
,当项目包含大量
.d.ts
声明文件时,
--watch
可能因文件系统事件队列溢出而卡死。解决方案是
ng test --watch --browsers=ChromeHeadless --code-coverage --watch-options='{"usePolling":true,"interval":1000}'
,强制轮询并延长间隔。一个被忽视的细节是
--code-coverage-exclude
:
ng test --code-coverage-exclude="src/environments/**/*"
排除环境文件,避免因
environment.prod.ts
中的 API 地址硬编码导致覆盖率计算偏差。
5.2
ng e2e
的 Playwright 时代:
--browser
、
--headless
、
--dev-server-target
如何重构端到端测试范式
Angular 17+ 将默认端到端测试框架从 Protractor 切换为 Playwright,
ng e2e
命令随之进化。
--browser=chromium
指定浏览器,
--headless
启用无头模式,
--dev-server-target=my-app:serve:production
指向构建后的生产服务器而非开发服务器。Playwright 的核心优势在于跨浏览器一致性:
--browser=webkit
可在 macOS 上测试 Safari 行为,
--browser=firefox
覆盖 Firefox 用户。
--dev-server-target
参数尤为关键——当
ng e2e
与
ng serve
并行时,Playwright 会等待开发服务器启动完成再执行测试;而
--dev-server-target
指向生产构建,则绕过开发服务器,直接测试
dist/
目录,更贴近真实用户环境。Playwright 的
test.config.ts
还支持
webServer
配置:
webServer: { command: 'npx http-server dist/my-app', port: 4200 }
,这比
ng serve
更轻量,避免 Angular Dev Server 的热更新开销。
5.3
--include
与
--exclude
的精准打击:如何让测试命令只运行你关心的那 0.1% 用例
ng test --include="src/app/core/**/*spec.ts"
仅运行
core
目录下的测试,
--exclude="src/app/shared/**/*spec.ts"
排除
shared
目录。这并非简单文件过滤,而是 Karma 的
files
数组动态重写。当
--include
指定路径时,Karma 会清空默认
files
数组,仅加载匹配文件,从而跳过
node_modules
中的测试依赖。
--exclude
则在默认数组基础上移除匹配项。一个高效工作流是:
ng test --include="src/app/features/user/**/*spec.ts" --code-coverage
,专注用户功能模块,生成精简覆盖率报告。对于大型项目,还可结合
--grep
参数:
ng test --grep="should create"
仅运行
describe
或
it
名称包含
should create
的测试,实现用例级精准执行。
6.
ng update
与
ng add
:升级与集成命令不是一键奇迹,而是你驾驭 Angular 生态演进的导航仪
6.1
ng update
的依赖图谱解析:
--dry-run
、
--force
、
--migrate-only
如何规避升级灾难
ng update @angular/core @angular/cli
是升级主干,但
--dry-run
是安全阀:它模拟升级过程,列出所有将被修改的文件、将被安装的包、将被删除的弃用 API。
--force
强制忽略 peer 依赖冲突,但这是双刃剑——
ng update @angular/material --force
可能安装与当前 Angular 版本不兼容的 Material 版本,导致
MatButtonModule
报
Cannot find module '@angular/cdk/bidi'
。
--migrate-only
仅执行代码迁移(如将
HttpModule
替换为
HttpClientModule
),不更新包版本,适用于需分阶段升级的遗留系统。Angular CLI 的升级逻辑基于
ng-update
包,每个包在
package.json
的
ng-update
字段中声明迁移器。例如,
@angular/router
的迁移器会扫描
RouterModule.forRoot([])
调用,将其升级为
provideRouter([])
。当
ng update
报错
Migration failed
时,应检查
node_modules/@angular/cli/node_modules/@angular-devkit/schematics
中的迁移日志,而非盲目
--force
。
6.2
ng add
的生态集成术:
--project
、
--skip-confirmation
、
--verbose
如何让第三方库无缝融入你的架构
ng add @angular/material
不仅安装包,更执行 schematics:生成
theme.scss
、在
styles.css
中导入、在
app.module.ts
中添加
MatButtonModule
。
--project=admin
将操作限定在
admin
子项目,
--skip-confirmation
跳过交互式确认,适用于 CI 脚本。
--verbose
输出详细日志,揭示 schematics 的每一步操作。一个典型场景是
ng add @ngneat/tailwind
:它不仅安装 Tailwind,还在
angular.json
中配置
tailwind.config.js
的路径,并修改
styles.scss
的
@tailwind
指令。若
--verbose
日志显示
Executing migration for @ngneat/tailwind
后卡住,通常是
tailwind.config.js
中的
content
路径未包含
src/**/*.html
,导致 Tailwind 无法提取类名。解决方案是手动编辑
tailwind.config.js
,添加
content: ['./src/**/*.{html,ts}']
。
6.3
ng version
与
ng list
:版本诊断的黄金组合,如何一眼识别项目健康度
ng version
显示全局和本地 Angular CLI 版本,但
ng list @angular/core
才揭示真相:它列出
@angular/core
的精确版本及依赖树。
ng list --deep
显示所有依赖的嵌套关系,
ng list --outdated
标识过时包。当
ng build
报
ERROR in node_modules/@angular/common/http/http.d.ts(11,22): error TS2307: Cannot find module 'rxjs'
时,
ng list rxjs
会显示
rxjs@6.6.7
(过时)与
rxjs@7.8.1
(期望),根因是
@angular/common
依赖
rxjs@^7.0.0
,而项目中存在
rxjs@6.6.7
的直接依赖。
ng list --graph
生成依赖图谱(需 Graphviz),可视化展示
@angular/platform-browser
如何通过
@angular/core
间接依赖
rxjs
,帮助定位版本冲突源头。
7. 高级技巧:那些藏在
angular.json
和
tsconfig.json
深处的 CLI 控制杠杆
7.1
angular.json
的
schematics
字段:如何定制
ng generate
的默认行为,让它真正懂你的团队规范
angular.json
的
schematics
字段是 CLI 的“DNA”。
"@schematics/angular:component"
下的
style
属性决定
ng g c
默认生成
.scss
还是
.css
;
changeDetection
属性设置
ChangeDetectionStrategy.OnPush
为默认策略。
"@schematics/angular:module"
的
routing
属性控制
ng g m
是否默认启用路由。一个高级技巧是覆盖
@schematics/angular:service
的
providedIn
:
"schematics": {
"@schematics/angular:service": {
"providedIn": "root"
}
}
此后
ng g s api/user
直接生成
@Injectable({ providedIn: 'root' })
,无需手动修改。
schematics
还支持自定义集合:
"my-schematics:component"
可指向团队内部的 schematics 包,实现
ng g c user-card --prefix=ui
自动生成
UiUserCardComponent
,强制组件名遵循设计系统命名规范。
7.2
tsconfig.json
的
angularCompilerOptions
:如何用
strictInjectionParameters
和
compilationMode
拔高代码质量水位线
tsconfig.json
的
angularCompilerOptions
是 Ivy 编译器的控制台。
"strictInjectionParameters": true
要求所有
@Injectable
类的构造函数参数必须有类型注解或
@Inject
装饰器,杜绝
constructor(private http: any)
这类反模式。
"compilationMode": "partial"
(Angular 15+)启用部分编译模式,生成
.d.ts
文件时保留装饰器元数据,使第三方工具(如 Storybook)能正确解析组件输入输出。
"enableIvy": true
在 Angular 12+ 已默认启用,但显式声明可避免旧版 CLI 的兼容性歧义。一个关键配置是
"skipTemplateCodegen": true
:它禁用模板代码生成,仅进行类型检查,大幅提升
ng build --watch
的增量编译速度,适用于大型项目。
7.3
ng config
:用命令行直接编辑配置,告别手抖改错
angular.json
的恐惧
ng config projects.my-app.architect.build.configurations.production.optimization true
直接将
optimization
设为
true
,无需打开
angular.json
。
ng config --global cli.packageManager pnpm
全局设置包管理器。
ng config schematics.@schematics/angular:component.inlineStyle true
将组件样式默认设为内联。
ng config
的 JSONPath 支持让配置修改原子化:
ng config projects.my-app.architect.test.options.codeCoverageExclude '["src/environments/**/*"]'
精准更新排除列表。当
ng config
报错
Property 'xxx' does not exist
时,说明路径错误,可用
ng config --help
查看完整路径语法。一个实用技巧是
ng config --get projects.my-app.architect.build.options.outputPath
获取当前输出路径,用于 CI 脚本中动态构建。
8. 故障排除实战:从
error response from daemon
到
unresolved reference
,一份基于真实日志的排错地图
8.1
error response from daemon: unknown: failed to resolve reference "docker.io/...
:这不是 Angular CLI 的错,而是 Docker 镜像拉取的网络迷雾
该错误频繁出现在
ng build
后的 Docker 构建阶段,与 Angular CLI 无关,但常被误判。
docker build
命令在
FROM node:18-alpine
阶段失败,根因是 Docker Daemon 无法解析
docker.io/library/node
的镜像引用。解决方案分三层:
网络层
,执行
docker login
确保认证有效;
DNS 层
,在
/etc/docker/daemon.json
中添加
"dns": ["8.8.8.8", "114.114.114.114"]
;
镜像源层
,添加国内镜像加速器:
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://registry.docker-cn.com"
]
}
重启 Docker:
sudo systemctl restart docker
。若仍失败,临时使用
docker pull node:18-alpine
预拉取镜像,再执行
docker build
。
8.2
unresolved reference 'implementation'
:TypeScript 配置与 Angular 版本的隐式契约破裂
此错误源于
tsconfig.json
的
compilerOptions.types
包含
'jest'
,但
@types/jest
版本与 Angular CLI 的 Jest 版本不兼容。Angular 17+ 使用 Jest 29,而
@types/jest@28
的
implementation
类型定义缺失。解决方案:
npm uninstall @types/jest && npm install @types/jest@29
。更彻底的方法是
ng add @angular/jest
,它自动安装匹配版本并配置
tsconfig.spec.json
。
8.3
undefined reference to 'yaml'
:C++ 扩展编译失败,Node.js 与原生模块的 ABI 鸿沟
当
ng build
报此错,通常是
node-sass
或
fsevents
等原生模块与当前 Node.js 版本 ABI 不匹配。
node-sass
已废弃,应迁移到
sass
(纯 Dart 实现)。
fsevents
是 macOS 专属,CI 环境无需安装:
npm uninstall fsevents --save-dev
。通用修复流程:
npm rebuild node-sass --force
强制重编译,或
npm install --update-binary
更新二进制包。
8.4
error: unknown option '--source-map'
:CLI 版本降级的无声警告
此错表明本地全局
@angular/cli
版本低于项目
devDependencies
中的版本。
ng version
显示全局
v15.2.0
,而
package.json
中
"@angular/cli": "^17.0.0"
。解决方案:
npm install -g @angular/cli@17
升级全局 CLI,或
npx ng build
强制使用本地 CLI。
npx
是终极保险——它始终调用
node_modules/.bin/ng
,确保版本一致。

356

被折叠的 条评论
为什么被折叠?



