Introduction
Angular的CLI(Command Line Interface)系统非常强大,它提供了丰富的命令用来构建,测试,运行Angular程序,今天我们就从源码的角度来看看cli中的ng serve命令是如何工作的。
ng serve是我们日常频繁使用的命令,它用来本地启动Angular项目,检测代码更新以做出响应,但是用了这么久的命令,你了解它的底层逻辑吗?下面的几个问题你是否思考过?
ng serve命令为什么没有输出文件到dist目录?ng serve命令是如何启动一个web server的?ng serve命令是如何监控文件变化的?ng serve命令是如何实现热更新的?
下面就让我们开始这段愉快而又漫长的探索之旅吧!
准备工作
为了调试ng serve命令,我们需要准备一个Angular项目,为了方便查看源码,我们将angluar-cli的源码也下载到本地,然后打开两个IDE,一个查看待调试的项目代码,一个查看angular-cli的源码。对照起来看,简直不要太爽!
从命令行开始
如果你直接查看ng serve命令的源码,可能得不到什么有用的信息,serve命令对应的源码在这里:packages/angular/cli/src/commands/serve/cli.ts, 从以下代码可知,serve命令是继承自ArchitectCommandModule的,同时也实现了CommandModuleImplementation接口。而该文件本身只是做了一个简单的配置,具体的实现逻辑都在ArchitectCommandModule和CommandModuleImplementation中。
1 | export default class ServeCommandModule |
还是调试吧,我们打开Angular项目,然后打开项目根目录下的package.json文件,找到scripts字段,你会看到如下内容:
1 | "scripts": { |
想要深入理解ng serve命令,我们需要先了解start命令是如何工作的。我们通过调式该命令的方式来了解ng serve的底层逻辑。不同的IDE对应不同的调试方式:
- WebStorm: 点击
start命令左侧的绿色三角按钮,然后选择Debug 'start',这样就可以进入ng serve的源码了。 - VSCode: 鼠标悬停到
start命令上,点击Debug按钮,这样就可以进入ng serve的源码了。
使用这种方法可以进入调试状态,但是我们要在哪里设置断点呢?
对于package.json中的script区块中的命令,其实他们都对应node_modules/.bin下面的一个文件。以ng serve为例,因为它的命令由ng来引导,那么我们首先到node_modules/.bin目录下找到ng文件。
可是我们找到了三个ng文件,分别是ng, ng.cmd, ng.ps1,那么我们应该选择哪一个呢?其实通过扩展名就能看出来,我这里使用的是Windows系统,所以我们选择ng.cmd文件。
- ng - Unix shell script
- ng.cmd - Windows batch file
- ng.ps1 - Windows PowerShell script
用记事本打开这个文件看看它的代码:
1 | @ECHO off |
我们不必纠结于每一行代码的含义,简单分析下来,我们可以推断出这个脚本的作用就是用node.exe来调用@angular/cli/bin/ng.js文件。
好了,我们再去看一下这个ng.js文件,这个文件就是Angular CLI的入口文件。ng.js调用了同一目录下的bootstrap.js文件,bootstrap.js文件调用了lib/init.ts文件。init.ts又调用了lib/cli/index.ts文件,后续又有一大堆的调用。
bin/ng.js –> bin/bootstrap.js –> lib/init.ts –> lib/cli/index.ts –> …
通过不断的设置断点并调试得知,最终在文件packages/angular/cli/src/command-builder/architect-base-command-module.ts中通过解析项目的配置文件angular.json,找到serve命令对应的builder,然后通过调用那个builder来启动一个web server。
architect-base-command-module.ts对应的代码如下:
1 | protected async runSingleTarget(target: Target, options: OtherOptions): Promise<number> { |
Webpack配置在哪里?
我们都知道,ng serve命令启动的是一个web server,而这是通过webpack-dev-server来实现的,那么这个webpack-dev-server的配置在哪里呢?我么可以在源码中找到如下目录:packages/angular_devkit/build_angular/src/tools/webpack/configs/common.ts,这个目录下有四个文件:
common.ts- 通用配置,主要是打包配置dev-server.ts- 开发服务器配置 - 我们要找的配置就在这里。styles.ts- 样式配置,用来处理各种样式文件, 如css, scss/sass, less等index.ts- 导出上面三个文件
总结
Angular的CLI命令对应的逻辑源码并不在CLI命令本身中,而是在对应的builder中,builder源码在这个目录下:
packages/angular/build/src/builders- application builderpackages/angular_devkit/build_angular/src/builders- other builders
关于builder的详细介绍,可以参考之前的一篇博文:https://zdd.github.io/2024/06/06/angular-builders/, 也可以参考Angular官方文档:https://angular.dev/tools/cli/cli-builder/
- ng server works in memory and never generate files to dist folder