こんにちは!りゅうです。
今回はVuejsの学習をDocker環境で行ったので、DockerとVuejsの環境構築からTODOリストを作るまでの流れを書いてみました。
この記事で実現したいこと
Docker+Vuejsの環境構築とTODOアプリを作れるようにする
参考にしたサイト
Vue.jsで作るtodoアプリ
docker-composeでシンプルにvue.js環境構築
Vueのアプリを動かすコンテナを作成していきます。
フォルダ構成は以下の通りです。serverフォルダはwebコンテナのappフォルダのマウント先です。
PS C:\Users\User\Desktop\DockerVuejs> tree /f フォルダー パスの一覧 ボリューム シリアル番号は 105F-A1E1 です C:. │ docker-compose.yml │ ├─docker │ └─web │ Dockerfile │ └─server
docker-compose.yml
version: '3.8'
services: 
    web:
        container_name: web
        build: ./docker/web
        ports: 
            - 8080:8080
        volumes: 
            - ./server:/app:cached
        tty: true
        stdin_open: true
        privileged: true
        command: /bin/sh
Dockerfile
FROM node:14.15.0-alpine WORKDIR /app RUN apk update && \ npm install && \ npm install -g npm && \ npm install -g vue-cli
docker-compose.ymlとDockerfieを作成したら、以下のコマンドでコンテナイメージの作成とコンテナの起動を実行
# イメージのビルドとコンテナ起動を同時に行う --buildは強制ビルドするオプション docker-compose up -d --build # 別々に行う場合 # イメージのビルド docker-compose build # コンテナの起動 -dはバックグラウンドで行うオプション docker-compose up -d
ビルドと起動ができたら、コンテナに入りvueのデフォルトAppを作成
# コンテナに入る docker-compose exec web /bin/sh # VueのデフォルトApp作成 /app # vue init webpack
デフォルトApp作成時、色々聞かれますが、特になければ回答はYesと基本的なパッケージを選択で問題ないです。
ホスト側のserverフォルダに色々追加されるので、その中から config>index.js を探して、修正していきます。

# hostをlocalhot→0.0.0.0 host: '0.0.0.0', // can be overwritten by process.env.HOST
# pollをfalse→true poll: true, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
pollをfalse→trueでファイルの変更を起動中に検知
デフォルトAppの作成が終わったら、以下のコマンドでAppを起動
# デフォルトAppの起動(コンテナに入った状態で実行) /app # npm run dev
localhost:8080にアクセスしてデフォルトの画面が表示されればOKです。

ポート8080が使用されている場合は使用しているものを閉じるか、 config>index.js  のport:8080 を空いているポートに変更し、docker-compose.ymlもそれに合わせて修正してあげれば、再設定したポートで表示できるようになります。
 docker-compose.ymlを修正した場合は再ビルドをお忘れなく、自分はよくやらかしてます(笑)
ポート7080で設定し直す場合
// 8080→7080 port: 7080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
ports: 
    - 7080:7080
# イメージのビルドとコンテナ起動を同時に行う docker-compose up -d --build
TODOアプリに必要なものを作成、修正していきます。
作成
 server\src\components\List.vue 
修正
server>src>App.vue
server>src>router>index.js
2つの修正ファイルから修正していきます。
<template>
  <div id="app">
    <router-view/>
  </div>
</template>
export default new Router({
  routes: [
    // /→/helloに変更
    {
      path: '/hello',
      name: 'HelloWorld',
      component: HelloWorld
    },
    // 元々のHelloWorldの3行をそのままコピペしてHelloWorldを→Listに変更
    {
      path: '/',
      name: 'List',
      component: List
    }
  ]
})
server\src\router\index.js ルーターと呼ばれどの画面に遷移するかの制御をします。
Listはこれから作成するTODOリストのファイル名(List.vue)です。
ここまでで、不要なロゴ画像の削除と、ルーターにTODOリスト画面のパスと呼び出すコンポーネントを登録しました。
TODOリストの画面部分を作成していきます。
入力部分とボタン押下時リストを追加するメソッド(ロジックは後述)をまず記述
<template>
    <div id="app">
        <h2>TODO List</h2>
        <form v-on:submit.prevent>
            <input type="text" v-model="newItem">
            <button v-on:click="addItem">Add</button>
        </form>
        <pre>{{$data}}</pre>
    </div>
</template>
<script>
export default {
  data () {
    return {
      newItem: ''
    }
  },
  methods: {
    addItem: function (event) {
      alert()
    }
  }
}
</script>
 9行目の<pre>{{$data}}</pre> で newItem の中身を確認
 addItem メソッドにalert()を書いて追加ボタン押下時のメソッド呼び出し確認

↓

addItemメソッドにロジックの追加、data()に入力内容を複数格納する配列(todos)の追加
<template>
    <div id="app">
        <h2>TODO List</h2>
        <form v-on:submit.prevent>
            <input type="text" v-model="newItem">
            <button v-on:click="addItem">Add</button>
        </form>
        <pre>{{$data}}</pre>
    </div>
</template>
<script>
export default {
  data () {
    return {
      newItem: '',
      todos: []
    }
  },
  methods: {
    addItem: function (event) {
      if (this.newItem === '') {
        return
      }
      var todo = {
        item: this.newItem
      }
      this.todos.push(todo)
      this.newItem = ''
    }
  }
}
</script>
複数追加できるか確認

↓

一覧表示のテーブル、リストのチェックと削除ボタンを追加
一覧を中央表示、文字を左寄せ、チェック後の取り消し線を<style>タグで調整
 確認できたら<pre>{{$data}}</pre>は削除 
<template>
    <div id="app">
        <h2>TODO List</h2>
        <form v-on:submit.prevent>
            <input type="text" v-model="newItem">
            <button v-on:click="addItem">Add</button>
        </form>
        <table>
            <tr v-for="(todo, key) in todos" :key="key">
                <td><input type="checkbox" v-model="todo.isDone"></td>
                <td><span v-bind:class="{done: todo.isDone}">{{todo.item}}</span></td>
                <td><button v-on:click="deleteItem(key)">Delete</button></td>
            </tr>
        </table>
    </div>
</template>
<script>
export default {
  data () {
    return {
      newItem: '',
      todos: []
    }
  },
  methods: {
    addItem: function (event) {
      if (this.newItem === '') {
        return
      }
      var todo = {
        item: this.newItem
        isDone: false
      }
      this.todos.push(todo)
      this.newItem = ''
    },
    deleteItem: function (key) {
      this.todos.splice(key, 1)
    }
  }
}
</script>
<style>
  #app table{
    margin-left: auto;
    margin-right: auto;
    text-align: left;
  }
  #app span.done{
    text-decoration:line-through;
  }
</style>
リストを3つ追加、取り消し線と削除の確認

↓

以上で、完成です。
Vuejsは初歩的な内容だったので、これを機により実用的な部分も学習できたらと思います。
それからDocker、イメージ作成時やコンテナ起動時に多少エラーで悩まされたりしますが、ローカルに一切パッケージをダウンロードせず学習が進められる点は、改めて便利だなと実感しました。
今回は以上になります。
ご覧いただき、ありがとうございました。