弁護士ドットコム株式会社 Creators’ blog

弁護士ドットコムがエンジニア・デザイナーのサービス開発事例やデザイン活動を発信する公式ブログです。

Vue2.7アップデートに伴うv-deep移行で詰まったところ

こんにちは。弁護士ドットコム クラウドサイン事業本部 Product Engineering 部の林と申します。執筆時点では入社1か月の新入社員です。もちろん入社してはじめて書く技術ブログですが、新参者でも臆せず発信できる組織ということをアピールしつつ、ジョインしたての業務で学んだことを整理します。

Vue2.7へのアップグレードに伴うv-deep移行作業の背景

現在、クラウドサインのフロントエンドは Vue2 で実装されています。Vue2はサポート期限が近づいているのもあり、Vue3 へのバージョンアップが望まれます。ただ巨大なシステムを一気に Vue3 に移行するのは難易度が高いため、段階的移行のために Vue2.7 にする活動が進んでいます。

その中で私はv-deepセレクタが使用されていたコンポーネントを Vue2.7 に対応させるタスクを担当しました。従来の::v-deepが使えなくなるため、新たなdeepセレクター:deep()に置き換える作業です。(deep セレクタの詳細はリンク先をご参照ください)

基本的には公式ドキュメントの示す例のとおり

.a ::v-deep .b {
  /* ... */
}

上記を

.a :deep(.b) {
  /* ... */
}

のように置き換えるという、そこまで難しくない作業になるはずでした。

v-deepを:deep()に移行する際に詰まったところ

作業を進める中で下記のようなコードがありました。

.hoge {
  & ::v-deep svg path,
  i {
    fill: #fff;
  }
}

このセレクタをどう変換するか考えたとき、v-deepはどのような範囲でセレクタに影響するか分からず、当初は下記のようにしました。

.hoge {
  & :deep(svg path, i) {
    fill: #fff;
  }
}

しかし、これだと元のセレクタとは等価にはなりませんでした。

ブラウザの開発ツールで対象 DOM に当たっているセレクタを確認すると、元の& ::v-deep svg path, i {}の方だと

.hoge[data-v-xxxxxxxx] svg path, .hoge i[data-v-xxxxxxxx]

ですが、& :deep(svg path,i) {}とすると

.hoge[data-v-xxxxxxxx] svg path

となっており、iに対するセレクタが消失してしまいました。

これはただ:deep()の使用方法が違っていただけという話ですが、では::v-deep:deep()はセレクタ結合に対してどのような範囲で適用されるのでしょうか。

正しい:deep()の適用範囲

結論、このように記述することで従来と等価なセレクタにすることができました。

.hoge {
  & :deep(svg path),
  i {
    fill: #fff;
  }
}

ブラウザの開発者ツールで観測したセレクタはこちらです。

.hoge[data-v-xxxxxxxx] svg path, .hoge i[data-v-xxxxxxxx]

つまり、& ::v-deep svg path, i {}というセレクタ指定だと、子孫結合子で結合されたセレクタには纏めて deep セレクタの影響がおよび、セレクターリストを跨いだ右辺のセレクタには影響を及ぼさないということです。

そのため、:deep(svg path)iで分けることが正解であったということですね。

分解して表現するとこのようになります。

.hoge ::v-deep svg path {}
.hoge i {}

こうすると、セレクターリストでsvg pathiは分かれていて、結合子によって結合されていたsvg pathのみにv-deepが影響していたことが分かりやすいかなと思います。

ちなみに(GPT-4に聞いてみた)

正解は検証してみるまで分からなかったのですが、その前に流行りのGPT-4Web Browsingを使って回答を生成してみました。プロンプトは下記のような感じです。

あなたは最新のVue.jsの知見を持ったフロントエンドエンジニアです。以下のscssコードをVue3に合った形で`:deep()`を使う形で変換して下さい。

{変換前コード}

すると

.hoge {
  :deep(svg path),
  :deep(i) {
    fill: #fff;
  }
}

と返してきました。確かに deep セレクタの影響がセレクターリストを跨ぐのであれば、こうなってもおかしくないですよね。

こちらのセレクタをブラウザの開発者ツールで観測するとこうなります。

.hoge[data-v-xxxxxxxx] svg path, .hoge[data-v-xxxxxxxx] i

割とおしいですよね。セレクターリストの両方に deep セレクタが適用されていることが分かります。 しかし元のセレクターはsvg pathにのみ deep セレクタが適用されておりiに適用してはいけなかったため、等価なセレクタにはなりません。

※社外秘の情報はChatGPTには入力しないようにしています。

まとめ

業務を通じて Vue2 から Vue2.7 もしくは Vue3 にバージョンアップする際のv-deepの扱いと影響範囲を知ることができました。

  • deep セレクタを Vue3(Vue2.7)に移行する方法
  • 新しい deep セレクター:deep()の使い方
  • deep セレクタのセレクターリストに対する影響範囲

今後もプロダクトの Vue3 への完全なバージョンアップに貢献していきたいと考えています。