Vue3のサンドボックスの仕組みの詳しい説明

Vue3のサンドボックスの仕組みの詳しい説明

序文

vue3サンドボックスには主に2つの種類があります

  1. ブラウザでコンパイルされたバージョンは、with構文とプロキシインターセプションを使用します。
  2. ローカルのプリコンパイル済みバージョンでは、テンプレートのプリコンパイル フェーズ中に transformExpression プラグインを使用して、非ホワイトリスト識別子をコンポーネント プロキシ オブジェクトの下に配置します。

ブラウザコンパイル版

レンダリング関数のコンパイル結果

<div>{{テスト}}</div>
<div>{{Math.floor(1)}}</div>

Vue を継承します。

関数 render(_ctx, _cache, $props, $setup, $data, $options) を返します {
  (_ctx) で{
    定数{
      表示文字列: _表示文字列、
      作成VNode: _createVNode、
      フラグメント: _Fragment、
      オープンブロック: _openBlock,
      ブロックの作成: _createBlock、
    } = _Vue;

    戻る (
      _openBlock(),
      _createブロック(
        _断片、
        ヌル、
        [
          _createVNode("div", null, _toDisplayString(test), 1 /* テキスト */),
          _createVNode(
            "div",
            ヌル、
            _toDisplayString(Math.floor(1))、
            1 /* テキスト */
          )、
        ]、
        64 /* 安定フラグメント */
      )
    );
  }
};

上記のコードから、変数識別子にプレフィックスが追加されておらず、スコープ チェーンを拡張するために with 構文でラップされているだけであることがわかります。では、js サンドボックス インターセプションはどのように実現されるのでしょうか。たとえば、変数 test です。理論的には、現在のスコープ チェーンには test 変数はありません。変数は、グローバル スコープが見つかるまで、前のスコープから検索されます。ただし、実際には、_ctx でのみ検索されます。原理は非常に単純です。_ctx はプロキシ オブジェクトです。では、Proxy を使用してインターセプトするにはどうすればよいでしょうか。サンプル コードは次のとおりです。

定数 GLOBALS_WHITE_LISTED =
  「無限大、未定義、NaN、isFinite、isNaN、parseFloat、parseInt、decodeURI」+
  「decodeURIComponent、encodeURI、encodeURIComponent、Math、Number、Date、Array」+
  "オブジェクト、ブール値、文字列、正規表現、マップ、セット、JSON、Intl、BigInt";

const isGloballyWhitelisted = (キー) => {
  GLOBALS_WHITE_LISTED.split(",").includes(key); を返します。
};

const hasOwn = (obj, キー) => {
  Object.prototype.hasOwnProperty.call(obj, key) を返します。
};

定数 origin = {};
const _ctx = 新しいプロキシ(origin, {
  get(ターゲット、キー、受信者) {
    if (hasOwn(ターゲット、キー)) {
      Reflect.get(ターゲット、キー、レシーバー);
    } それ以外 {
      コンソール.警告(
        `レンダリング中にプロパティ ${JSON.stringify(key)} がアクセスされました ` +
          `ただし、インスタンスでは定義されていません。`
      );
    }
  },
  has(ターゲット, キー) {
    // グローバル オブジェクトの場合は false を返し、get インターセプションをトリガーせず、前のスコープから変数を検索します。// グローバル オブジェクトでない場合は true を返し、get インターセプションをトリガーします。 return !isGloballyWhitelisted(key);
  },
});

コードは非常にシンプルですが、なぜこのようなシンプルなコードで傍受が実現できるのでしょうか? with ステートメントは has インターセプションをトリガーするため、has が true を返すと、プロキシ オブジェクトの get インターセプションがトリガーされます。false を返すと、プロキシ オブジェクトの get インターセプションはトリガーされず、変数は現在のプロキシ オブジェクトで検索されず、上位スコープで直接検索されます。

ローカルプリコンパイルバージョン

<div>{{テスト}}</div>
<div>{{Math.floor(1)}}</div>

輸入 {
  toDisplayString を _toDisplayString として、
  createVNode を _createVNode として、
  フラグメントとしての_Fragment、
  openBlock を _openBlock として、
  createBlock を _createBlock として、
} から "vue" へ;

エクスポート関数 render(_ctx, _cache, $props, $setup, $data, $options) {
  戻る (
    _openBlock(),
    _createブロック(
      _断片、
      ヌル、
      [
        _createVNode("div", null, _toDisplayString(_ctx.a), 1 /* テキスト */),
        _createVNode(
          "div",
          ヌル、
          _toDisplayString(Math.floor(1))、
          1 /* テキスト */
        )、
      ]、
      64 /* 安定フラグメント */
    )
  );
}

上記のコードから、ホワイトリストに含まれない識別子には _ctx 変数がプレフィックスとして付けられていることがわかります。では、これはどのように行われるのでしょうか?テンプレートをローカルでコンパイルすると、変換フェーズ中に変数式ノード NodeTypes.SIMPLE_EXPRESSION がプレフィックスとして付加されます。サンプル コードは次のとおりです。

