【Vue 2.x】Vueコンストラクタ関数をWebコンソール上で見つける方法

# Vue コンストラクタ関数とは？
[Vue.js](https://jp.vuejs.org/index.html) 2.x 系を [webpack](https://webpack.js.org/) などのバンドラと共に使用している方にとっては、この `Vue` のことです:

```javascript
import Vue from 'vue';
       ^^^
```

`<script>` タグを貼り付けるだけのいわゆる「CDN版」の Vue.js を利用している場合は `window.Vue` で簡単に Vue コンストラクタ関数を参照できますが、バンドラを用いてビルドされている場合においても Vue コンストラクタ関数を参照できる方法を紹介します。

<img width="588" alt="vue_constructor_func_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137045/bf0be878-f2c8-e2c7-f851-c47e582ae05b.png">

# 動作環境
- Vue.js 2.6.11 などの Vue.js 2.x 系
- Chrome 80
  - Vue.js devtools 5.3.3

# Vue コンストラクタ関数の参照を得る方法
以下のスクリプトをWebコンソール上で実行することで、Vue コンストラクタ関数を参照することができます:

```javascript
const Vue = (() => {
  const el = [].find.call(document.all, el => el.__vue__);
  if (!el) {
    return;
  }
  let Vue = Object.getPrototypeOf(el.__vue__).constructor;
  while (Vue.super) {
    Vue = Vue.super;
  }
  return Vue;
})();
```

Vue 公式のブラウザ拡張である [Vue.js Devtools の実装](https://github.com/vuejs/vue-devtools/blob/v5.3.3/packages/shell-chrome/src/detector.js)を参考にしました。
Internet Explorer 11 に対応した実装が必要であれば、[こちらの Gist](https://gist.github.com/mascii/f3452ad00fc49406e19cc956159a1a69) を参照してください。

# 応用
## プロダクションビルドされていても Vue.js Devtools を有効にする
2019年6月に Apple の [SwiftUI のチュートリアルサイト](https://developer.apple.com/tutorials/swiftui/)が Vue.js で構築されていることが話題になりましたが、プロダクションビルドされたものにも関わらず Vue.js Devtools が有効となっていることにも驚いた方が多かったようです。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">.<a href="https://twitter.com/Apple?ref_src=twsrc%5Etfw">@Apple</a> is using <a href="https://twitter.com/vuejs?ref_src=twsrc%5Etfw">@vuejs</a> <a href="https://t.co/RGZ6TIWjMj">pic.twitter.com/RGZ6TIWjMj</a></p>&mdash; Rahul Kadyan (@znck0) <a href="https://twitter.com/znck0/status/1135651853776052224?ref_src=twsrc%5Etfw">June 3, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">Add debugger before new Vue() then set Vue.config.devtools = true and continue!<br><br>You have to find new Vue() in minimised code. Here search for `new n["a"]`.</p>— Rahul Kadyan (@znck0) <a href="https://twitter.com/znck0/status/1135656191986552833?ref_src=twsrc%5Etfw" target="_blank" rel="noopener noreferrer">June 3, 2019</a>
</blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この Twitter のやりとりをご覧になった [@mottox2](https://twitter.com/mottox2) さんがブレークポイントを挿入して Vue コンストラクタ関数を見つける方法[^1]を紹介されていましたが、やり方を変えたものがこちらのスクリプトとなります:


```js
(() => {
  if (!__VUE_DEVTOOLS_GLOBAL_HOOK__) {
    return;
  }
  const el = [].find.call(document.all, el => el.__vue__);
  if (!el) {
    return;
  }
  let Vue = Object.getPrototypeOf(el.__vue__).constructor;
  while (Vue.super) {
    Vue = Vue.super;
  }
  Vue.config.devtools = true;
  __VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = Vue;
})();
```

上記スクリプトをコンソールで実行後、デベロッパーツールを開き直すと "Vue" タブが出現します。

<img width="771" alt="vue_constructor_func_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137045/f27b2980-15c2-37c4-9c7c-2fd488380c25.png">

## バージョン情報の取得・ランタイム限定ビルドであるか判定する
ランタイムビルド・完全ビルドについて詳しくは[Vue.js 公式ガイドの「さまざまなビルドについて」](https://jp.vuejs.org/v2/guide/installation.html#%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%93%E3%83%AB%E3%83%89%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)を参照してください。

```js
(() => {
  const el = [].find.call(document.all, el => el.__vue__);
  if (!el) {
    return;
  }
  let Vue = Object.getPrototypeOf(el.__vue__).constructor;
  while (Vue.super) {
    Vue = Vue.super;
  }
  console.log('Vue.version:', Vue.version);
  console.log('Vue.compile:', Vue.compile);
})();
```

ランタイム限定ビルドの場合は、 `Vue.compile` が `undefined` となっています:
<img width="500" alt="vue_constructor_func_04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137045/8112cf10-dbfd-4aee-1989-37c4123ac43f.png">

完全ビルドの場合は、 `Vue.compile` が定義されています:
<img width="500" alt="vue_constructor_func_03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137045/098f86ff-6396-8dcc-3e13-f2b25083a3d2.png">

## 状態を変更したり特定のページに遷移したりする
Vue コンストラクタ関数を見つける方法と近い方法で ViewModel を見つけることもできます[^2]。
ViewModel を見つければ、特定の状態に変更したり、特定の画面に遷移することなどが可能です:

```js
(async () => {
  const $root = [].find.call(document.all, el => el.__vue__).__vue__.$root;
  await $root.$store.dispatch('HOGE_ACTION'); // Vuex
  $root.$router.push(`/fuga/path`); // Vue Router
})();
```

投稿完了画面など、実際に操作して遷移させるのが面倒な画面の CSS を書いたりするときに便利かもしれません。

[^1]: [Production modeでもVue.js Devtoolsを有効にする方法 - mottox2 blog](https://mottox2.com/posts/344)
[^2]: Vue.js Devtools を用いる方法もあります: [【Vue.js / Nuxt.js】 ブラウザのコンソールでVueオブジェクトを表示させるには - poyopoyoのブログ](https://poyopoyo0.hatenablog.com/entry/2018/11/19/202521)