初心者こそ、Docker を使おう！

## 初心者こそ、Docker を使うべきです。
### 初心者こそ、Docker で　node.js の　練習環境を作って快適に練習しよう！

対象者：　dotinstall 等で javascript(node.js) を練習されているかた
        練習環境を想定していますので、ここでは本格的な環境は想定していません。
        nodeのversion管理面倒なんだけどと思っているなら、とても参考になるでしょう。
        version違うけど、動くからと思っている人には、効果が薄いかもしれません.(笑)

まぁ、node環境しかり、python環境しかり、練習する前に環境を作る手間が誰でも手間ですが、初心者にとっては苦痛の何者でもありません。
簡単なお試しであれば、ウエブ上でもできますが、ある程度好みをいれるとなるとローカル環境を作ることになります。
様々なヴァージョンの`node, python` を入れるのに `nodenv, pyenv, anyenv` 等はなかなかクールで愛用していますが、Dcoker に練習環境をいれるのは、さらにクールです。
　練習用コンテナを作って用が済めば、コンテナを消すのも簡単
会社のwindowsでdocker で作業をして、 macbook で　喫茶店で気になるところをチェックする、　家に帰って iMac で Docker を立ち上げ作業を続ける等もやろうと思えば出来るでしょう。（笑）
初心者でも、こんな環境が手に入るのです。 使わない理由がありません。


### 今回の作業内容は、githubにおいてありますので、うまく行かない場合は clone してつかってください.
* 動かないと、やる気が半減するので置いておきます
* https://github.com/atoris1192/docker-node-env
* 最初複雑に見えるかもしれませんが、同じパターン作業なので慣れます.


* この作業は、うまくいかない場合ためしてください、　最初は、導入からどうぞ

```
git clone https://github.com/atoris1192/docker-node-env.git

git reset --hard c026b7e19331000aa0a

cd docker-node-env
docker-composer up
docker-compose run --service-ports node bash

cd src
yarn
npx parcel index.pug
```


## 導入
Docker for Mac 或いは Docker for Windows を入れる　　
入れ方は、検索してみてくださいね (DockerをMacにインストールする) などQiitaの記事丁寧でいいんじゃないでしょうか
Docker のアカウントも作って、DcokerHubにも入れるようにしておいてください。


`Dockerfile`と`docker-compose.yml` ファイルを作ります。
この２つで、Docker を操作します。
イメージは、最初からnodeが入っている公式のを使います。
vim 等を入れていますが、要らなければ削除してください
yarn も要らないものは、削除すればいいでしょう、必要になれは後からいれればいいのですから。


`Dockerfile`

```
FROM node:10.15.3
WORKDIR /tmp/src
RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "vim"]
RUN ["apt-get", "install", "-y", "tree"]
RUN yarn init -y && yarn add parcel-bundler pug typescript sass stylus firebase
CMD ["/bin/bash"]
```
イメージを作り直すのにビルドします
最後のドットは忘れないでください。　カレントのDockerfile を指定しています

`docker build -t atoris1192/node:0.1.5 .`
`docker images`　でローカルにイメージができているのが確認できます。


`docker-compose.yml`
* 先にビルドしたものを使う

```
version: "3"
services:
  node:
    container_name: node
    image: atoris1192/node:0.1.5
    # build: .
    # volumes は上書きに注意
    volumes:
      - .:/app
    ports:
      - "1234:1234"
      - "1235:1235"
    working_dir: /app
    command: cp -rp /tmp/src /app
    # command: npx parcel --hmr-port 1235 --hmr-hostname localhost index.pug
    tty: true
```

`docker-compose.yml` ファイルがあるディレクトリであることを確認します。
`dockder-compose up` で環境を作ります。

最初の`docker-compose up` は非常に時間がかかります。
早い機種ならすぐにおわるのでしょうが、Macbookで、5分位かかります
Attaching to node # この状態で止まる
node exited with code 0 # これがでればコピーが終わり
src配下に`node_modules`, `package.json`, `yarn.lock` ができているはずです


`docker-compose.yml`があるディレクトリで

```
# ホスト(Mac)作業
  docker-compose up  # コピーに時間がかかります Attaching to node で止まっているように見える
  docker-compose ps  # node state が exit0 になっているのを確認します。 copy が終わってstopした状態です
  docker-compose run --service-port node bash # コンテナが立ち上がります. ここからlinux側です。
# コンテナ作業
  uname -a` # linuxが動作しています。
  node --version # node が動作しています。
```

  npm がつかえるので、 npm install で vue.js, nuxt, react等 をいれればコンテナ環境で練習ができる
  yarn もつかえますので、yarn global add @vue/cli　をすればいいですね。
  これで Vue Cli version3 が使えます。
  https://qiita.com/atoris/items/6e603e59228f0ccadfd8
  使い方は,上記を参考にしてもらえれば幸いです。

* さて、現在の構成です。
  * node_modulesは、src配下にはいっていますので、npm, yarn を使うのはコンテナに入り、`src`　配下でしてください。
  * コンテナに入らずに、ホスト(Mac)のターミナルで npm, yarn はしないでください、たぶん nodeのヴァージョンがちがうはずです。`node --version` すればわかります。 同じであればうごくかもしれませんがファイルが壊れるのでしないほうがいいでしょう

```
├── Dockerfile
├── docker-compose.yml
└── src
    ├── package.json
    └── yarn.lock
