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 です。理論上、現在のスコープ チェーンにはテスト変数はありません。変数は、グローバル スコープが見つかるまで、前のスコープから検索されます。ただし、実際には _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 サンドボックスのメカニズム全体が説明されています。ブラウザーでコンパイルされたバージョンは、ステートメント変数クエリでインターセプトできることを知らなかったため、長い間私を悩ませていました。

参照する

プロキシハンドラには
JS のサンドボックスについて話し、JS サンドボックスを手動で記述します

vue3 サンドボックスの仕組みの詳しい説明はこれで終わりです。vue3 サンドボックスの仕組みに関するより詳しい内容については、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続きご覧ください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  Windows 環境での MySQL の解凍、インストール、バックアップ、復元

>>:  ポートマッピング後に Docker コンテナが突然接続に失敗する問題のトラブルシューティング プロセス

推薦する

MySQLが中国語の文字を挿入する問題を永久に解決するコツを教えます

目次序文最初のステップ:ステップ2: このmy.iniを変更する要約する序文問題の説明:不正な文字列...

Vuex全体のケースの詳細な説明

目次1. はじめに2. 利点3. 使用手順1. Vuexをインストールする2. Vuexを参照する3...

すべてまたは逆の選択機能を実現するJavaScript

この記事では、全選択または選択を反転する機能を実現するためのJavaScriptの具体的なコードを参...

ウェブページを最適化してメモリとCPUの使用率を削減

一部の Web ページは大きく見えなくても開くのに非常に時間がかかる場合があります。一方、他の We...

uni-appがNFC読み取り機能を実装

この記事では、参考までに、NFC読み取り機能を実装するためのuni-appの具体的なコードを紹介しま...

CSS 3.0とビデオを組み合わせることでクリエイティブなオープニング効果を実現

CSS 3.0 とビデオを組み合わせて実現したクリエイティブなオープニングをご紹介します。効果は次の...

Centos に MYSQL8.X をインストールするチュートリアル

MySQLのインストール(4、5、6は省略可能)ステートメント: CentOS のバージョンは 7....

MySQLデータベースは重複データを削除し、メソッドインスタンスを1つだけ保持します

1. 問題の紹介ユーザー テーブルに 3 つのフィールドが含まれているシナリオを想定します。 id、...

Dockerコンテナがホストポートにアクセスできない場合の解決策

最近、仕事中に問題が発生しました。Docker コンテナがホストの redis にアクセスできず、t...

CentOS 7 で yum を使用して MySQL 5.7.20 をインストールする最も簡単な方法

CentOS7 のデフォルトのデータベースは mariadb ですが、mysql を使っている人も多...

現在のマウススライドの座標を取得するVue+openlayer5メソッド

序文: Vue プロジェクトで現在のマウスの座標を取得するにはどうすればよいでしょうか。ここで共有す...

一般的なイベントを処理するための JavaScript の使用に関する詳細な説明

目次1. フォームイベント2. マウスイベント3. キーボードイベント4. 共通イベントメソッド(ウ...

Dockerコンテナ監視とログ管理の実装プロセス分析

Docker の導入規模が大きくなると、コンテナを監視する必要があります。一般的に、Docker に...

Webデザインチュートリアル(3):デザインの手順と考え方

<br />前のチュートリアル:Webデザインチュートリアル(2):模倣と盗作について。...