babel源码阅读 ~ 准备工作

前言

学习一个库的源码,我认为不能直接打开 src 或者 lib 目录去直接找入口文件着去阅读,而应该去了解下库的作者是如何梳理、debug 源码的

本着这个原则,我们需要在阅读源码之前,理清楚整个项目是如何 debug 的,一些 pkg.json 里的命令是如何执行的

以下代码全部出自于 babel-7.9.6 这个版本,源码地址:https://github.com/babel/babel/tree/v7.9.6

package.json

拿到一个 nodejs 的库,首先应该看他根目录下的 package.json 文件。

作为阅读者和学习者,我们应该关注它的 scriptsbin 两个字段下的内容。

由于 babelbin 命令都散落在 packages 中的各个包中,所以这里我们只需要关注 scripts 字段:

"scripts": {
    "bootstrap": "make bootstrap",
    "codesandbox": "make bootstrap-only; make build-no-bundle",
    "build": "make build",
    "fix": "make fix",
    "lint": "make lint",
    "test": "make test"
}

我们发现所有的 script,全部使用 make 命令触发。

此时会在根目录下寻找名为 makefile 或者 Makefile 的文件,找到后则执行相应的内容。

Makefile

lint: make lint 为例:

找到 Makefile 中的 lint 命令的注册位置:

lint: lint-js lint-ts

注:Makefile 的主要语法为:

target : Array<prerequisites> 
    List<command>

具体为:

  • target: 命令 label,或者 target 文件 => 这里只做一个命令的名称
  • prerequisites: 依赖的命令或目标文件 => 可以理解成执行该命令前需要执行的命令, 可以没有,也可以很多很多
  • command: 具体的指令,纯 bash

好的回过头来,我们发现他有两处 prerequisites

  1. lint-js
  2. lint-ts

所以此时去找到两个依赖的命令:

# YARN 这个变量赋值为 `yarn --silent`
YARN := yarn --silent

# SOURCE 变量赋值为: `packages codemods eslint` 
SOURCES = packages codemods eslint

# lint-js 不包含依赖,只有一条命令
lint-js:
    # 带入 YARN 和 SOURCE 变量后,执行的命令就是: 
    # BABEL_ENV=test yarn --silent eslint scripts packages codemods eslint '*.js' --format=codeframe
	BABEL_ENV=test $(YARN) eslint scripts $(SOURCES) '*.js' --format=codeframe

lint-ts:
    # 直接执行 scripts 目录下的 lint-ts-typigs.sh 这个脚本
	scripts/lint-ts-typings.sh

我们可以看到,lint-js 命令就相当于我们在控制台中输入:

BABEL_ENV=test yarn --silent eslint scripts packages codemods eslint '*.js' --format=codeframe

可以看到执行的是 eslint 命令,我们可以将 --silent 去掉后看到 eslint 命令的位置:

/Users/anning/Desktop/babel-7.9.6/node_modules/.bin/eslint scripts packages codemods eslint '*.js' --format=codeframe

注:其实一般都在 /node_modules/bin 里找...

说完这个例子之后,我们折回来说我们学习时 debug 的方式。

scripts 里我们是没能找到类似 vue-next 之类的 "dev": "node scripts/dev.js", 之类的命令的,所以也不能够像 vue-next 那样直接 yarn dev [packageName] 的去 debug 某个具体的包

这时候我们有注意到 CONTRIBUTING 里有一段:

Fork the babel repository to your GitHub Account.

Then, run:

$ git clone https://github.com/<your-github-username>/babel
$ cd babel
$ make bootstrap

Then you can either run:

$ make build

to build Babel once or:

$ make watch

to have Babel build itself and incrementally build files on change.

所以我们尝试去寻找 Makefile 中的 watch 指令:

watch: build-no-bundle
	BABEL_ENV=development $(YARN) gulp watch

这里也给出 build-no-bundle 的各个依赖的配置和注释:

# 先执行 clean, clean-lib
build-no-bundle: clean clean-lib
    # 控制权交到 gulp 和 Gulpfile. 执行 Gulpfile 里的 build-no-bundle task
	BABEL_ENV=development $(YARN) gulp build-no-bundle
	# Ensure that build artifacts for types are created during local
	# development too.
	// 然后执行到 makefile 里的 generate-type-helpers 和 build-typings 命令
	$(MAKE) generate-type-helpers
	$(MAKE) build-typings

# 执行 `node packages/babel-types/scripts/generateTypeHelpers.js` 这条命令
generate-type-helpers:
	$(NODE) packages/babel-types/scripts/generateTypeHelpers.js
	
