vue createで挫折した人へ ～ゼロから組み立てるVue.js～

# 概要
Vue.jsを使ってみようとしたけど、サンプルコードで面食らってしまったので、いっそ`vue create`せずにゼロから書いてみる。

## 筆者の経緯
「Vue.js、流行ってるよね！ モダンだよね！ ちょっと触ってみようかな」
「npmでVue CLIをインストールして」
```sh
npm install -g @vue/cli
```
「新規プロジェクトを作成しよう」
```sh
vue create sample
```
「……なんもわからん」

## 目的
`vue create`で作成されるコードと同じ構成のものを、ゼロから組み立てながら理解する。

## 前提
HTML, CSS, JavaScriptの知識を前提とします。
モダンブラウザーを使用します。

# 本編

## サンプルコードを見る
### サンプルコード作成＋実行
とりあえず、ワークスペース上にサンプルコードを作成します。
```sh
cd ~
vue create sample -d
```
上のコマンドで、`sample`ディレクトリーが切られ、サンプルコードが作成されます。
`-d`オプションは、すべてをデフォルト設定にするというオプションです。デフォルトでVue3になります。このオプション無しでもすべてEnterで同じものができます。

サンプルコードが実行できるか確認してみます。
```sh
cd sample
npm run serve
```
実行後、 http://localhost:8080/ へアクセスして、「Welcome to Your Vue.js App」という画面が表示されれば成功です。
サービスを停止して、次へ進みます。

### ディレクトリー構成
サンプルコードのディレクトリー構成は以下のようになっています。

> sample/
 ├node_modules/
 ├public/
 │ ├favicon.ico
 │ └index.html
 ├src/
 │ ├assets/
 │ │ └logo.png
 │ ├components/
 │ │ └HelloWorld.vue
 │ ├App.vue
 │ └main.js
 ├.gitignore
 ├babel.config.js
 ├jsconfig.json
 ├package-lock.json
 ├package.json
 ├README.md
 └vue.config.js

これとだいたい同じものを作成します。
なお、`.gitignore`と`README.md`はgit管理用のファイルなので、無視します。

## ゼロから組み立てる
### イニシャライズ
まず、新しいディレクトリー`vue`を切り、移動します。
```sh
cd ~
mkdir vue
cd vue
```

npmで実行できるように、`package.json`を作成します。
`npm init`でもよいですが、今回は自力で書いてみます。

```package.json
{
  "name": "vue",
  "version": "0.1.0",
  "private": true
}
```

とりあえずこれだけ書いてあればOK。
```sh
npm install
```
を実行すると、`package-lock.json`が自動的に生成されます。


### 最初の実行

最も大事なvueをインストールします。
```sh
npm install vue
```

ローカルでサービスを実行できるように、開発者用に`vue-cli-service`を導入します。

```sh
npm install -D @vue/cli-service
```

コマンドでサービスを実行できるように、`package.json`にスクリプト(`"scripts"`)を書き込みます。

```package-lock.json
{
  "name": "vue",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve"
  },
  "dependencies": {
    "vue": "^3.2.47"
  },
  "devDependencies": {
    "@vue/cli-service": "^5.0.8"
  }
}
```

この状態で`npm run serve`を実行すると、コンパイルエラーが出ます。
```
Module not found: Error: Can't resolve './src/main.js' in ......
```

Vueを実行するためには、`main.js`が必要ということです。
コンパイルができるように、`src/main.js`を作成します。
中身は空で大丈夫です。

実行してみましょう。
```sh
npm run serve
```

実行後、 http://localhost:8080/ へアクセスすると、真っ白な画面が表示されます。
ソースを見ると以下のようになっています。
```html
<!DOCTYPE html>
<html lang="">
  <!-- 略 -->
  <body>
    <div id="app"></div>
  </body>
</html>

```

`<body>`内に`<div>`要素が一つ（idは"app"）あるので、この中に文字を入れます。
main.jsを書き換えます。

```src/main.js
let app = document.getElementById('app');
app.innerText = "Hello, world!";
```

再実行してみると、"Hello, world!" と表示されます。
Vueで単純なサービスが実行できました。

### .vue ファイルの使用

vueファイルを作って使用します。
`src`配下に`App.vue`を作成します。

