yarn add から webpackがimportを解決するまでを追う
Javascriptでは、Yarnとwebpackを使うのが主流なので、それらがどのような動きをしているかを追った。
事前準備
動きを追うために以下を用意した
- コード
- Verdaccio
コード
コードの配置は以下
. ├── build │ └── bundle.js ├── node_modules │ ├── my-isarray │ ├── webpack -> ../../../.config/yarn/link/webpack │ ├── webpack-cli ├── package.json ├── src │ └── app.js ├── webpack.config.js └── yarn.lock
各ファイルの中身は、
- my-isarray
console.log("test-isarray"); export default function(obj) { console.log("my-isarray is called"); return Array.isArray(obj); }
- src/app.js
import a from "my-isarray"; (function() { console.log("src************"); })() a();
- webpack.config.js
module.exports = { mode: "none", entry: "./src/app.js", output: { filename: "bundle.js", path: __dirname + "/build" } }
Verdaccio
プライベートnpm のレポジトリ用にVerdaccioを使った。
dockerが用意されているので、configを弄った後に自作のpackageを登録すれば完了する
Yarnとwebpackのコミットハッシュ
調査に使用したコードのハッシュ値は以下である
Yarn: c58bd58e029ab5a69d75742c6ae82aa96cef0140 (v1.11.0-0)
webpack: 5ade57451073ef0993379d2cc6b80d616e86ef5d (v4.19.0)
動きを追う
大まかな流れは画像の様になる
yarn add
最初に、yarn add
をしてnode_modules
に展開されるまでを追う
- npmからメタデータを取得する
npmのAPIを使用して、hash値やバージョンなどの最新情報を取得する。 - npmから~/.cache/yarn/v2に保存
メタデータと以前にダウンロードしたものが違うものであればtarballをダウンロードして、展開する。
この時、直接node_modules
にダウンロードするのではなく、~/.cache/yarn/v2
のような共通ディレクトリにダウンロードすることで、別プロジェクトが使うときにも使いまわせるようになっている。 - 対象のnode_modulesディレクトリへコピー
~/.cache/yarn/v2
に保存したパッケージ内容を対象ディレクトリにコピーする。
webpackを使って対象パッケージを使用する
次に、webpack
が"ビルド"として行っている「ファイルの結合」の流れを追う
- Parserを通して各ファイルの依存関係を発見する
Acornを使用してパースしている。
Acornの結果を基に、webpack内にあるParser.js
がフックポイントを作って回る。
このフックポイントの一つがimport
を通ったときに発火するようになっているので、発火した場所を見ることで各ファイルが依存したパッケージを知ることが出来る。 - Resolverが名前解決する
enhanced-resolveという、デフォルトのResolverがwebpackから切り出されている。
これを利用することで、各ファイルが依存しているパッケージをnode_modulesから選び出している。 - webpackに登録されたLoader,Pluginsを実行し、各ファイル・全体を変更する
- 結果を基にファイルをつなぎ合わせる
以上
以上で、yarnがパッケージをダウンロードしてwebpackがファイルに結合するまでの流れが追えた。
読んでいて思ったこと
Yarn
yarnでは、jestとflowを使用していて、「やはり、Facebook製」といった感じを出している。
やることを絞っているためか、コードは結構シンプルで読みやすい。
上に書いた事以外にも、ネストや重複した依存関係の解決があるのでそこはまた読んでみたい所
webpack
webpackはプラグインの仕組みを使っていて、他の人が勝手にプラグインを書いて好きに公開できるようになっている。
この仕組みはwebpackを下支えしている良い仕組みだと思う。
ただし、コードを見ると、制御できている人が居るのか疑問なレベルの複雑さを持っている。
読み慣れていないせいかもしれないが、コールバック地獄がかなり読みづらかった。
また、hooks
という各PluginやLoaderに対するフックポイントをまとめた変数があるのだが、フックポイントが多すぎてどこがいつ影響するのかわかりづらい。
あと、デフォルトのプラグインがまとめてlib
直下に送られているのは流石にどうかと思う・・・