Vue3 コンパイルプロセス - ソースコード分析

Vue3 コンパイルプロセス - ソースコード分析

序文:

Vue3 がリリースされてからかなり経ちますが、最近、会社のプロジェクトでVue3 + TypeScript + Vite技術スタックを使う機会があり、私も暇な時間に Vue3 のソースコードを読む時間を取っています。記憶力は悪いペンほど良くないという考えから、ソースコードを読みながらメモを取りました。また、ソースコードを読みたいが理解に苦労しているすべての学生の理解コストを削減するために、ソースコードの読み取りメモをいくつか書きたいと思っています。

Vue2.x のソースコードも簡単に読んでみました。Vue3 の再構築以降、Vue プロジェクトのディレクトリ構造も大きく変わりました。各機能モジュールはpackagesディレクトリに配置され、責任がより明確になり、ディレクトリ名から一目でわかるようになりました。今日は、Vue エントリ ファイルから始めて、単一の Vue ファイルがcompile-coreどのように宣言され、レンダリング関数にコンパイルされるかを見ていきます。

読者の便宜と記事の長さを抑えるため、ソースコードを読む際にあまり注意を払う必要のないロジックは折り返したり、/* ロジックを無視 */ などのコメントで無視したりします。

個人的には、ソース コード分析記事を読むときに、冒頭に長いコード セクションが表示されるのは好きではありません。これは、それを読んでいない学生を簡単に混乱させる可能性があるためです。そこで、このシリーズの記事では、キーコードのフローチャートを描いてみたいと思います。目的は同じで、全員が理解するためのコストを削減できるようにし、同時に生徒が次回自主的に読むときに参照できるフローチャートを提供することです。

1. Vueエントリファイルの解釈

Vue オブジェクトのエントリ ポイント、 packages/vue/index.tsからソース コードの読み取りを開始します。このエントリ ファイルのコードは比較的単純で、 compileToFunction関数が 1 つだけですが、関数本体の内容は非常に重要です。そのため、まずこの関数本体が何を実現するのかを正確に理解するために、画像を見てみましょう。

フローチャートを見た後は、一緒にコードを見てみましょう。この時点で、ほとんどの生徒は図のコードについて明確に理解していると思います。

すべてのコードをスキップして、ファイルの最後の 35 行を見てください。registerRuntimeCompiler 関数registerRuntiomCompiler呼び出され、 compileToFunction関数がパラメーターとして渡されます。このコード行は、フローチャートの先頭に対応しています。compile compileは、依存性注入を通じてruntimeに注入されます。依存性注入は、分離するための巧妙な方法です。この時点で、実行時にcompileコンパイル関数を呼び出すと、現在のcompileToFunction関数が呼び出されます。

コードの 17 行目を見ると、 compile-domライブラリによって提供されるcompile関数が呼び出され、戻り値からcode変数が分解されています。コンパイラ実行後に生成されるコンパイル結果です。コードはコンパイル結果のパラメータの 1 つであり、コード文字列です。例えば

<テンプレート>
  <div>
    こんにちは世界
  </div>
</テンプレート>

この単純なテンプレートをコンパイルすると、 codeによって返される文字列は次のようになります。

const _Vue = Vue return function render(_ctx, _cache) { with (_ctx) { const { openBlock: _openBlock, createBlock: _createBlock } = _Vue return (_openBlock(), _createBlock("div", null, "Hello World")) } }

この魔法のcompile関数の内部にある謎については、後ほど詳しく説明します。

このコード文字列の結果を取得した後、コードを見ていきます。25 行目ではrender変数を宣言し、生成されたコード文字列 code をnew Functionコンストラクターのパラメーターとして渡します。これはフローチャートの最後から 2 番目のステップで、 render関数を生成します。上記に入力したcode文字列をフォーマットすると、 render関数が、スコープ チェーンを拡張する関数を返すカリー化された関数であることがわかります。

最後に、エントリ ファイルはrender変数を返し、レンダリング関数をキャッシュします。

上記のソースコードの 1 行目を見ると、エントリ ファイルがcompileToFunction関数によって生成されたrender関数をキャッシュするためのcompileCacheオブジェクトを作成し、 templateパラメータをキャッシュ キーとして使用し、11 行目にキャッシュの判断を行う if 分岐があることがわかります。テンプレートが以前にキャッシュされていた場合、テンプレートはコンパイルされなくなり、キャッシュ内のrender関数が直接返されてパフォーマンスが向上します。

この時点で、 package/vue/index.tsのエントリ ファイルが解釈されています。最も興味深い部分は、コード文字列をコンパイルするために compile 関数を呼び出すことであることは皆さんもご存知だと思いますので、次にcompile関数について引き続き説明します。コンパイル機能には、 compile-domcompile-core 2 つのモジュールが含まれます。この記事では、主要なプロセスについてのみ説明します。詳細な分析は後続の記事に掲載されます。コンパイルの実行プロセスを見てみましょう。

2. コンパイル処理

compile関数は、 baseCompile関数の結果を直接返します。実行中、 baseCompile関数は AST 抽象構文木を生成し、 transformを呼び出して各 AST ノードを処理します。たとえば、vOn、v-if、v-for などの命令を変換します。最後に、処理された AST 抽象構文木は、generate 関数によって使用され、上記のコード文字列を生成し、コンパイル結果を返します。この時点で、 compile関数が実行されます。大まかなプロセスを理解したら、ソースコードを見てみましょう。

