three.jsのプロジェクトを作ってGitHubにあげてHerokuに公開するまでのステップ 1/2

Blenderで鉛筆のモデルとアニメーションを作ったので、three.jsを使用してwebブラウザに表示させたものをHerokuにアップしてみようと思います。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/ef4b2397-05d0-ac8f-6ae7-620fef9ed22f.gif)


GitHubのリポジトリ作成から環境構築、Herokuのデプロイまでを2回に分けて記載します。
今回の記事では、GitHubリポジトリの作成〜環境構築〜GitHubへの初回pushまでを行います。
それ以降の手順は以下の記事に記載しています。
[three.jsのプロジェクトを作ってGitHubにあげてHerokuに公開するまでのステップ 2/2](https://qiita.com/kyk_nr/items/2bc526928eb2fb74f7fe)

# もくじ
[1. リモートリポジトリの作成](#1-リモートリポジトリの作成)
[2. three.js、webpackの環境構築](#2-環境構築)
[3. 上手く動くか確認](#3-上手く動くか確認)
[4. リモートリポジトリにプッシュする](#4-リモートリポジトリにプッシュする)

#1. リモートリポジトリの作成
自分のGithubアカウントからリポジトリを作成します。

## (1) アカウントの[New]ボタンを押下する
![shot01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/6033ce8c-d81b-7c85-1993-68647f9a6a09.png)

## (2) リポジトリの設定をして[Create repository]を押下する
 **Repository name** → 好きな名前をつける。
 **Description** → 任意。リポジトリの説明を書く。
 **Public / Private** → このリポジトリを公開するかどうか。
 **Add a README file** → チェックするとリポジトリのトップに表示する文章の雛形を作成してくれる。後から追加可能。
 **Add .gitignore** → チェックするとgit管理しないドキュメントを記載するファイルの雛形を作ってくれる。後から追加可能。
 **Choose a license** → リポジトリのライセンスを決定する。[この記事](https://qiita.com/shibukk/items/67ad0a5eda5a94e5c032)が詳しいので気になる方はみてみてください。
 
![shot02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/123d789f-7f63-a1ef-0960-84f837a83f94.png)

## (3) 作成したリポジトリをクローンする
Githubリポジトリの[code]ボタンを押下して出てきたurlをコピーします。
![shot03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/25f9ac80-dd73-f67c-0fb5-1c5f62879de6.png)

ターミナル(windowsの人はコマンドライン)等でリポジトリをクローンしたいディレクトリまで移動し、以下のコマンドで上記でコピーしたurlからリポジトリをクローンします。

```shell
git clone {さっきコピーしたurl}
```

#2. 環境構築
Webpackを使用してthree.jsの環境構築を行います。
使用するパッケージは以下の通りです。

| No | パッケージ                | 説明 |
|---:|:------------------------|:-----------|
| 1  | webpack                 | モジュールバンドラ。複数のモジュールを一つにまとめて出力してくれる。 |
| 2  | webpack-cli             | webpackを使うなら必ず必要。 |
| 3  | webpack-dev-server      | 開発用に簡単にサーバーを立ち上げられる。 |
| 4  | babel-loader            | Babel（トランスパイラ。Jsは書き方によって動作するブラウザが違うのでそれを互換性のあるECMAScript 5に変換してくれる。）のモジュールの一つ。 |
| 5  | @babel/core             | Babelのモジュールの一つ。 |
| 6  | @babel/preset-env       | Babelのモジュールの一つ。 |
| 7  | three                   | Web上に3Dを簡単に表示させるためのライブラリ。 |
| 8  | css-loader              | webpackでcssもバンドルできるようにする。 |
| 9  | mini-css-extract-plugin | webpack@4でCSSを扱うときはこのプラグインを使うことが推奨されているらしいです。 |
| 10 | html-loader             | webpackでhtmlもバンドルできるようにする。 |
| 11 | html-webpack-plugin     | html-loaderを使うときはこのプラグインも必要。 |
| 12 | copy-webpack-plugin     | webpackでsrcディレクトリ以下の特定のファイルを、バンドル後のファイル階層にもコピーしたい時に使うプラグイン。今回はBlenderで作ったmodelをコピーするために使用。 |

## (1) 関連パッケージをインストールする

まずは初期化してpackage.jsonファイルを作成します。

```shell
yarn init -y
```

webpack関連のパッケージをインストール

```shell
yarn add webpack webpack-cli webpack-dev-server --dev
```

Babel関連のパッケージをインストール

```shell
yarn add babel-loader @babel/core @babel/preset-env --dev
```

threeをインストール

```shell
yarn add three
```

html-loader、css-loader、その他プラグインのインストール

```shell
yarn add html-loader html-webpack-plugin css-loader mini-css-extract-plugin copy-webpack-plugin --dev
```

## (2) package.jsonに追記する
ローカルで開発サーバを立ち上げるスクリプト、開発完了後にHerokuにデプロイするファイルを出力するスクリプトを追記します。

```json:package.json
{
    "scripts": {
        "serve": "webpack-dev-server",
        "build": "webpack"
    },
    "dependencies": {
        // threeとかのバージョンが書かれているはず
    }
}
```

## (3) srcフォルダを作成する

package.jsonと同じ階層に「src」フォルダを作成します。
srcフォルダの中に以下のファイルを作成します。（現時点では内容は空でOK。）

* index.html
* index.js
* style.css

![shot04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/1bc009b5-04b6-9007-1ba5-3d2d1eb8f10d.png)

## (4) staticフォルダを作成する
package.jsonと同じ階層に「static」フォルダを作成します。（現時点で中身は空でOK。）
![shot5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/81d4fa99-d133-cf55-090b-5e05407cc80e.png)


## (4) webpack.config.jsを作成する
package.jsonと同じ階層に「webpack.config.js」ファイルを作成します。
![shot6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/8a7ff1d0-d250-f622-4659-56b490ba67c4.png)

作成したファイルには以下のように記載します。

<details><summary>webpack.config.js</summary><div>

```js:webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCSSExtractPlugin = require('mini-css-extract-plugin')
const path = require('path')

module.exports = [
  {
    // メインとなるJavaScriptファイル（エントリーポイント）
    entry: `./src/index.js`,
    output: {
      //  出力ファイルのディレクトリ名
      path: path.resolve(__dirname, 'dist'),
      // 出力ファイル名
      filename: 'bundle.js'
    },
    // モード値を development に設定するとソースマップ有効でJSファイルが出力される
    mode: "development",
    devServer: {
      // 開発時にdevserverを立ち上げた時にブラウザが自動で開くようにする設定
      open: true
    },
    plugins: [
      // staticフォルダの中をコピーして展開してくれる
      new CopyWebpackPlugin({
        patterns: [
          { from: path.resolve(__dirname, './static'), to: path.resolve(__dirname, 'dist/static') }
        ]
      }),
      // htmlファイルをindex.htmlという名前で展開してくれる
      new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '/src/index.html'),
        minify: true
      }),
      new MiniCSSExtractPlugin()
    ],
    module: {
      rules: [
        // HTML
        {
          test: /\.(html)$/,
          use: ['html-loader']
        },
        // JS
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: 'babel-loader'
        },
        // CSS
        {
          test: /\.css$/,
          use: [MiniCSSExtractPlugin.loader, 'css-loader']
        }
      ]
    }
  },
];

```
</div></details>

#3. 上手く動くか確認
動作確認のために、最低限のコードを書いて実際に開発サーバを起動したりbuildしてみます。

## (1) 最低限のコードを書く
html、css、jsに以下の通りコードを書きます。

<details><summary>index.html</summary><div>

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pencil Animation</title>
</head>
<body>
    <canvas class="webgl"></canvas>
</body>
</html>
```
</div></details>

<details><summary>style.css</summary><div>

```css:style.css
*
{
    margin: 0;
    padding: 0;
}

html,
body
{
    overflow: hidden;
}

.webgl
{
    position: fixed;
    top: 0;
    left: 0;
    outline: none;
}
```
</div></details>

<details><summary>index.js</summary><div>

```js:index.js
import './style.css'
import * as THREE from 'three'

// Sizes
const sizes = {
  width: window.innerWidth,
  height: window.innerHeight
}

// Canvas
const canvas = document.querySelector('canvas.webgl')

// Scene
const scene = new THREE.Scene()

// Test cube
const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial()
)
cube.rotation.set(0.3, 0.3, 0)
scene.add(cube)

// Camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.set(0, 0, 4)
scene.add(camera)

// Renderer
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  antialias: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

// Render
renderer.render(scene, camera)

```
</div></details>

## (2) webpack.config.jsのCopyWebpackPluginを一旦コメントアウトする
現在のファイル構成では「static」フォルダ配下に何も置いておらずCopyWebpackPluginがエラーになるため、一旦「webpack.config.js」の対象の部分をコメントアウトします。

```js:webpack.config.js
module.exports = [
  {
    // 省略
　　　　　　　　plugins: [
      // staticフォルダの中をコピーして展開してくれる
      // new CopyWebpackPlugin({
      //   patterns: [
      //     { from: path.resolve(__dirname, './static'), to: path.resolve(__dirname, 'dist/static') }
      //   ]
      // }),
      // htmlファイルをindex.htmlという名前で展開してくれる
      new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '/src/index.html'),
        minify: true
      }),
      new MiniCSSExtractPlugin()
    ],
　　　　　　　　// 省略
  }
]
```

## (3) 開発サーバを立ち上げる
以下のコマンドで開発サーバを立ち上げます。
<font color="grey">※ Macの場合はCommand + C、Windowsの場合は Ctrl + C で開発サーバを停止できます。</font>

```shell
yarn serve
```

こんな画面が表示されれば成功です！
![shot7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/086e058a-278a-eca9-fc30-a9fb0e2de67a.png)

## (4) buildしてみる
以下のコマンドでbuildしてみます。

```shell
yarn build
```

「dist」というディレクトリができ、その中にhtml、js、cssファイルが配置されていれば成功！
![shot8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/40181ac6-3e64-ebdb-2d0d-90f2d7bdf15b.png)

#4. リモートリポジトリにプッシュする
ここまでのソースをGitHubのリポジトリにpushします。

## (1) .gitignoreファイルを作成する
Git管理しないソースを指定するため、プロジェクトのルートディレクトリに「.gitignore」ファイルを作成します。
![shot9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604689/22703861-a3a5-cd4b-fe75-871c60bd914e.png)

## (2) .gitignoreに追記する
今回はnode_modulesをgit管理から外すので、gitignoreに以下のように記述します。
<font color="grey">※　staticフォルダやdistフォルダはherokuにアップロードする際に必要になるので.gitignoreには記載しません。</font>

```
# dependencies
/node_modules

```

## (3) GitHubにプッシュする

以下のコマンドで、addされていないフォルダを確認します。
<font color="grey">※ .gitignoreで除外したnode_modulesとstaticが表示されないことを確認します。</font>

```shell
git status
```

変更したファイル全てをaddします。

```shell
git add .
```

コミットメッセージを記載します。
<font color="grey">※ -mの後は任意のコメントを記載してください。今回は初回のコミットなのでinitial commitとしています。</font>

```shell
git commit -m "initial commit"
```

pushします。

```shell
git push origin main
```


# 次回
次回は、実際にthree.jsでBlenderで作成したモデルを取り込み、Herokuにデプロイしてみます。
[three.jsのプロジェクトを作ってGitHubにあげてHerokuに公開するまでのステップ 2/2](https://qiita.com/kyk_nr/items/2bc526928eb2fb74f7fe)

# 参考にした記事

https://qiita.com/hirogw/items/506fd433b35ad0118c5d

https://qiita.com/fuubit/items/02a78744196e17869548

https://ics.media/entry/16028/