Nuxt.jsをやろうとしたら何も知らなかった

##きっかけ
友人にNuxt.jsはプロジェクトの管理がしやすいと聞いたので始めたいと思い立ったのですが色々覚えないといけないみたいです...
殆ど引用なのでリンクを見た方がいいと思います。また色々ご指摘等頂けると嬉しいです。

[nuxt.js 公式](https://ja.nuxtjs.org/guide)
>>Nuxt.js はリッチなウェブアプリケーションを構築するために下記のものを含んでいます:
・Vue 2
・Vue-Router
・Vuex（ストアオプションを利用している場合に限る）
・Vue Server Renderer（mode: 'spa' を利用している場合を除く）
・vue-meta
すべて合わせてもわずか 57kB min+gzip です。（Vuex 利用時は 60kB）
バンドルやソースコードの分割やミニファイ化するために内部で webpack、vue-loader と babel-loader を使います。

全然わからん、まずwebpackって何だろうと思って調べたがnpmを使わないといけない
しかしnpmもわからない私はまずはそこからでした。

##npm
[npm入門](https://qiita.com/maitake9116/items/7825d90c09f3e2f87dea)
Node Package Managerの略で、Node.jsのモジュールを管理するツールです。
サーバーサイドの言語とは聞いていましたが、Node.jsを使った事が無かったので調べました。
>>C言語なら#include、ruby なら require、golang なら import。どんな言語でも用意されている、他のファイルを読み込んで使えるようにする機能が、なんと Javascriptにはありませんでした。 

上記のような理由の作られたサーバーサイドのJavascriptという事らしいです。
今回は公式からインストールをしました。
[Node.js](https://nodejs.org/ja/)そうすると自動的にnpmもインストールされます。

```html
npm --version
```
ではこのnpmってのはいったい何なのか
>>node.js の世界では、npm というパッケージ管理ツールを使います。npm のリポジトリに、node.jsという言語で書かれた便利ツール達がどんどん追加されていきます。例として
・http-server : 簡易webサーバー。
・grunt : タスクランナー。
・bower : パッケージ管理ツール。

**node.jsで書かれたパッケージ**(ローカルでサーバーを立てられる(http-server)等)がnpmでインストール出来るようになるみたいです。
ここからは実際にnpmを使ってみます。自身で適当にディレクトリを作成して

```html
npm init
```
上記を実行するとpackage.jsonというのが作られます。
その際に色々聞かれますがプロジェクトをnpmパッケージとして公開するときに使われます。
公開する予定がない場合は省略したり適当に入力してしまっても構いません。今回は公開する訳ではないので詳細は省略します。

```
package name: <プロジェクトのパッケージ名>
version: <バージョンコード(x.y.z形式)>
description: <パッケージの説明>
entry point: <ライブラリとして呼び出されるときのエントリーポイント>
test command: <テストコマンド>
git repository:  <gitリポジトリのURL>
keywords: <関連ワード>
author: <作者名>
license: <ライセンス(MIT, GPLなど)>
```

今回は全てEnterのみをしました。そうするとpackage.jsonが生成されます。
このpackage.jsonというのはどういったものなのでしょう。

>>パッケージのバージョン管理を行うのに用いられます。
npmでは、npmでインストールしたパッケージのバージョン情報をpackage.jsonに格納します。
このpackage.jsonからパッケージを一括でインストールすることが出来るため、package.jsonを一元管理することによりフロントエンドで使用するパッケージのバージョン管理を一元化することが出来ます。

npmでインストールする内容が記載されるみたいです。
また、自身でパッケージを公開する際にも使用するようです。(この辺りは今回省略)
インストールする種類には２種類あります。

###グローバルインストール
グローバルインストールではnpmのルート配下にあるnode_modulesにパッケージがインストールされます。
Node.jsインストール時にNode.jsの実行モジュールのインストール先にパスが通されているため、グローバルインストールされたパッケージを全てのプロジェクトで使用することが出来ます。

###ローカルインストール
ローカルインストールではプロジェクトのルート配下にあるnode_modulesにパッケージがインストールされます。 ローカルインストールされたパッケージは対象のプロジェクトのみで使用することが出来ます。

実際にディレクトリのルート配下でローカルインストールを実行してみました。

```js
/* ローカルインストール*/
npm install jquery
```

```js
/*　グローバルインストール */
npm install -g jquery
```

ただそこで気になったのはグローバルインストールを実行する理由ってなんだろうという事
[グローバルインストールは控える](https://mosapride.com/index.php/2018/02/06/post-681/)
>>グローバルインストールしたパッケージはpackage.jsonに記載されない。つまりグローバルインストールすることを前提にREADME.mdなどに注意事項を書く必要が出て来るため構築時に作業量が増える。

という事で今回はローカルインストトールにしました。
確かに他の人にグローバルでインストールした事を伝える手間は必要ないですね

他には--saveオプションを付ける事でpackage.jsonのdependenciesに依存関係が追記されます。
--save-devではdevDependencies依存関係が追加されます。

```js
npm install --save jquery
```

```js
npm install --save-dev jquery
```

dependencies(訳:依存関係)ってなんだろう

>>これは他のライブラリとの依存関係を示しています。ここに記述されたライブラリが必要だということです。
実はこのdependeciesにはいくつかの種類があるらしく、dependenciesとdevDependenciesの違いを見ていきたいと思います。
明確な違いはライブラリを開発するかどうかということです。自作ライブラリをnpmに公開したいとき、別のプロジェクトに組み込みたいとき はdevDependenciesを使う必要があります。単にライブラリを使うだけならdependenciesだけ注目していればいいのです。

ようするにこのプロジェクトには
記載されているパッケージが必要だよってことを記述するみたいですね。
実行後、プロジェクトディレクトリが下記のようになる筈です。

```
node_module
package.json
package-lock.json
```

node_moduleにはjqueryが追加されます。
また、package.jsonにはjqueryが追記されます。

```json
{
  "name": "test_dir",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jquery": "^3.3.1"
  }
}
```

先程jqueryをインストールした事により
このプロジェクトにはjqueryが必要といった内容になります。
package-lock.jsonについては厳密にパッケージの内容が記載されているようです。
[package-lock.jsonについて知りたくても聞けなかったこと](https://qiita.com/yfujii1127/items/7ca887a45e0855917279)
>>・依存パッケージが依存するパッケージ(ネストした依存状態)のバージョン情報が変わる場合がある
package.jsonだけでは、node_modulesを完璧に再現できるとは限らない(勝手に違うバージョンのライブラリがインストールされてしまう可能性)
・package-lock.jsonはバージョン情報をすべて正確に記録する
・package-lock.json に書き込まれたバージョンのパッケージがインストールされる


##webpack
モジュールバンドラのこと。
webpack以外に、以下のようなモジュールバンドラが存在します。
・Browserify
・RequireJS
[webpack 4 入門](https://qiita.com/soarflat/items/28bf799f7e0335b68186#development%E3%81%AE%E4%B8%8A%E6%9B%B8%E3%81%8D%E4%BE%8B)
[最新版で学ぶwebpack 4入門](https://ics.media/entry/12140)
>>モジュールバンドラとは
複数のモジュールを1つにまとめたファイルを出力するツールのこと（簡潔に言ってしまえば）。
※出力設定によっては複数のファイルを出力することもあります。
WebpackはNode.jsでサーバーサイドで動かすモジュールバンドラーツールになります。

>>一つのJavaScriptファイルに長い処理を書くと、可読性が悪くなります。これを解決するには複数ファイルへ分割することでしょう。ウェブのフロントエンド界隈では、機能ごとに分割されたJavaScriptファイルのことを一般的に「モジュール」と呼びます。

実際に私が引き継いでるシステムもfunction.jsに関数がズラーっと書いてある状態でした汗
では早速使用してみます。まずは初期化をしていきます。
package.jsonが生成される筈です。その後必要なパッケージをローカルインストールしていきます。

```js
/*-yで全てYesと答える状態で実行されます*/
npm init -y
```

```json:package.json
{
  "name": "test_dir",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
```

```js
npm install webpack webpack-cli
```

下記ディレクトリが生成されパッケージがインストールされています。
package.jsonの内容も追記されます。

```
node_module
package.json
package-lock.json
```

```json:package.json
{
  "name": "test_dir",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}
```

ではプロジェクトの中にsrcというディレクトリを作成して
その中にファイルを二つ作成します。ここで作成しているディレクトリ名は
あとでwebpackの設定ファイルに記載します。

>>index.jsでsub.jsに定義されたhello()メソッドを呼び出す仕組みを考えてみます。

```js:index.js
// import 文を使って sub.js ファイルを読み込む。
import {hello} from './sub';
// sub.jsに定義されたJavaScriptを実行する。
hello();
```

```sub.js
// export文を使ってhello関数を定義する。
export function hello() {
  alert('helloメソッドが実行された。');
}
```

そして上記のファイルを一つにまとめたファイルを出力する場所を作成します。
今回はdistというディレクトリを作成し、その中で一つにまとまったjsを読み込むhtmlを作成します。


```html:index.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Step1</title>
  <script src="main.js"></script>
</head>
  <body>
  </body>
</html>
```

では新たにwebpackの設定ファイルを作成していきます。
階層はpackage.jsonと同じ階層です(ルート配下といえばいいのかな)。

>>webpack.config.jsファイルを用意することで、webpackの挙動を調整できます。よく使う設定として、エントリーポイントを指定するentryと、出力フォルダーをカスタマイズするoutputがあります。これらは必須ではないもの、よく使うオプションのため必ず抑えておきましょう。次のように指定します。

```js:webpack.config.js
module.exports = {
  // メインとなるJavaScriptファイル（エントリーポイント）
  entry: `./src/index.js`,
 
  // ファイルの出力設定
  output: {
    //  出力ファイルのディレクトリ名
    path: `${__dirname}/dist`,
    // 出力ファイル名
    filename: 'main.js'
  },
};
```

実行したいところですが、その前にpackage.jsonに追記をします。
>>実際の開発ではnpm scriptsを使う方が便利です。npm scriptsとはコマンドのショートカット（エイリアス）を貼るための機能。package.jsonファイルのscriptsには、webpackのビルドコマンドを追加します。

との事です、私はリンク先の```npx webpack```では無い方法を試していきたいと思います。
では下記編集後実行していきます。

```json:package.json
{
  "name": "test_dir",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}
```

```
npm run build
```

そうするとdistにsrcの中にあるjsが一つにまとめられたmain.jsが作成されました。
しかし私の画面では下記のようなエラーが出力されました。

```
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
```

上記について調べてみました。
[modeについて](https://original-game.com/webpack4/#mode)
[mode](https://webpack.js.org/concepts/mode/)

>>WARNING（警告）が出ていますが、一応ビルドはされます。
もしWARNINGが気になる場合は、オプションとしてmodeを指定してあげると出なくなります。
modeはどのように最適化するかを指定できるものです。
development、production、noneを指定できます。
また、デフォルトはproductionです。

それぞれにメリットがあるそうです。
ではmodeの設定をwebpack.config.jsに今回は開発としてdevelopmentを追記して実行します。
そうするとエラーが出力されないようになりました。


```webpack.config.js
module.exports = {

    mode: 'development',
 
    //メインとなるJavaScriptファイル（エントリーポイント）
    //下記ファイルはsub.jsを読み込んでおり、含めてmain.jsとしてくれる
    entry: `./src/index.js`,
   
    // ファイルの出力設定
    output: {
      //  出力ファイルのディレクトリ名
      path: `${__dirname}/dist`,
      // 出力ファイル名
      filename: 'main.js'
    },
  };
```

```js
Hash: f2bdbfead822c577d88c
Version: webpack 4.29.6
Time: 575ms
Built at: 2019-03-11 11:35:13
  Asset     Size  Chunks             Chunk Names
main.js  4.6 KiB    main  [emitted]  main
Entrypoint main = main.js
[./src/index.js] 104 bytes {main} [built]
[./src/sub.js] 84 bytes {main} [built]
```

###webpackでローカルサーバーを起動し、変更時にブラウザをリロードする
>>JavaScriptを編集すると、即座にブラウザが結果を反映する。ローカルのウェブサーバーとしても利用できる。
「webpack-dev-server」はとても便利な機能です。わずかな設定でできるので構築してみましょう。

今度は上記を試していきたいと思います。
早速インストールしてみます。jsonに情報が追記されます。
その後scriptsに``"start": "webpack-dev-server"```と記述していきます。

```js
npm install webpack-dev-server
```

```json:package.json
{
  "name": "test_dir",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack-dev-server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.1"
  }
}
```

次にwebpack.config.jsにdevServerの設定を記述していきます。

```js:webpack.config.js
module.exports = {

    mode: 'development',
 
    // メインとなるJavaScriptファイル（エントリーポイント）
    entry: `./src/index.js`,
   
    // ファイルの出力設定
    output: {
      //  出力ファイルのディレクトリ名
      path: `${__dirname}/dist`,
      // 出力ファイル名
      filename: 'main.js'
    },
    devServer: {
      // devServerにルートフォルダーを設定します。
      // open: trueを指定しておくと、自動的にブラウザが立ち上がります。
      contentBase: 'dist',
      open:true
    }
  };
 ```

```js
npm run start
```

無事実行がされました。
JSファイルを編集するとリアルタイムに反映されます。

###疑問点・理解を深めないといけない事
・パッケージをインストールする際にオプションを付けずに実行しているが、
devDependenciesとdependencies使い分けを実際の運用の際にどのようにしていくかがピンと来ていない


##Babel
[最新版で学ぶwebpack 4入門 – Babel 7でES2018環境の構築](https://ics.media/entry/16028)
>>ECMAScript 2015(略：ES2015)以上の言語仕様でJavaScriptを書くことが、昨今のウェブのフロントエンドエンジニアの基本テクニックです。しかし、ECMAScript 2015以上の仕様のJavaScriptで記述すると、**Internet Explorer 11など古いブラウザでは動作しないこともあります。**そこでBabelなどのトランスパイラと呼ばれるツールを使って、ES2015・ES2016・ES2017・ES2018の仕様で記述したJavaScriptファイルを互換性のあるECMAScript 5に変換します。

JavaScriptの新しい機能で実装したプロジェクトを古いブラウザでも使えるように変換してくれるようです。
ではまず新しくパッケージを初期化後、必要なモジュールをインストールしていきます。

```
npm init
```

```
npm install webpack webpack-cli babel-loader @babel/core @babel/preset-env
```
ではwebpackの設定ファイルを作成していきます。```npm run build```が使えるように
```"build": "webpack"```をpackage.jsonに追加します。追加後、起動していきます。


```js:webpack.config.js
module.exports = {
    // モード値を production に設定すると最適化された状態で、
    // development に設定するとソースマップ有効でJSファイルが出力される
    mode: 'development',
   
    // メインとなるJavaScriptファイル（エントリーポイント）
    entry: './src/index.js',
    
    output: {
        //  出力ファイルのディレクトリ名
        path: `${__dirname}/dist`,
        // 出力ファイル名
        filename: 'main.js'
    },
    
    module: {
      rules: [
        {
          // 拡張子 .js の場合
          test: /\.js$/,
          use: [
            {
              // Babelを利用する
              loader: 'babel-loader',
              // Babelのオプションを指定する
              options: {
                presets: [
                  //presetを指定することで、ES2018 を ES5 に変換
                  '@babel/preset-env',
                ]
              }
            }
          ]
        }
      ]
    }
  };
```

```
npm run build
```

###jqueryを試してみる
jqueryをインストール後index.jsにjqueryをインポートしていきます。

```
npm install jquery
```

```js
import jQuery from 'jquery';

// ドルマークに参照を代入(慣習的な $ を使うため)
const $ = jQuery;

// テキストを取得
const text = $('#myText').text();
$('#myText')
  .empty() // 一旦、空にする
  .show(); // 表示する

const arr = text.split(''); // 一文字ずつ、配列に格納
const elements = [];

// 一文字ずつ、spanタグで包む
arr.map((str, index) => {
  elements[index] = $(`<span>${str}</span>`);
  $('#myText').append(elements[index]); // 元の場所に挿入
});

// エフェクトの適用
elements.map((element, index) => {
  element
    .delay(40 * index)
    .queue(function () {
      $(this).addClass('motion');
    });
});
```

ちなみにこのインポートとする際のパスの指定ですが、
>>node_modulesはマジックディレクトリです。
ここに宣言されたモジュールはパスの指定を省略して検索されます。

とのことです[詳細](https://qiita.com/hosomichi/items/149b28c89a012ead26aa)

**BabelにはJSファイルをまとめる機能が提供されていませんのでBabelでES2015以降で記載されたjsをECMAScript5に変換 => webpackでひとつのjsファイルにまとめる**といった流れになります。

##Vue
nuxtにはbabelの他にvueも使用されています
Vueの使い方は今回は省略します。
[VueCLIで出てくるファイルを概要図で理解](https://qiita.com/po3rin/items/3968f825f3c86f9c4e21)
[体で覚えるVue.js](https://qiita.com/hosomichi/items/ad9a9c99a4fda041a563)
[私がハマったVue.jsのショボいミス](https://qiita.com/fruitriin/items/fe26e3ecb33000a6544e)
>>.vueファイルを読み込むために、vue-loaderやvue-template-compilerを入れておきます（必須）。.vueファイルではCSSも扱うので、css-loaderやfile-loaderも必要となります。



#nuxt



とりあえずドキュメントを進められます.......
[SPA : シングルページアプリケーション](https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a)
[SSR : サーバーサイドレンダリング](https://www.wantedly.com/companies/branu/post_articles/79475)
[nuxt: インストール](https://github.com/nuxt/create-nuxt-app)

私のnpmのバージョンは6.1以降なので下記のコマンドを実行します。npm initとinstallをしてくれます。

```
npm init nuxt-app
```

上記の際に注意したいのがAuthor nameの際にデフォルトのままにしてしまうと/User名となりエスケープと認識し、エラーが出力されます。何かしら入力した方がいいと思います。他にもaxiosを使われますかとか聞かれますが、今回は全て無しにしました。起動していきます。

```
npm run dev
```

無事大量のディレクトリも生成され、ブラウザにて確認できました。
しかし低スペックな私のPCでは重すぎてつらいです。下記を試してみようと思います。
[Nuxt.js でビルド時間を100倍高速化して作業時間が大幅upした件](https://qiita.com/toaru/items/0690a9110c94052bb479)

webpackの設定はwebpack.config.jsに記載していていましたが、nuxtではnuxt.config.jsに記載するようです。
[nuxt.config.js](https://ja.nuxtjs.org/guide/configuration/)

```js:nuxt.config.js
const pkg = require('./package')

module.exports = {
  mode: 'universal',

/////////////////*省略*///////////////////
  build: {
    /*
    ** You can extend webpack config here
    */
    extend(config, ctx) {
      const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
      config.plugins.push(new HardSourceWebpackPlugin())
    }
  }
}
```

##nuxt 記法メモ
```
<p v-for="message in messages"
       class="text"
       :class="{ 'text-error': message.error }">
      {{ message.text }}
    </p>
```

```
var app = new Vue({
  el: '#app',
  data: {
    messages: [
      { text: 'This is normal message.', error: false },
      { text: 'This is ERROR message!', error: true },
    ]
  }
})
```

属性の値として指定したオブジェクトのキー（ 'text-error' ）がクラス名です。そして、オブジェクトの値（ message.error ）は真偽値として評価されます。値が真と評価された場合はキーのクラス名がタグに追加されます。逆に偽と評価された場合はキーのクラス名がタグから削除されます。まとめるとオブジェクトをforで回した際にmessage.errorの値を見て真偽値でclassを付与するかどうかを切り替えています。trueの場合はtext-errorが付与されます。





##Express
[Nuxt.js&Expressプロジェクト作成](https://qiita.com/ta1nakamura/items/417d858d5c93bbf3040e)
[ExpressでPOSTを処理するメモ](https://qiita.com/K_ichi/items/c70bf4b08467717460d5)