學習一個庫的源碼,我認爲不能直接打開 src
或者 lib
目錄去直接找入口文件着去閱讀,而應該去了解下庫的做者是如何梳理、debug
源碼的vue
本着這個原則,咱們須要在閱讀源碼以前,理清楚整個項目是如何 debug
的,一些 pkg.json
裏的命令是如何執行的node
如下代碼所有出自於 babel-7.9.6
這個版本,源碼地址:https://github.com/babel/babel/tree/v7.9.6react
拿到一個 nodejs
的庫,首先應該看他根目錄下的 package.json
文件。git
做爲閱讀者和學習者,咱們應該關注它的 scripts
和 bin
兩個字段下的內容。github
因爲 babel
的 bin
命令都散落在 packages
中的各個包中,因此這裏咱們只須要關注 scripts
字段:typescript
"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
命令觸發。npm
此時會在根目錄下尋找名爲 makefile
或者 Makefile
的文件,找到後則執行相應的內容。json
以 lint: make lint
爲例:gulp
找到 Makefile
中的 lint
命令的註冊位置:bootstrap
lint: lint-js lint-ts
注:Makefile
的主要語法爲:
target : Array<prerequisites> List<command>
具體爲:
target
: 命令 label
,或者 target
文件 => 這裏只作一個命令的名稱prerequisites
: 依賴的命令或目標文件 => 能夠理解成執行該命令前須要執行的命令, 能夠沒有,也能夠不少不少command
: 具體的指令,純 bash
好的回過頭來,咱們發現他有兩處 prerequisites
:
lint-js
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 bootstrapThen you can either run:
$ make buildto build Babel once or:
$ make watchto 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
咱們能夠看到前置執行了 build-no-bundle
以後,執行的是:
BABEL_ENV=development yarn --silent gulp watch
因此控制權交回到 gulp
和 Gulpfile
中的各個 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-bundle
的 task
,然後從新執行 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
至此,咱們就能夠邊調試邊學習了~