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 コンテナが突然接続に失敗する問題のトラブルシューティング プロセス

推薦する

Linuxファイアウォールiptablesの詳細な紹介、設定方法と事例

1.1 iptablesファイアウォールの概要Netfilter/Iptables (以下、Ipta...

Linux\Nginx 環境での仮想ドメイン名の設定とテスト検証

Nginx 仮想ドメイン名設定を使用すると、ドメイン名を購入せずに特定のドメイン名を介してローカル ...

Javascript実践におけるコマンドモードの詳しい説明

目次意味構造例カスタムショートカットキー元に戻すとやり直し録音と再生マクロ要約する意味リクエストをオ...

ボリュームを使用してホストと Docker コンテナ間でファイルを転送する方法

以前、Docker コンテナとローカル マシン間のファイル転送に関する記事を書きました。しかし、この...

nginx パニック問題の解決方法の詳細な説明

nginx パニック問題に関しては、まず nginx の起動プロセス中に、マスター プロセスが構成フ...

MYSQLについては、データ型と操作テーブルを知る必要があります

データ型と操作データテーブル1.1 MySQL 型: 整数 1.2 MySQL データ型: 浮動小数...

MySQL で高性能なインデックスを作成するための完全な手順

目次1. インデックスの基本1. インデックスの種類1.1 Bツリーインデックス1.2 ハッシュイン...

Mysql 8.0.17 winx64バージョンのインストール中に発生した問題を解決する

1. my.iniファイルを手動で作成して追加する # クライアントセクション # --------...

初心者向けWebサイト構築ガイド⑥:FlashFXPの詳しい使い方

今日は、サイトの設定やウェブサイトのアップロードなど、FlashFXP の最も基本的な機能を紹介しま...

Tomcat ソースコード起動コンソールの中国語文字化けのデバッグプロセス記録

問題を見つける今日はTomcatのソースコードを勉強するつもりなので、公式サイトからTomcatのソ...

JavaScript デザインパターン プロキシパターンの学習

目次概要実装保護エージェント仮想エージェント画像の遅延読み込みを実現する仮想プロキシ概要プロキシ パ...

Tomcat でタイムアウトしたセッションを監視および削除する方法

序文偶然、30 分の Tomcat セッション時間は、セッションが作成された後、30 分間のみ有効で...

Linux でスワップ領域を確認する 5 つのコマンドの概要

序文Linux では、スワップ パーティションとスワップ ファイルの 2 種類のスワップ領域を作成で...

Reactの二次連携を実現する方法

この記事では、二次リンクを実現するためのReactの具体的なコードを参考までに共有します。具体的な内...

Dockerでランナーコンテナを構成する方法

1. ランナーコンテナを作成する mk@mk-pc:~/Desktop$ docker run -d...