```src/App.vue
<template>
  <h1>This is Vue.js!</h1>
</template>
```

main.jsを以下のように書き換えます。

```src/main.js
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
```

これで、`App.vue`の内容が反映されます。
実行すると、"This is Vue.js!" という文字が見出し（h1）で表示されます。

### スタイルの適用

画面が味気ないので、スタイルを変更します。
App.vueに`<style>`を追加します。

```src/App.vue
<template>
  <h1>This is Vue.js!</h1>
</template>

<style>
#app {
  text-align: center;
  margin-top: 60px;
  color: darkblue;
  background-color: lightblue;
}
</style>
```

これで、スタイルが適用されます。

### コンポーネントの利用

コンポーネントを作成し、利用します。
`src/`配下に`components/`ディレクトリーを切り、その配下に`HelloWorld.vue`ファイルを作成します。

```src/components/HelloWorld.vue
<template>
  <div class="hello-world">
    <h1>Hello, World!</h1>
    <p>paragraph</p>
  </div>
</template>

<style scoped>
.hello-world {
  background-color: lightpink;
  color: darkred;
}
</style>
```

HelloWorldコンポーネントができたので、インポートします。

```src/App.vue
<script setup>
import HelloWorld from "./components/HelloWorld.vue";
</script>

<template>
  <h1>This is Vue.js!</h1>
  <HelloWorld />
</template>

<style>
#app {
  text-align: center;
  margin-top: 60px;
  color: darkblue;
  background-color: lightblue;
}
</style>
```

実行すると、コンポーネントが追加されたことがわかります。
このコンポーネントに、値を受け渡す機能を付けます。

```src/components/HelloWorld.vue
<script setup>
const props = defineProps({
  msg: String,
});
</script>

<template>
  <div class="hello-world">
    <h1>{{ msg }}</h1>
    <p>paragraph</p>
  </div>
</template>

<style scoped>
.hello-world {
  background-color: lightpink;
  color: darkred;
}
</style>
```

```src/App.vue
<script setup>
import HelloWorld from "./components/HelloWorld.vue";
</script>

<template>
  <h1>This is Vue.js!</h1>
  <HelloWorld msg="Message"/>
</template>

<style>
#app {
  text-align: center;
  margin-top: 60px;
  color: darkblue;
  background-color: lightblue;
}
</style>
```

コンポーネントに"Message"と表示されるようになります。

### ファビコンを追加・ページ名を追加

ファビコンを利用するために、`index.html`を作成します。
`public/`ディレクトリーを切り、`index.html`と`favicon.ico`を格納します。
`favicon.ico`は好きな画像ファイルを用意します。

```public/index.html
<html>
  <head>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
```

サーバーを一度停止し、ブラウザーのキャッシュを削除してから、もう一度開くと、ファビコンとページ名が設定されています。

### サンプルページに近づける

以下の変更を加えると、サンプルページとほぼ同じ見た目のものになります。

```src/App.vue
<script setup>
import HelloWorld from "./components/HelloWorld.vue";
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Welcome to Your Vue.js App" />
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

```src/components/HelloWorld.vue
<script setup>
const props = defineProps({
  msg: String,
});
</script>

<template>
  <h1>{{ msg }}</h1>
  <p>
    paragraph<br />
    <a href="http://localhost:8080" target="_blank" rel="noopener">link</a>
  </p>
  <h3>List</h3>
  <ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
  </ul>
</template>

<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

```

`src/assets/logo.png`を用意し、実行します。
これで、サンプルコードとほぼ同じものが完成します。

### 注意

一部、`<script setup>`というVue3.2の機能を使いました。
その部分だけ、サンプルコードとは違う書き方になっています。ご注意下さい。
こちらの書き方のほうが便利そうなので、今回採用しました。

## その他

* babel.config.js
* jsconfig.json
* vue.config.js

以上の3ファイルは、今回は必要としませんでした。
また、サンプルコードにはありますが、省略した部分もあります。
気になる場合は各人でお調べください。
簡単に言うとIE対応や静的解析などです。


# 最後に
筆者はとりあえず、Vue.js のサンプルコードがだいたい理解できました。
この記事がほかの人の手助けになれば幸いです。