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のデッドロックチェック処理の通常の方法

推薦する

MySQLが正常にインストールされたかどうかを確認する方法

MySQL をインストールした後、DOS ウィンドウまたは MySQL 5.7 コマンドライン クラ...

jQueryは何に使われるのですか?jQueryは実際にはjsフレームワークです

jQuery 入門jQuery ライブラリは、簡単なマークアップ行を使用して Web ページに追加で...

mysql バックアップ戦略の実装 (フルバックアップ + 増分バックアップ)

目次設計シナリオ技術的なポイントサーバー情報準備フルバックアップスクリプト(Mysql-FullyB...

HTML要素を非表示にするいくつかの方法

1. CSSを使用するコードをコピーコードは次のとおりです。スタイル="display:n...

@font-face を使用して Web ページに特殊文字を実装する (カスタム フォントを作成する)

数日前、CSS を使用して三角形の矢印を実装する方法について記事を書きました。 目的の効果は達成され...

vueプロジェクトは特定の領域に透かしを描くことを実現する

この記事では、Vueを使用して特定の領域に透かしを描く方法を紹介します。具体的な内容は次のとおりです...

Vue で円形プログレスバーを実装する例

データ表示は、常にあらゆる職業の人々が求めているものです。特にフロントエンド開発業界では、データを表...

燃える炎効果の英語フォント16種類をシェアする

私たちは視覚の世界に住んでおり、多くの視覚効果に囲まれています。コンピューターの前にいても、屋外にい...

Mysql 5.7.18 MySQL proxies_priv を使用して同様のユーザーグループ管理を実装する

MySQL proxies_priv(シミュレートされたロール)を使用して同様のユーザーグループ管理...

Vue でよく使われる高階関数と包括的な例

1. 配列のよく使われる高階関数配列があり、その配列に対して次の操作を実行したいとします。 100 ...

JavaプログラミングでJavaScriptの超実用的なテーブルプラグインを書く

目次効果ドキュメント最初のステップステップ2ステップ3ソースコード効果ドキュメント最初のステップta...

MySQL で最大接続数を正しく変更する 3 つの方法

MySQL データベースをインストールすると、デフォルトの MySQL データベースの最大接続数が ...

Nexusプライベートサーバー構築原理とチュートリアル分析

1つ。 Nexus プライベート サーバーを構築する理由は何ですか?社内の開発メンバーは全員外部ネッ...

MySQL の分離レベル、ロック、MVCC の紹介

この記事の目的は、これらの概念とその機能の関係を明らかにすることです。 Mysql がトランザクショ...

Linux でのマルチスレッドおよびマルチプロセス クラッシュのシミュレーションに関する簡単な説明

結論:マルチスレッド環境では、スレッドの 1 つがクラッシュすると、他のスレッド (プロセス全体) ...