compile関数のソースコードパスはpackages/compiler-dom/src/index.tsです。compile compileの本体では、 baseCompileの処理結果が直接返されていることがわかります。 baseCompileのソースコード パスはpackages/compiler-core/src/compile.tsです。 baseCompile名前がなぜこのように付けられているのでしょうか? compile-coreコンパイルのコア モジュールであるため、外部パラメータを受け入れてルールに従ってコンパイルを完了します。compile-dom は、特にブラウザー シナリオでのコンパイルを処理するために使用されます。このモジュールでエクスポートされるコンパイル関数は、エントリ ファイルが実際に受け取るコンパイル関数です。 compile-domの compile 関数も、 baseCompileよりも高レベルのコンパイラです。たとえば、Vue が iOS または Android 上の weex などのネイティブ アプリで動作する場合、 compile-dom関連するモバイル コンパイル ライブラリに置き換えられることがあります。

以下の baseCompile 関数を見てみましょう。

まず、関数宣言から、 baseCompile template template と上位レベルの高レベルコンパイラによって処理されたコンパイルoptions options を受け取り、最後にCodegenResult型のコンパイル結果を返します。

エクスポートインターフェースCodegenResult {
  コード: 文字列
  プリアンブル: 文字列
  ast: ルートノード
  マップ?: RawSourceMap
}

CodegenResultのインターフェース宣言を通じて、返された結果にcode文字列、処理された AST 抽象構文ツリー、および sourceMap が含まれていることが明確にわかります。

上記のソース コードの 12 行目を見て、 templateが文字列かどうかを判断します。文字列の場合は文字列が解析され、文字列でない場合はtemplate直接 AST として使用されます。実際、私たちが通常記述する単一ファイルの Vue コードは文字列として渡されます。

次のソースコードは 16 行目です。これは、 transform関数を呼び出し、命令変換やノード変換などのツール関数を渡して、テンプレートによって生成された AST を変換します。

最後に、32 行目で、変換された AST を生成に渡し、 CodegenResult型の戻り結果を生成します。

compile-core モジュールでは、AST 解析、 transformcodegencompile 、およびparse関数はすべて独立した小さなモジュールです。内部実装は非常に洗練されており、コンパイラに関する今後の記事で 1 つずつ紹介されます。

この記事では、エントリ ファイルから始まるコンパイルの一般的なプロセスについて説明します。コンパイラのこのモジュールのコードを読むときに、誰もがプロセスを明確に理解できるようにし、フローチャートとともに読むとさらに興味深くなることを願っています。

これで、Vue3 コンパイルプロセス - ソースコード分析に関するこの記事は終了です。Vue3 コンパイルプロセスの関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • アイデアコンパイラvueインデントエラー問題シナリオの分析
  • Vue でリッチテキストエディタ wangEditor3 を使用する方法
  • Vue3 テンプレートコンパイルの原理に関する深い理解
  • Vue-cliがes6をコンパイルできない問題を解決する
  • Vue プロジェクトのパッケージ化とコンパイルの最適化ソリューション
  • vue プロジェクトをコンパイルする webpack によって生成されるコード探索についての簡単な説明
  • Vue テンプレートのコンパイルの詳細

<<:  Docker インストール Nginx チュートリアル 実装図

>>:  MySQLのデッドロックチェック処理の通常の方法

推薦する

Vue3 コンポジション API の紹介

目次概要例なぜそれが必要なのでしょうか?設定参照、反応的計算して見るライフサイクルVue3.0 は ...

ファイル共有サーバーを構築するための samba + OPENldap の詳細な説明

ここでは、samba (ファイル共有サービス) v4.9.1 + OPENldap (バックエンド ...

MySQL ビューの原則分析

目次更新可能なビュービューのパフォーマンスビューの制限ビューは MySQL 5.0 以降で導入されま...

CSSをインポートする方法に関する詳細な洞察の要約

CSS の開発履歴についてはここでは紹介しません。ブログを書いている理由の 1 つは、フロントエンド...

この記事はJavaScriptの変数とデータ型を理解するのに役立ちます

目次序文:親切なヒント:変数1. 免責事項2. 譲渡3. 2つの小さな文法上の詳細変数の命名規則なぜ...

WebページのレイアウトではIE6の互換性の問題を考慮する必要があります

下の図は、当社のウェブサイト統計システムの訪問者詳細におけるブラウザ閲覧率を示しており、IE6 が ...

Win10にmysql8.0.15 winx64をインストールしてサーバーに接続する際に問題が発生しました

1. mysql-8.0.15をダウンロード、インストール、設定する1. 公式サイト (https:...

Windows 環境での MySQL 8.0 のインストール、設定、アンインストール

ソフトウェアバージョンウィンドウズ: ウィンドウズ10 MySQL: mysql-8.0.17-wi...

CSS3 で画像ドロワー効果を実装するためのサンプル コード

いつものように、まずは画像効果を投稿しましょう: このエフェクトの原理は非常にシンプルです。CSS3...

JavaScript のシングルトン デザイン パターン

目次1. デザインパターンとは何ですか? 2. デザインパターンの5つの設計原則(SOLID) 3....

MySQL ロック(テーブルロック、行ロック、共有ロック、排他ロック、ギャップロック)の詳細な説明

現実世界では、鍵は外の世界から身を隠したいときに使用するツールです。コンピュータでは、複数のプロセス...

Expressを使用してプロジェクトを自動的にビルドするNode.jsのプロセス全体

1. Expressライブラリとジェネレータをインストールするcmdを開いて、次のコマンドを入力しま...

mysql 8.0.16 winx64 および Linux でルート ユーザーのパスワードを変更する方法

データベースへの接続などの基本的な操作はご自身で行ってください。この記事ではパスワードの変更方法を中...

JS Canvas インターフェースとアニメーション効果

目次概要Canvas API: グラフィックスの描画パス線種矩形アーク文章グラデーションと画像の塗り...