Open7

esbuildを読む

ryota kiseryota kise

https://github.com/evanw/esbuild

swcなどと同様にbabelなどの代替手段として作られたもの、READMEに書いてある通り早い
Rustはわからないが、Goならある程度は読めるし、GoでJavascriptASTをいじりたいのでそのためにコードを読む。

FAQのところにいい質問がたくさん書いてあるので読んだ方が良さそう
https://esbuild.github.io/faq/

基本的に関数のところに英語でコメントがあり、ある程度何がしているかは理解できそう

https://github.com/jamiebuilds/the-super-tiny-compiler/blob/master/the-super-tiny-compiler.js

ryota kiseryota kise

https://github.com/evanw/esbuild/blob/master/docs/architecture.md
ここにesbuildの設計思想や何をしているのかが書いてある
設計思想として

  • 最大限の並列化
  • 不必要な作業の回避
    変換してさらにそれを読んでっていうのをなくしてる
  • ES6とCommonJSの両方の構文のサポート
  • キャッシュの局所性を高めるためにできるだけ少ないfullASTにしてる
  • インクリメンタルにコンパイルできる「ウォッチモード」を可能にするための構造
    変更時の再実行するコードを最小限にしてる

https://ja.wikipedia.org/wiki/定数畳み込み

ryota kiseryota kise

https://esbuild.github.io/api/

APIの実装
https://github.com/evanw/esbuild/blob/master/pkg/api/api.go

The transform API call operates on a single string without access to a file system. This makes it ideal for use in environments without a file system (such as a browser) or as part of another tool chain.The transform API call operates on a single string without access to a file system. This makes it ideal for use in environments without a file system (such as a browser) or as part of another tool chain.

The build API call operates on one or more files in the file system. This allows the files to reference each other and be bundled together.

transformは任意の長さの文字列を変形してくれる、buildは一つまたは複数のファイルの中身を変形してくれる

ryota kiseryota kise

https://github.com/evanw/esbuild/blob/master/internal/js_parser/js_parser.go

js_parser.goにesbuildのパーサーが何をしているのかが書かれている

  1. Parse the source into an AST, create the scope tree, and declare symbols.
  2. Visit each node in the AST, bind identifiers to declared symbols, do constant folding, substitute compile-time variable definitions, and lower certain syntactic constructs as appropriate given the language target.
    So many things have been put in so few passes because we want to minimize the number of full-tree passes to improve performance. However, we need to have at least two separate passes to handle variable hoisting. See the comment about scopesInOrder below for more information.
ryota kiseryota kise

logger にtokenとかの情報が入ってる

           printer -> linker -\
input -> parser -> scanner ---> compiler -> output

NewLexer -> newParser -> Parse -> parseFile -> maybeParseFile -> scanAllDependencies -> ScanBundle -> Compile -> buildImpl -> Build
                                                                                   Printer -> link -> Compile