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

推薦する

Windows Server 2008 のサーバー パフォーマンス監視に関するチュートリアル

次に、ログ管理、ログのアーカイブ、ログのトラブルシューティング、イベントの転送と収集のためのコンピュ...

CentOS に MySQL をインストールしてリモート アクセスを設定する方法

1. MySQLリポジトリソースをダウンロードする$ wget http://repo.mysql....

Nginxリバースプロキシ設定でプレフィックスが削除される

nginx をリバース プロキシとして使用する場合、リクエストをそのまま次のサービスに転送するだけで...

js キャンバスはスライダー検証を実現します

この記事の例では、スライダー検証を実装するためのjsキャンバスの具体的なコードを参考までに共有してい...

Vueは製品の拡大鏡効果を実現します

この記事の例では、製品の拡大鏡効果を実現するためのVueの具体的なコードを共有しています。具体的な内...

HTML での Li タグの使用例

タイトルを左に、日付を右に揃えたいのですが、日付の範囲に float:right を直接追加すると、...

Linuxのip netnsコマンドを使用してネットワークポートを分離し、IPアドレスを設定します。

1. 分離マーカーを追加します。 ip netns add fd 2. 指定されたネットワーク カ...

JS 配列の重複を排除する 9 つの高度な方法 (実証済みで効果的)

序文一般的な方法はここには記載されていませんが、等しいかどうかを判断するための二重ループや、比較のた...

Ant Design Pro ログイン機能にグラフィック検証コード コンポーネントを統合する方法

序文:この記事では、Ant Design Proログイン機能にグラフィック検証コードコンポーネントを...

mysql バッチで大量のデータを削除する

mysql バッチで大量のデータを削除する1000万件のレコードを持つテーブル(syslogs)があ...

HTMLフォームタグチュートリアル(1):

フォームは、動的な Web ページを実装するための主要な外部フォームです。フォームとフォーム フィー...

Ubuntu 18.04にmysql5.7をインストールする

Ubuntu 18.04では参考までにmysql 5.7をインストールします。具体的な内容は以下のと...

CentOS 7 で grub パスワードと単一ユーザー ログインを設定するサンプル コード

Centos7 と Centos6 では、GRUB パスワードの設定手順に大きな違いがあります。これ...

MySQL サーバーにおける SSD パフォーマンスの問題の詳細な分析とテスト

【質問】 HP サーバーを使用しています。SSD が IOPS 約 5000 を書き込むと、%uti...

MySQL マルチバージョン同時実行制御メカニズム (MVCC) ソースコードの詳細な説明

目次1. はじめに2. MVCC (マルチバージョン同時実行制御メカニズム) 2.1 繰り返し読み取...