Vue CLIで自動生成されるmain.jsを読む

# はじめに
この記事ではVue CLIの`vue create`コマンドでプロジェクトを作成した際に自動で生成される`main.js`の中に記述されている数行のコードは何をする処理なのか読み解きます。
render関数の使い方やVue.configの各種設定には踏み込みません。

利用するVueのバージョンは2.x、Vue CLIは3.xです。


読む前にVue CLIを利用して適当なプロジェクトを作成することをおすすめします。
`vue create プロジェクトの名前`でプロジェクトを作成。
`cd プロジェクトの名前`
`npm run serve`でローカルで開発サーバーを利用して起動。

# main.js　？
Vue CLIを利用してvueのプロジェクトを作成すると自動で`./src/main.js`というファイルが作成されます。
作成したプロジェクトは`main.js`をエントリーポイントとして動きます。

```js:main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

6行をほどの記述の中のimport文を除く以下の4つに分けて何をしているのか読んでいきます。
`Vue.config.productionTip`
`new Vue`
`render: h => h(App)`
`.$mount('#app')`

#Vue.config.productionTip
公式ドキュメントによると
"これを false に設定すると、 Vue の起動時のプロダクションのヒントが表示されなくなります。"とのこと。
https://jp.vuejs.org/v2/api/index.html#productionTip

ここで言われるプロダクションのヒントとは何かを見てみます。
`Vue.config.productionTip`にtrueを指定してブラウザの開発者ツールでconsoleを見ると下のように
development modeで起動していることを知らせるメッセージが出ます。
これが「起動時のプロダクションのヒント」です。
<img width="338" alt="スクリーンショット 2019-12-23 22.45.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191180/51b63bcd-6f83-b3d7-2c85-a114ab7fbed0.png">


productionモードにするとこのような警告の出力はなくなりアプリの負荷を軽減できます。
https://vuejs.org/v2/guide/deployment.html#Turn-on-Production-Mode

productionTipのON/OFFで表示を切り替えられるメッセージは上であげたもの以外に見つかりませんでした。
メッセージ１つだけを切り替えるだけの設定でもなさそうなんですが...
(Vueのソース内でも探しましたが上記のメッセージ以外見つけられず...知ってるかた教えてください...)


#new Vue
シンプル。
[Vueのインスタンスを作成](https://jp.vuejs.org/v2/guide/instance.html#Vue-%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90)しています。


#render: h => h(App)
まず書き方が構文的に分かりづらいので書き下します。
ちょうどこの部分について触れたissueがありました。
https://github.com/vuejs-templates/webpack-simple/issues/29#issuecomment-312902539
issue内であるように、下のように書き下すことができます。

```
render: function (createElement) {
    return createElement(App);
}
```

render関数の引数にはVueインスタンスのcreateElement関数が来ていて、`h`と省略されています。
※`h`はHyperscriptの略で仮想dom実装の中で一般的に使われるんだとか。
https://github.com/vuejs/babel-plugin-transform-vue-jsx/issues/6#issuecomment-232994673


ここで登場する[render](https://jp.vuejs.org/v2/api/#render)はhtmlを描画するための関数です。
公式ドキュメントによると`render`は[template](https://jp.vuejs.org/v2/api/#template)の代替として利用できるものとされており
`template`を利用して以下のように書き換えることもできます。

```js:main.js
// import Vue from 'vue'
import Vue from "vue/dist/vue.esm.js";
import App from './App.vue'

Vue.config.productionTip = true

// new Vue({
//   render: h => h(App),
// }).$mount('#test')

new Vue({
  components: { App },
  template: '<App />'
}).$mount('#test')
```

templateを用いて書いた場合、事前にJavaScriptレンダリング関数にコンパイルされる必要があります。
importでVueに`vue.esm.js`を利用するように書き変えたのは[vueのビルド](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)がランタイム限定ビルドを利用するのを回避するためで、この記述がなければ画面には何も表示されなくなります。


vueのランタイム限定ビルドは完全版(コンパイラ込み)のビルドに比べておよそ30%軽量なため利用可能なら利用することが推奨されています。
[ランタイム + コンパイラとランタイム限定の違い](https://jp.vuejs.org/v2/guide/installation.html#%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0-%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%81%A8%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E9%99%90%E5%AE%9A%E3%81%AE%E9%81%95%E3%81%84)

[描画関数とJSX](https://jp.vuejs.org/v2/guide/render-function.html#%E5%9F%BA%E6%9C%AC)の項目に`Vue ではほとんどの場合 HTML をビルドするためにテンプレートを使うことが推奨されます`と書かれているため、なぜ`main.js`でrender関数を利用するのか疑問でしたが
ランタイム限定ビルドを利用するのがモチベーションかなと考えています。
(明確な理由を探したが見つからないので知ってる方教えてください)


引数の`createElement`はVueインスタンスの関数で、指定されたパラメータの情報を元に生成した仮想DOMを返します。



#.$mount('#app')
[vm.$mount( [elementOrSelector] )](https://jp.vuejs.org/v2/api/index.html#vm-mount)によると
`Vue インスタンスがインスタンス化において el オプションを受け取らない場合は、DOM 要素は関連付けなしで、”アンマウント(マウントされていない)” 状態になります。vm.$mount() は アンマウントな Vue インスタンスのマウンティングを手動で開始するために使用することができます。`
とのこと。

これだけ読んでもわかりにくいので
わかりやすくするために、少しコードを書き換えます。
`./public/index.html`を見ると下のような記述があります

```html:index.html
  <body>
    <noscript>
      <strong>We're sorry but vue-banner doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
```
ここの

```html
<div id="app">
```
を下のように書き換えてみてください

```html
<div id="hoge">
```

何も表示されなくなります。
続けて`main.js`の

```js
.$mount('#app')
```

を下のように書き換えてみてください。

```js
.$mount('#hoge')
```

再び`App.vue`の内容が表示されるようになります。
この時点で気づくかもしれませんが
この`vm.$mount()`は引数のセレクタで指定したhtml要素の子要素にVueインスタンスを挿入します。
`main.js`を下のように[elオプション](https://012-jp.vuejs.org/api/options.html#el)を利用する形式に書き換えても同様に`<div id="hoge">`の子要素としてVueインスタンスが挿入されます。

```js:main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = true

new Vue({
  el: '#hoge',
  render: h => h(App),
})
```

また、`elオプション`と`vm.$mount()`が同居した場合は`elオプション`が優先されます。

```js:main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = true

new Vue({
  el: '#hoge',
  render: h => h(App),
}).$mount('#fugafuga')

```

※優先されるものの`vm.$mount()`が無効化されたわけではないようで、警告が出ました。
<img width="1411" alt="スクリーンショット 2019-12-24 22.28.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191180/28d9743f-4602-1b38-b048-3dcdb0050b83.png">


たった6行のコードしか書かれていない`main.js`でしたが、ちゃんと読むとなると結構読み応えあって面白かったです。
年末年始の暇な時にでも、もっと深く読み込んでみたい。

それではよいクリスマスを

$\huge{🎅メリークリスマス!!!!🎄}$

【参照】
[renderの実装](https://github.com/vuejs/vue/blob/2.6/src/core/instance/render.js)
[createElementの実装](https://github.com/vuejs/vue/blob/2.6/src/core/vdom/create-element.js)