```

## 今回は webpack ではなく、 Parcel bundler を使います

今回は、webpackでバンドルされていないものを使います
練習にもってこいのParcel-bundler です
webpack, parcel-bundler も　ファイルをコンパイルして纏めるのが仕事ですが、練習に余計なファイルができるのは避けたいのと簡単に、pug, sass, stylus, typescript, 等を練習に混ぜたいためです。

pug で　html を仮に作ります。 pug が嫌いな人は、`src/index.html` を作りましょう

ホスト側(Mac)、コンテナどちらからでもOKです
ターミナルは２つ立ち上げておいたほうが便利でしょう( host用,コンテナ用)
`touch src/index.pug`

後は、お好きなエディターでホスト側(atom, vscode等)作っていきます。
持ちろん、コンテナ側で `vim` で作ってもらってもOKです。

`src/index.pug`

```ts
<!DOCTYPE html>
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    meta(http-equiv="X-UA-Compatible", content="ie=edge")
    title Document
  body
    div Hello !
```
* コンテナ内作業 ( linux 側 `uname` すればわかります mac なら　Darwin　と表示されます)

```
cd src
npx parcel index.pug
```

ブラウザーで確認します。
http://localhost:1234

Hello がでていれば、Parcel が正常に動いています

### エラーになる場合ポートマッピングがされているか確認しましょう

  * ホスト側
   `docker-compose.yml`があるディレクトリから実行
  `docker-compose ps`
  * `ports` が指定されているか確認

  ```
  atoris@atorisnoMacBook 08 % doccom ps
            Name                   Command          State                    Ports                
  ------------------------------------------------------------------------------------------------
  08_node_run_ca4fd0d55598   bash                   Up       0.0.0.0:1234->1234/tcp,              
                                                             0.0.0.0:1235->1235/tcp               
  node                       cp -rp /tmp/src /app   Exit 0                      
  ```

  よくあるのが、何回も試していると二重起動やコンテナがすでにある場合失敗します。
  ---
  docker container ls -a で確認して、一旦 コンテナを削除してしまいましょう
  docker container stop コンテナid
  docker container rm コンテナid
  docker-compose down など　コマンドを駆使して消してください(笑)
  ---

  `docker-compose.yml` があるディレクトリで再度
  * ホスト(Mac)作業 の項目から試して見てください

無事にブラウザーに表示されたら、そこまでの作業fileを git commit しておきましょう。(host側にgitが入っていれば)


## vue.js で簡単なTodo アプリを開発してみます。
* まず vueコンポーネントが正常に動くか確認します。
* コンテナでparcel が動いていれば一旦 ctrl + c で止めておきます
* コンテナ作業 で`vue.js` のライブラリを入れておきます。
* package.json がなければ、`yarn init -y `で作っておきます あるはずですが

* コンテナ作業

  ```
  cd src
  yarn add vue
  ```

* vue も無事入っていますね

`pacage.json`

```json
{
  "name": "src",
  "version": "1.0.0",
  "main": "index.js",
  "license": "mit",
  "dependencies": {
    "firebase": "^7.2.1",
    "parcel-bundler": "^1.12.4",
    "pug": "^2.0.4",
    "sass": "^1.23.0",
    "stylus": "^0.54.7",
    "typescript": "^3.6.4",
    "vue": "^2.6.10"
  }
}
```

* vue でコードを書いていきます。

`src/index.pug`

```ts
<!DOCTYPE html>
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    meta(http-equiv="X-UA-Compatible", content="ie=edge")
    title Document
  body
    p index.pug
    #app
    script(src="./index.js")
```

`src/index.js`

```js
import Vue from 'vue/dist/vue.esm';
import MyApp from './MyApp.vue';

new Vue({
  el: '#app',
  components: {
    MyApp,
  },
  template: '<my-app></my-app>'
})
```

`src/MyApp.vue`

```ts
<template lang="pug">
  div
    p MyApp
    Hello
</template>
<script lang="ts">
import Vue from 'vue';
import  Hello  from './Hello.vue';
export default Vue.extend({
  components: {
    Hello,
  }
})
</script>
```

`src/Hello.vue`

```ts
<template lang="pug">
  div
    p Hello.vue
    p {{ name }}
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  data() {
    return({
      name: 'Hello !!!'
    })
  }
})
</script>
```

* 現在のファイル構成です。

```
.
├── Dockerfile
├── docker-compose.yml
└── src
    ├── Hello.vue
    ├── MyApp.vue
    ├── dist
    ├── index.js
    ├── index.pug
    ├── package.json
    └── yarn.lock
```



* コンテナが止まっている場合は再度立ち上げます、立ち上がっていれば parcel コマンドを実行
* ホスト側

```
docker-compose ps
docker-compose run --service-port node bash
```

* Parcel オプションを追加して立ち上げます
  * もし時間がかかってうまく起動しない場合オプション抜きで試してみてください
  * node-hmr が使えないだけです
* コンテナ作業

```sh
cd src
npx parcel --hmr-port 1235 --hmr-hostname localhost index.pug
# npx parcel index.pug
```

ブラウザーにすべて表示されていれば、OKです。
すべてのコンポーネントが動いています

```
index.pug

MyApp

Hello.vue

Hello !!!
```


今回　Todo アプリを作るところまでいけなかったので、次回があります。(笑)