# 执行 build-flow-typings build-typescript-typings 两条前置依赖的指令
build-typings: build-flow-typings build-typescript-typings

# 编译 flow 的类型文件
build-flow-typings:
	$(NODE) packages/babel-types/scripts/generators/flow.js > packages/babel-types/lib/index.js.flow

# 编译 ts 的类型文件
build-typescript-typings:
	$(NODE) packages/babel-types/scripts/generators/typescript.js > packages/babel-types/lib/index.d.ts

# 先执行 test-clean 命令
# 而后删除一些文件夹 - -。。
clean: test-clean
	rm -f .npmrc
	rm -rf packages/babel-polyfill/browser*
	rm -rf packages/babel-polyfill/dist
	rm -rf coverage
	rm -rf packages/*/npm-debug*

# 执行 clean-source-test 这个变量下的命令
test-clean:
	$(foreach source, $(SOURCES), \
		$(call clean-source-test, $(source)))

# 执行 clean-source-lib 这个变量下的命令		
clean-lib:
	$(foreach source, $(SOURCES), \
		$(call clean-source-lib, $(source)))

# clean-source-lib定义
define clean-source-lib
	rm -rf $(1)/*/lib
	
endef

# clean-source-test 定义
define clean-source-test
	rm -rf $(1)/*/test/tmp
	rm -rf $(1)/*/test-fixtures.json

endef

Gulpfile

我们可以看到前置执行了 build-no-bundle 之后,执行的是:

BABEL_ENV=development yarn --silent gulp watch

所以控制权交回到 gulpGulpfile 中的各个 task 中,我们看到 gulp watch 对应的脚本是:

const defaultSourcesGlob = "./@(codemods|packages|eslint)/*/src/**/*.js";
gulp.task("build-no-bundle", () => buildBabel());

gulp.task(
  "watch",
  gulp.series("build-no-bundle", function watch() {
    gulp.watch(defaultSourcesGlob, gulp.task("build-no-bundle"));
  })
);

比较明显的就是会监听 defaultSourcesGlob 下的文件,监听到修改时就会重新执行 build-no-bundletask,而后重新执行 buildBabel()

我们尝试执行 make watch 之后,控制台打印如下信息:

[11:50:26] Using gulpfile ~/Desktop/babel-7.9.6/gulpfile.js
[11:50:26] Starting 'watch'...
[11:50:26] Starting 'build-no-bundle'...
[11:50:26] Compiling 'packages/babel-helper-builder-react-jsx-experimental/src/index.js'...
[11:50:27] Compiling 'packages/babel-helper-compilation-targets/src/debug.js'...
@babel/preset-env: `DEBUG` option

Using targets:
{
  "node": "10.15"
}

Using modules transform: false

Using plugins:
  proposal-numeric-separator { "node":"10.15" }
  proposal-nullish-coalescing-operator { "node":"10.15" }
  proposal-optional-chaining { "node":"10.15" }
  syntax-json-strings { "node":"10.15" }
  syntax-optional-catch-binding { "node":"10.15" }
  syntax-async-generators { "node":"10.15" }
  syntax-object-rest-spread { "node":"10.15" }
  syntax-dynamic-import { "node":"10.15" }

.......

在经历了很多很多文件的输出之后,我们看到最后两句:

[11:50:44] Finished 'build-no-bundle' after 18 s
[11:50:44] Starting 'watch'...

一切如我们所见。

我们修改之后,被修改的文件会重新被编译:

[11:50:44] Finished 'build-no-bundle' after 18 s
[11:50:44] Starting 'watch'...
[11:55:17] Starting 'build-no-bundle'...
[11:55:18] Compiling 'packages/babel-core/src/index.js'...
[11:55:18] Finished 'build-no-bundle' after 700 ms
[11:55:27] Starting 'build-no-bundle'...
[11:55:27] Compiling 'packages/babel-core/src/index.js'...
[11:55:27] Finished 'build-no-bundle' after 422 ms
[11:55:47] Starting 'build-no-bundle'...
[11:55:47] Compiling 'packages/babel-core/src/index.js'...
[11:55:48] Finished 'build-no-bundle' after 376 ms
[11:55:50] Starting 'build-no-bundle'...
[11:55:50] Compiling 'packages/babel-core/src/index.js'...
[11:55:50] Finished 'build-no-bundle' after 362 ms

至此,我们就可以边调试边学习了~

posted @ 2020-05-09 15:26  叁歌~  阅读(524)  评论(0)    收藏  举报