2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue v2.6.11のバグを発見

Last updated at Posted at 2020-02-14

Vueのバグを発見しました。

PR: https://github.com/vuejs/vue/pull/11107

事象

async componentでv-if="false"を使うと、vueのvdom処理でエラーになる。

詳細はPRのテストコード参照。

原因

vdomでは、async componentはasyncPlaceholder(コメントノード + 補助データ)として扱われる。
v-if="false"はコメントノードとして扱われる (参考: https://github.com/vuejs/vue/issues/5117 )。

patch.jsのsameVNodeでは、async componentとコメントノードが同じと判定されてしまう(これが誤り)。

sameVNodeで同じと判定されると、patchVNode処理に入り、その中のasyncFactory.resolvedで、asyncFactoryがundefinedでエラーになる。

修正

sameVNodeでasync componentとコメントノードが同じと判定されないようにする。

メモ

data-server-renderedはルートにのみつくらしい。
hydrationするときに取り除くので、hydrationは一回のみ実行される。
hydrationのときにロードできないasync componentはasyncPlaceholderにされる(つまり、async component内部はhydrationの対象外になる)。

コードを見た感じ、hydrationのときにすでにresolveされているasync componentは通常のコンポーネントとほぼ同様に処理されるみたい。

感想

nuxtでパフォチューをやっているときに遭遇した。

セキュリティ懸念(誤ってキャッシュされるとか、リクエスト間で情報が漏れるとか)から、SSRでは認証が必要なデータは取得しないようにしている。
非ログインユーザーはSSRで完結するのでクライアント側でデータ取得しなくて良い。
ログインユーザーはクライアント側でデータ取得するが、今まではmount後にリクエストを開始していて遅かったので、mount前にリクエストを開始するようにした。
それでこのバグが発生。

最初、hydrationが行われる前にリクエストが返ってきて、SSRとクライアントのdom不整合かなと思ったが、データ更新を強制的にmount後や、mount後のnextTick後にしても発生する。

vue内部のresolvedでエラーになっていることがわかったので、vueのコードを検索したらpatch.jsを発見。

async componentがresolveされる前に、v-if="false"でvdom更新されるとエラーになることを発見。

結局、パフォチューで速くなったせいで、async componentのロードとデータ更新のタイミングが逆転してバグが発生したみたい。

自分のコードが原因だと思って1日くらいかかった。
これでvueのコントリビューターの肩書を得た。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?