イベント修飾子
Vue はテンプレート修飾子を withModifiers(...) や withKeys(...) のような runtime helper に
コンパイルします。これらの helper は本来、実際のブラウザ Event を前提に動作します。
@omnicajs/vue-remote では、ネイティブイベントは host 側で購読され、その後シリアライズされて
remote callback に送られます。つまり remote 側が受け取るのは元の DOM event instance ではなく、
そのシリアライズ済み snapshot です。
そのため、標準の Vue helper だけでは remote template の修飾子を正しく扱えません:
preventDefault()やstopPropagation()のような命令的メソッドはシリアライズ済み payload には存在しない;.selfのようにイベントの live identity に依存する判定は plain snapshot からは安定して再現できない;- key / pointer / modifier guard に必要なフィールドが host serializer で明示的に残されていないと不足する;
- そのままの Vue helper が transported payload に対して動くと、修飾子コードが誤動作したり runtime error になったりする。
解決策は、ビルド時に修飾子 metadata を保持し、シリアライズ前に host 側でネイティブイベント依存の 処理を適用することです。以下の webpack loader と Vite plugin はそのためのものです。
何が動くか
見出しへのリンク書き換えを有効にすると、リモートテンプレートと render function で次を維持できます:
.capture、.once、.passiveなどのイベントオプション修飾子;.stop、.prevent、.selfなどの伝播 / 既定動作の修飾子;.enter、.left、.right、.ctrl、.alt、.shift、.meta、.exactなどのキー / ポインタガード。
修飾子のない通常のリスナーは従来のトランスポート経路を使い続けます。
transform が見る必要のあるもの
見出しへのリンク修飾子を正しく復元するには、バンドラ側の transform が次を見られる必要があります:
Widget.remote.vueのようなリモート SFC のソース;- それらの SFC から生成される Vue サブモジュール、特に
template、script、scriptSetupの request; main.remote.tsやpanel.remote.tsxのような単独のリモートエントリファイル。
このどれかが抜けると、テンプレート自体はコンパイルできても、修飾子の挙動は runtime で戻りません。
webpack の設定
見出しへのリンクwebpack では、このリモート loader を vue-loader の置き換えではなく補助として扱います。
SFC のコンパイルは引き続き vue-loader が担当し、@omnicajs/vue-remote/webpack-loader
はリモートエントリを追跡して、生成済みモジュール内の helper import を書き換えます。
実際の webpack 設定では、次の 3 点が必要です:
- 元の
.vueソースをリモート loader に通して<script remote>と<script setup remote>を検出する; - 標準の
vue-loaderルールとVueLoaderPluginを維持する; - 生成された Vue モジュール request と単独の
.remote.ts/.remote.jsエントリファイルに対してリモート loader を実行する。
設定例:
const { VueLoaderPlugin } = require('vue-loader')
module.exports = { module: { rules: [ { test: /\.vue$/, enforce: 'pre', loader: '@omnicajs/vue-remote/webpack-loader', }, { test: /\.vue$/, loader: 'vue-loader', }, { test: /\.vue$/, resourceQuery: /vue.*type=(?:template|script|scriptSetup)/, loader: '@omnicajs/vue-remote/webpack-loader', }, { test: /\.remote\.(?:[cm]?[jt]sx?)$/, loader: '@omnicajs/vue-remote/webpack-loader', }, ], }, plugins: [ new VueLoaderPlugin(), ],}この構成で得られること:
Widget.remote.vueはファイル名だけでリモート SFC として認識される;- 通常の
Widget.vueも<script remote>または<script setup remote>で opt in できる; - 生成された Vue の
template/scriptモジュールでwithModifiers(...)とwithKeys(...)の import が書き換えられる; main.remote.tsのような単独のリモートエントリも同じ書き換え経路に乗る。
既存の webpack 設定で oneOf 分岐やフレームワーク固有の rule generator を使っている場合でも、
考え方は同じです。リモート loader は元の SFC request と生成された Vue モジュール request の両方を見る必要があります。
Vite の設定
見出しへのリンクVite では、リモート plugin を @vitejs/plugin-vue と一緒に登録します:
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import { vueRemoteVitePlugin } from '@omnicajs/vue-remote/vite-plugin'
export default defineConfig({ plugins: [ vue(), vueRemoteVitePlugin(), ],})実運用では次を推奨します:
vue()は通常どおり SFC コンパイラとして残す;vueRemoteVitePlugin()を同じ Vite 設定に追加し、生成された Vue モジュールを観測 / 書き換えできるようにする;- 明示的なリモートエントリには
*.remote.vueを使うか、通常の SFC を<script remote>/<script setup remote>でマークする; - SFC 以外のエントリスクリプトには
*.remote.ts、*.remote.js、*.remote.tsx、*.remote.jsxを使う。
内部の書き換えロジックは webpack loader と共有されるため、修飾子の意味論は両方の bundler で揃います。
authoring と tooling の注意
見出しへのリンク- リモートネイティブ template ref 推論は
@omnicajs/vue-remote/toolingで別途設定します。 - テンプレートの修飾子はネイティブ DOM ノードと
defineRemoteComponent(...)で定義した host Vue components の両方で動作します。 - 手書きの render function では
@omnicajs/vue-remote/remoteがエクスポートする同じ helper を使えます。
次に読むもの
見出しへのリンク- 初期セットアップ: クイックスタート。
- host 側の契約: ホストコンポーネント。
- remote 側の UI モデリング: リモートコンポーネント。