定数 GLOBALS_WHITE_LISTED =
  「無限大、未定義、NaN、isFinite、isNaN、parseFloat、parseInt、decodeURI」+
  「decodeURIComponent、encodeURI、encodeURIComponent、Math、Number、Date、Array」+
  "オブジェクト、ブール値、文字列、正規表現、マップ、セット、JSON、Intl、BigInt";

const isGloballyWhitelisted = (キー) => {
  GLOBALS_WHITE_LISTED.split(",").includes(key); を返します。
};
const isLiteralWhitelisted = (キー)=>{
  'true,false,null,this'.split(',').includes(key) を返します。
}
エクスポート関数 processExpression(
  ノード
){
  const rewriteIdentifier = (raw) => {
    `_ctx.${raw}` を返す
  }
  定数rawExp = ノード.content
  if (isSimpleIdentifier(rawExp)) {
    const isAllowedGlobal = isGloballyWhitelisted(rawExp)
    定数 isLiteral = isLiteralWhitelisted(rawExp)
    if (!isAllowedGlobal && !isLiteral) {
      ノードのコンテンツ = rewriteIdentifier(rawExp)
    }
    戻りノード
  }

もちろん、上記のコードは簡略化されたバージョンにすぎません。元のプラグインでは、__props $setup を正確にしたり、変数クエリパスを短縮したり、パフォーマンスを向上させたり、矢印関数などの複雑な式を babel 経由でコンパイルしたりもしています。

要約する

vue3 js サンドボックスのメカニズム全体が説明されています。ブラウザーでコンパイルされたバージョンは、ステートメント変数クエリでインターセプトできることを知らなかったため、長い間私を悩ませていました。

以上がvue3のサンドボックスの仕組みの詳しい説明です。vue3のサンドボックスの仕組みについてさらに詳しく知りたい方は、123WORDPRESS.COM内の他の関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • springboot+vue+ドッキング Alipay インターフェース+QR コードスキャン決済機能 (サンドボックス環境)
  • Vue は複数の方法で js ファイルを参照します (推奨)
  • Vueルーティングジャンプの4つの方法の詳細な説明(パラメータ付き)
  • Vue の親コンポーネントと子コンポーネント間の通信の例 (props、$ref、$emit)
  • Vue props の使い方の詳しい説明(要約)
  • Vue プロジェクトで現在のページを更新する 3 つの方法
  • Vue の Props 属性の簡単な理解
  • VUE 要素の非表示と表示 (v-show ディレクティブ)
  • Vueはファイルアップロード機能を実装します
  • Vueを使用して写真をアップロードする3つの方法
  • 一般的な Vue.js 命令の概要 (v-if、v-for など)

<<:  英語の単語の出現頻度を数えるtrコマンドの魔法

>>:  MySQL で浮動小数点データを文字データに変換するときに起こりうる問題の詳細な説明

推薦する

JavaScript によるダイナミッククリスマスツリーの詳細な説明

目次1. CSS のみを使用して作成したアニメーションのクリスマスツリー2. CSS のみを使用して...

MySQL の binlog ログと、binlog ログを使用してデータを回復する方法を説明します。

ご存知のとおり、binlog ログは MySQL データベースにとって非常に重要です。万が一、データ...

ウェブページでメモの詳細が灰色になる問題に対処する

1. IE では、相対的な配置、つまり <div style="background...

CentOS7仮想マシンで固定IPアドレスを設定する方法

私の開発環境は、VMWare 仮想マシンに CentOS をインストールし、ホスト ファイルにインタ...

LinuxシステムでのSystemC環境設定方法

以下はcentos7での設定方法ですsystemc ソース パッケージをダウンロード: System...

HTML マルチメディア アプリケーション: Web ページにフラッシュ アニメーションと音楽を挿入する

1. HTML_falshアニメーションでのマルチメディアの応用(WebページへのFlashアニメー...

JavaScript の setTimeout() の使用法の概要

目次1. はじめに2. setIntervalとsetTimeoutの違い3.タイムアウトを設定する...

MySQLカスタム関数とストアドプロシージャの詳細な説明

序文この記事では主にMySQLのカスタム関数とストアドプロシージャに関する関連コンテンツを紹介し、皆...

Linux 7.7 でスワップ パーティション SWAP を設定する方法

Linux システムの Swap パーティション、つまり swap パーティションは、一般に仮想メモ...

vue.js 動的コンポーネントの詳細な説明

:動的コンポーネントv-bind:is="component name" を使用...

Linux で AIDE に基づいてファイルシステムの整合性を検出する方法

1. 補助AIDE (Advanced Instruction Detection Environm...

テーブルタグ(TAGS)の詳細な紹介

テーブルの基本構文<table>...</table> - テーブルを定義し...

MySQLの3つの用途と違いは同等ではない

MySQLでは判定記号がよく使われますが、等しくない記号はもっと一般的に使われます。次の3つの等しく...

Linux での SSH パスワードフリーログイン設定の詳細な説明

Linux サーバー A と B が 2 台あり、一方のサーバーから SSH 経由でパスワードなしで...