Vue テンプレートのコンパイルの詳細

Vue テンプレートのコンパイルの詳細

考える:

HTML はタグ言語であり、判定やループを実装できるのは JS だけです。テンプレートには命令、補間、JS 式があり、判定やループなどを実装できます。したがって、テンプレートは HTML ではないため、テンプレートを何らかの JS コードに変換する必要があります。このコンパイルはどのように行われるのでしょうか?

分析:

テンプレートのコンパイルは、テンプレートをレンダリング関数にコンパイルするプロセスです。このプロセスは、おおまかに次の 3 つの段階に分けられます。

1. 解析する

パーサーは主にテンプレート文字列をelement ASTsに変換します。

テンプレート文字列:

<div>
   <p>{{メッセージ}}</p>
</div>

要素 AST

AST は抽象構文ツリーを指し、 Vnodeに似ています。どちらもJavaScriptオブジェクトを使用してノードのツリー表現を記述します。

{
  タグ: "div"
  // ノードタイプ (1 ラベル、2 リテラル式を含むテキストノード、3 通常のテキストノードまたはコメントノード)
  タイプ: 1,
  // 静的ルートノード staticRoot: false,
  // 静的ノード static: false,
  平易: 真実、
  // 親ノード要素の説明オブジェクトへの参照 parent: undefined,
  // ノードタイプが 1 の場合のみ、attrsList 属性が存在します。これは、元の HTML 属性名と値を格納するオブジェクト配列です。attrsList: [],
  // 上記と同じですが、違いは attrsMap が HTML 属性名と値をキーと値のペアで保存することです: attrsMap: {},
  //このノードのすべての子ノードの要素記述オブジェクトを格納します。children: [
      {
      タグ: "p"
      タイプ: 1,
      静的ルート: false、
      静的: false、
      平易: 真実、
      親: {タグ: "div", ...},
      属性リスト: [],
      属性マップ: {},
      子供たち: [{
          タイプ: 2,
          テキスト: "{{メッセージ}}",
          静的: false、
          // ノードタイプが 2 の場合、オブジェクトには式式: "_s(message)" が含まれます。
      }]
    }
  ]
}

1.1 傍受のルール

主にテンプレート内の html.indexof('<') の値を判断して、タグをインターセプトするかテキストをインターセプトするかを決定します。

傍受プロセス:

文字列部分

`<div><p>{{メッセージ} } <p></div>`

1.2 傍受プロセス部分

最初の迎撃

  • テンプレート内のhtml.indexof('<')の値が 0 であることを確認します (コメント、条件付きコメント、 doctype 、開始タグ、終了タグのいずれか)
  • 開始タグの正規表現が正常に一致し、現在のタグ名が div として取得され、一致した '<div' 部分が切り捨てられて新しい文字列 ><p>{{message}}</p></div> が取得されます。
  • 開始タグを切り取った後、一致する属性の正規表現を使用して一致させます。一致が成功した場合、タグの属性リストが取得されます。一致が失敗した場合、タグの属性リストは空の配列になります。
  • 属性が切り取られた後、開始タグの末尾に一致する正規表現を使用して、それが自己終了タグであるかどうかの情報を取得するために一致させ、一致した文字列を切り取って新しい文字列を取得します<p>{{message}}</p></div>
  • 開始タグを照合し、現在のノードにルート ノードがあるかどうかを判断します。ルート ノードがない場合は、要素タイプのツリー ノードが作成されます。存在する場合は、それがcurrentParentの子ノードとして設定され、現在のノードがstackにプッシュされます。
/**
   まとめると、タグを一致させ、属性を抽出し、階層を確立します*/
// 上記のマッチング後、残りの文字列は次のようになります:
`<p>{{メッセージ} } <p></div>`

2回目のインターセプト

/**
    同上*/
// 上記のマッチング後、残りの文字列は次のようになります:
`{{メッセージ}}</p></div>`

3回目のインターセプト

  • テンプレート内のhtml.indexof('<')の値が 0 以上であるかどうかを確認します (テキストと式のいずれか)
  • 最も近い '<' を照会し、それが一致するかどうかを確認します (開始タグ、終了タグ、コメント、条件付きコメントのいずれか)。一致が成功した場合、トラバーサルは終了します。一致しない場合は、トラバーサルが続行されます。

例えば:

a < b </p> =>テキスト部分 a < b 、終了タグに当たる

a<b</p> =>テキスト部分 a
開始タグ<b

/**
   要約すると、タイプを判別してテキストを傍受する*/
// 上記のマッチング後、残りの文字列は次のようになります:
</p></div>`


4回目のインターセプト

  • テンプレート内のhtml.indexof('<')の値が 0 であることを確認します (コメント、条件付きコメント、doctype、開始タグ、終了タグのいずれか)
  • 終了タグの正規表現が正常に一致し、一致した部分 </p> が切り取られて新しい文字列 </div> が取得されます。
  • 終了タグが一致すると、ノード「p」がスタックからポップされ、スタック内の最後のノード「div」がcurrentParent
/**
    まとめると、ラベルを合わせてレベルを決定します*/
// 上記のマッチング後、残りの文字列は次のようになります:
</div>` </div>`
5回目のインターセプト/**
    同上*/
仕上げる

1.3 パーサーの概要

  • テンプレート文字列element ASTsに変換するプロセスは、実際には文字列を継続的にインターセプトして解析するプロセスです。
  • 開始タグが一致すると、対応する開始タグがインターセプトされ、AST の基本構造が定義され、タグ上の属性 ( attrstagName ) や命令などが解析され、タグがスタックにプッシュされます。
  • 終了タグが一致すると、スタック内の各項目のtagNameこの終了タグのtagNameを介して後ろから前に向かって一致する必要があり、一致した項目の後のすべての項目が削除されます (スタックからポップされます)。したがって、スタック内の最後の項目が親要素になります。
  • 解析フェーズでは、ノードはフラット化され、階層関係はありません。ノード ツリーを観察すると、最も内側のノードが解析され、最後に解析されるノードが親要素であることが多いことがわかります。そのため、スタックを使用してノードの階層関係を記録します。
  • 自己終了タグ <input /> には子ノードがないため、 stackpush必要はありません。

2. 最適化する

オプティマイザの主な機能は、生成された AST の静的コンテンツを最適化し、静的ノードをマークすることです。毎回再レンダリングするために、静的サブツリーに新しいノードを作成する必要がなく、仮想 DOM でのpatch処理をスキップできます (つまり、2 ページ目のレンダリングに参加する必要がないため、レンダリング効率が大幅に向上します)。

2.1 静的ノード

AST構文ツリーをトラバースし、すべての静的ノードを見つけてマークします。

関数isStatic(ノード) {
    // 表現
    ノードタイプ === 2 の場合 {
      偽を返す
    }
    //文章
    ノードタイプが3の場合
      真を返す
    }
    /**
 

1. 動的バインディング構文は使用できません。つまり、タグに v-、@、または : で始まる属性を含めることはできません。
2. v-if、v-else、v-for 命令は使用できません。
3. 組み込みコンポーネントにすることはできません。つまり、タグ名をslotおよびcomponentにすることはできません。
4. タグ名はプラットフォームで予約済みのタグである必要があります。つまり、コンポーネントにすることはできません。
5. 現在のノードの親ノードはv-forを使用したtemplateタグにすることはできません。
6. ノードのすべての属性のキーは、静的ノードにのみ存在するキーである必要があります。注: 静的ノードのキーは制限されています。

指定できるのは、 type 、tag、attrsList、attrsMap、plain、parent、children、attrs のいずれか 1 つだけです。

    */
    戻り値 !!(node.pre || (
      !node.hasBindings &&
      !node.if && !node.for &&
      !isBuiltInTag(ノードタグ) &&
      プラットフォーム予約タグ(node.tag) &&
      !isDirectChildOfTemplateFor(ノード) &&
      Object.keys(ノード).every(isStaticKey)
    ))
}

2.2 静的ルートノード

上記の手順の後にツリーをトラバースし、静的ルートノードを見つけてマークします。

2.3 オプティマイザの概要

  • Vueの独自の構文( v-pre v-onceを除く)を使用しないノードは静的ノードと呼ばれる。
  • 静的ノード:現在のノードと、そのすべての子ノードが静的ノードであることを示します。
  • 静的ルートノード:自身とそのすべての子ノードは静的ノードであるが、親ノードは動的ノードであるノードを指します。

3. コードジェネレーターを生成する

コード ジェネレーターの機能は、AST 構文ツリーを介してコード文字列を生成することです。コード文字列はレンダリング関数にパッケージ化されます。レンダリング関数が実行されると、vnode を取得できます。

3.1 構文付きJS

with を使用すると、 {} 内の自由変数の検索方法を変更したり、 {} 内の自由変数をobjの属性として検索したりできます。一致する obj 属性が見つからない場合は、エラーが報告されます。

定数オブジェクト = {a: 100, b: 200}
(obj) で {
     コンソールログ(a)
     コンソールログ(b)
     // console.log(c) // エラーを報告します}

コード文字列

parseによって生成された要素ASTを解析し、文字列に連結します。

(これ){_c('div',_c('p',[_v(message)])]) を返します}

レンダリング関数を取得します。

/** コード文字列は、new Function('code string') を通じて現在のコンポーネントのレンダリング関数を取得できます。*/

const stringCode = `with(this){return _c('div',_c('p',[_v(message)])])}`

const render = 新しい関数(文字列コード)

さまざまな命令、補間、JS式を表示するには、 vue-template変換を使用できます。

const コンパイラ = require('vue-template-compiler')
// 補間 const template = `<p>{{message}}</p>`
const 結果 = コンパイラ.コンパイル(テンプレート)
console.log(結果.レンダリング)
// with(this){return _c('p',[_v(_s(message))])}


略語関数の意味を調べるためのVueソースコード

テンプレートコンパイルのソースコードは`vue-template-compiler` [2]パッケージにあります。

関数 installRenderHelpers(ターゲット) {
    target._c = 要素を作成します
    // タグ v-once
    target._o = 一度だけマーク
    // 数値型に変換 target._n = toNumber
    // 文字列に変換 target._s = toString
    // v-for をレンダリングする
    target._l = レンダリングリスト
    // 通常のスロットとスコープ付きスロットをレンダリングする target._t = renderSlot
    // staticRenderFns を通じて静的ノードをレンダリングする target._m = renderStatic
    // フィルターターゲットを取得します。_f = resolveFilter
    // キーボードイベントのキーコードをチェックする
    target._k = チェックキーコード
    ターゲット._b = バインドオブジェクトプロパティ
    // テキスト vnode を作成する
    ターゲット._v = テキストVノードを作成します
    // 空のvnodeを作成する
    target._e = 空のVノードを作成します
    target._u = スコープ付きスロットを解決する
    ターゲット._g = バインドオブジェクトリスナー
    // 処理修飾子 target._p = prependModifier
}

まとめ:

Vue スキャフォールディングは、開発環境でテンプレートをコンパイルするためにvue-loaderを使用します (事前コンパイル)

解析プロセスでは、文字列を小さなセグメントに分割し、スタックを維持して DOM の深さを保存します。すべての文字列がインターセプトされると、完全な AST が解析されます。

最適化プロセスでは、すべてのノードを再帰的にマークして静的ノードであるかどうかを示し、次に静的ルート ノードを再度再帰的にマークします。

コード生成ステージでは、関数実行コードの文字列を再帰的に生成します。再帰プロセスでは、異なるノード タイプに応じて異なる生成メソッドが呼び出されます。

これで、vue テンプレートコンパイルの詳細に関するこの記事は終了です。より関連性の高い vue テンプレートコンパイルのコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。

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

<<:  Mysql5.7でのスケジュールバックアップの実装

>>:  Docker Compose マルチコンテナデプロイメントの実装

推薦する

MySQLキーワードDistinctの詳細な紹介

MySQLキーワードDistinctの使い方の紹介DDL SQLを準備します: テーブルテストを作成...

Docker を使用して pypi プライベート リポジトリを構築する方法

1. 建設1. htpasswd.txtファイルを準備するファイルには、パッケージを倉庫にアップロー...

Linuxカーネルとデバイスツリーのコンパイルと書き込みを分析する

目次1. 材料を準備する2. Linuxカーネルファイルをダウンロードする3. コンパイル4. TF...

Linux で Bash コマンド プロンプトをカスタマイズする方法

序文ご存知のとおり、bash (Bourne-Gain Shell) は、ほとんどの Linux デ...

Zabbix が MySQL のマスター/スレーブ状態を監視する方法の詳細な説明

MySQLマスタースレーブを設定した後、スレーブの状態が正常かどうかわからないことが多く、例外が発生...

MySQL でサーバーのインストールを開始できない場合の解決策について簡単に説明します。

コンピュータに初めて MySQL をインストールする場合、通常このエラー メッセージは表示されません...

Web プロジェクト開発 VUE の混合と継承の原則

目次ミキシンMixin ノート (重複名)ローカルミックスイングローバル ミックスイン定義とグローバ...

ウェブページの背景色を制御する CSS コード

誰もが自分の Web ページの背景にふさわしい画像を見つけることに悩むことが多いと思います。これは事...

CSSを使用してTDのINPUTの幅を設定する

最近、C# を使用して Web プログラムを作成していたときに、次のような問題が発生しました。 Te...

Win10でのMySQL5.7.17無料インストール版の基本設定チュートリアルについて(画像とテキスト付き)

データベース アプリケーションは、アプリケーション システムに不可欠な部分です。リレーショナル デー...

MySQLデータベースは何をするのか

MySQL は、スウェーデンの会社 MySQL AB によって開発されたリレーショナル データベース...

Centos6でgitlabを構築する方法

序文元のプロジェクトは、パブリックネットワークgitlabに配置されていました。セキュリティ上の理由...

jQueryは検証コード送信のコントロールボタンを無効にする機能を実装します

必要な効果: 確認コードを送信するためにクリックした後、ボタンは無効になり、5 秒後に無効解除されま...

VMware ESXi サーバー仮想化クラスター

目次まとめ環境とツールの準備サーバー仮想化のインストール VMware ESXi仮想マシンのオペレー...

Windows に WSL をインストールして構成する方法

WSLとはBaidu 百科事典からの一節を引用します。 Windows Subsystem for ...