新人にドヤ顔で説明できるか、今風フロントエンド開発ハンズオン(Git/Node.js/ES6/webpack4/Babel7)

# 概要
- 今風の手法でJavaScriptアプリを作ろうとすると色々ツールがあって便利な反面、**複雑でわからない**ことがたくさんあります。
- わからないことがあったら、それを放置せず、しっかり理解して**大いに寄り道**しつつブラウザで動作するJavaScriptアプリをゼロから作っていきます
- ブラウザ上で動作するフロントエンドアプリを作ったら、ライブラリ化してnpmモジュールとして公開します

### 対象読者＝今風のJavaScript開発の入門者、初心者
- 11年前からタイムトラベルしてきたひと
- ブラウザ用アプリを作りたいが今風の手法の初心者(jQueryだけでなんとか生きてきた人とか）
- Node.jsの環境をつかってフロンドエンドアプリかいているけど、「何となく」理解している人
- 来年の新人教育係

### キーワード

本投稿では、以下のようなキーワードが出てきます。

Node.js、npm、ES6(ECMAScript6)、webpack4、Babel v7、ソースマップ、クラス、JSでオブジェクト指向

### ソースコード
この記事のソースコード（最終版）は https://github.com/riversun/es6hello.git にあります。

クローンしてサンプルを実行する場合は、以下のようにします。

```shell
git clone https://github.com/riversun/es6hello.git
npm install
npm start
```


# 準備

## node/npmのインストール

node/npmをそれぞれの環境にあわせてインストールしておく

私のバージョンは以下のとおり。 ```-v```コマンドでバージョンを表示できる

```shell:コマンドラインで以下を入力
node -v
v8.11.4

npm -v
5.6.0
```

## npmプロジェクトの作成

### プロジェクトの作業ディレクトリを作成

まずプロジェクトの作業ディレクトリを作る
任意の名前をつける。ここでは **es6hello**とする

```shell:コマンドラインで以下を入力
mkdir es6hello
cd es6hello
```

### npm init でnpmプロジェクトを初期化

npm initをして、このディレクトリをnpmプロジェクトにする

```shell:コマンドラインで以下を入力
npm init
```

```npm init```と入力すると以下のようになる

```shell
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (es6hello)
```

いろいろきかれるが、後から変更できるのでここではとりあえずすべてエンターでOK。
（エンターを9回程度押す）

```shell
package name: (es6hello)?
version: (1.0.0)?
description:?
entry point: (index.js)?
test command:?
git repository:?
keywords:?
license: (ISC)?
About to write to /dev/es6hello/package.json:

{
  "name": "es6hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Tom Misawa <riversun.org@gmail.com> (https://github.com/riversun)",
  "license": "ISC"
}

Is this ok? (yes)?
```

これでディレクトリに **package.json** が生成される

```shell:package.json
{
  "name": "es6hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Tom Misawa <riversun.org@gmail.com> (https://github.com/riversun)",
  "license": "ISC"
}
```

これでnpmプロジェクト完成！

**現在のディレクトリ構成**

```
es6hello
├── package.json
```

# 最後にnpmモジュールとして公開したいから、npmプロジェクトをGit管理下におき、GitHubにpushする

なぜGitの部分まで説明しているかというと、最終的に作ったjsを、外部から使えるnpmモジュールとして公開することをもくろんでいるのでGit管理の説明をする。
npmモジュールにすることに全く興味がなければ、Gitの部分はすべて読み飛ばしてOK。

ソースコードのバージョン管理をするためにディレクトリをGit管理下に置く。
リモート側はGitHubを使う


## ディレクトリをGit管理下に置く

このディレクトリをGit管理下におく

```
git init

Initialized empty Git repository in /dev/es6hello/.git/
```

<hr>

このディレクトリ以下のすべてのファイルをGit管理下におく
（といっても、まだpackage.jsonしかない）

```
git add -A
```

ちなみに、```git add -A```は以下をステージ領域に追加という意味

- 新規追加されたファイルやフォルダ
- 変更があったファイルやフォルダ
- 削除されたファイルやフォルダ

<hr>

package.jsonをコミットする

```
git commit -m "first commit"

[master (root-commit) 5cee35d] first commit
 1 file changed, 11 insertions(+)
 create mode 100644 package.json
```


## GitHubに初回のpushをする

ついでにGitのリモートリポジトリにpushするところまでやっておく

### GitHubにリポジトリを作る

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/2a7ce00a-9558-706f-7b41-ce4b30e5d428.png)

GitHubにリポジトリができたらURLをコピーする

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/a164cb6e-a7a1-5ca2-fa51-55f7f502d524.png)


## ローカルGitのリモート側をGitHubに設定する

リモート名：**origin**にGitHubのリポジトリをひもづける

```
git remote add origin https://github.com/riversun/es6hello.git
```

これでリモート **origin**にgithubにつくったリポジトリがひもづいた。

## 現在のブランチをGitHubにpushする

現在のブランチはデフォルト設定なので ```master```ブランチとなっている

```shell
git branch
* master
```

現在のブランチをリモート側(**origin**)の**master**ブランチにpushする
(pushするときにupstreamブランチを指定する)

```shell
git push --set-upstream origin master

Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 411 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote:      https://github.com/riversun/es6hello/pull/new/master
remote:
To https://github.com/riversun/es6hello.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
```

以下で、現在のブランチがどのupstreamブランチを追跡するか確認する

```shell
git branch -vv
* master 5cee35d [origin/master] first commit
```
upstreamブランチが設定できていることが確認できた。


また、GitHub側にもちゃんとpushできていることを確認。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/e7509c18-a26e-59ff-32d7-8ded7413c3b9.png)


以降は ```git push``` でpush可能。

これでひとまずローカル側とリモート側にGitの環境が整った。

# webpackを使えるようにする

早くJavaScriptでコードを書きたいところだが、まずは最低限の環境をつくるところからはじめる。

まずは**webpack**導入から。

## webpackとは何か
webpackとはモジュールバンドラーと呼ばれるモノで、要は複数のjsファイルを良い感じに処理して1つにまとめてくれるツールのこと。

## なぜwebpackが必要か

大規模なソフトを開発する場合には、ソースコードを複数のファイルに分割して開発する。
分割することをモジュール化といったりする、また分割された１つ１つのファイルを**モジュール**と呼んだりする。

**以前は**、下のようにブラウザからjsファイルを読み込むときに複数のjsファイルを**scriptタグ**で列挙して読み込むということが割と一般的だった。

```html:scriptタグで各種モジュールを読み込んでいるhtml
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Hello world!</h1>

<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>

</body>
</html>

```

読み込むモジュールが3つくらいなら、これも特に問題はないが、これが増えてくるとどのモジュールとどのモジュールの依存関係があるか、どのモジュールを先に読み込むか、など問題がでてくる。
また**npm**で外部公開されているパッケージを取り込むときにもかなり面倒になってくる。

Node.jsの**サーバーサイド**向け仕様では、こうした問題に対応するために**require**で依存モジュールを解決したり、npmで外部パッケージを取り込んで利用したりが簡単にできるようになった。
JavaScriptも他の言語プラットフォーム(JavaやRubyなど)同様の開発エコシステムが**急速に**(※)整備された。
（※私がjsに初めて触れたのは1990年代後半なので、急速に整備されたように感じるｗ）

そうした便利な機能を**フロントエンド**つまりブラウザ用のJavaScript開発でも使えるようにしてくれるのがwebpackとなる。（もちろんnpm等も仕組みもあわせてつかう）

いちばんシンプルにwebpackをとらえるなら以下のように複数のjsを1つにまとめてくれる、機能となる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/b1ed47f3-c37a-6dab-4370-4ae5f327df07.png)

webpackと同じようなことをしてくれるツールはいくつかある(以前流行っていた[browserify](https://github.com/browserify)や最近でてきた[parcel](https://github.com/parcel-bundler/parcel)など)が現時点でいちばんメジャーなのでこちらを使う。最新のバージョンは [webpack4系](https://github.com/webpack/webpack)となる。

## webpackの導入準備

早速webpackをインストールしていく。


### npm installの使い方

コマンドラインに```npm install --save-dev webpack webpack-cli webpack-dev-server```と入力する。

```shell
npm install --save-dev webpack webpack-cli webpack-dev-server

npm WARN es6hello@1.0.0 No description
npm WARN es6hello@1.0.0 No repository field.

+ webpack-cli@3.1.0
+ webpack-dev-server@3.1.8
+ webpack@4.19.1

updated 3 packages in 19.837s
```

するとインターネットから3つのパッケージ(webpack webpack-cli webpack-dev-server)が自動的にダウンロードされる。
どれもwebpack関連のパッケージとなる。

しばらく待つと、webpackのインストールが終了する。

**現在のディレクトリ構成**

```
es6hello
├── node_modules
├── package.json
└── package-lock.json
```

node_modulesというディレクトリとpackage-lock.jsonというファイルが生成された模様。
これは後で説明する。

webpackのインストールが終わると、package.jsonには以下が自動的に追加される。

```json:package.json追加分
 "devDependencies": {
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.7"
  }
```

```npm install --save-dev webpack webpack-cli webpack-dev-server```の意味だが、
**npm install**コマンドはnpmのパッケージをインストールしてね、という意味、
そのパッケージは、**--save-dev**は開発時のみに使うという意味となる。

**npm install --save-dev パッケージ名 パッケージ名 パッケージ名**のように複数のパッケージを同時に指定することができる。

### package.jsonのdevDependencies意味とは？

上のpackage.jsonの追加分にあった**devDependencies**以下には、このプロジェクトで利用するパッケージが記述される。プロジェクトがこのパッケージに依存しているので依存パッケージとも呼ぶ。

さきほどのパッケージインストール時には **--save-dev**を指定して開発時のみにつかうことを指定したが、それがpackage.jsonでは**devDependencies**となる。

```json
 "devDependencies": {
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.7"
  }
```

devDependencies以下にある **"webpack": "^4.19.0"**は```"[パッケージ名]":"^[バージョン]"```　の意味となる。

バージョンのところにある「^」（キャレット）に注目。「おいおい、**^**は何だよ」っていう話だが、これはキャレット表記と呼びバージョン指定をするときに特別な意味をもっている。

さて、このキャレット表記の意味だが、**^4.19.0**は、パッケージのバージョン**Ｘ**が **4.19.0≦ Ｘ＜5.0.0**の範囲ならOKという意味になる。（こちら https://docs.npmjs.com/misc/semver に詳しい説明がある）

それだけでは意味がよくわからないので、まずこのバージョン表記の意味からみていく。

npmパッケージのバージョン、たとえば**4.19.0**というバージョン名の付け方は[セマンティックバージョニング](https://semver.org/lang/ja/)というルールに従っている。

↓のように、それぞれの数字の意味が **メジャーバージョン**.**マイナーバージョン**.**パッチバージョン**の意味をもつ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/f50bbc16-dd88-33cc-319a-ff198e025618.png)

ちなみに、**後方互換**とはAPIのバージョンが上がっても、旧APIと互換性が保たれるという意味。

さきほどにもどると、キャレット表記つまり**^4.19.0**が**4.19.0≦ Ｘ＜5.0.0**の範囲ということで「**メジャーバージョンは固定**するよ、ただ**マイナーバージョンやパッチバージョンは変化するよ(上がる)**」という意味になる。

メジャーバージョンが固定されるので、パッケージを作った人がセマンティックバージョニングの精神にきちんと従っていれば理屈上は後方互換が担保される。

ただし、これは、あくまでも理屈。
人間がやることなのでマイナーバージョンやパッチバージョンを上げるような更新の場合でもうっかり忘れで後方互換が破綻する場合もある。

そのあたりの課題を解決するために考えられたのが次にでてくる **package-lock.json**の話につながる。

### package-lock.jsonとは何か

現在は↓のようなディレクトリ構成になっており、**package-lock.json**が自動的に追加されている。

**現在のディレクトリ構成**

```
es6hello
├── node_modules
├── package.json
└── package-lock.json
```

さきほどキャレット表記でメジャーバージョンを固定することで後方互換が理屈上は担保されていたが、実際には、パッチバージョンを変えたら動かなくなってしまった、みたいなことが起こっている。

また、ある依存パッケージが別の依存パッケージに依存しているいわゆるツリー状（入れ子状）の依存関係になっていることが良くあるため、ツリーのどこかにある依存パッケージのマイナーバージョンやパッチバージョンがあがったりすると、イッキに動かなくなってしまうことが起こりえる。

なので、やっぱり依存パッケージのバージョン番号は　メジャー・マイナー・パッチ　すべて固定（ロック）しようよ、というのが**package-lock.json**のお役目となる。

最上位のパッケージだけ固定しても仕方がないので、依存パッケージの依存パッケージといったツリー上の依存関係にある全パッケージのバージョン情報が**package-lock.json**に書き出される。

例えば、webpack 4.19.1 の依存パッケージのツリーは以下のようになる。ツリーをたどっていくとなんと１０００個以上の依存パッケージがあり、深くネストしている。

ここでは参考までに```npm-remote-ls```というツールをつかって、依存パッケージのツリーを表示してみた。
（依存関係をグラフィカルに表示してくれる[サイト](http://npm.anvaka.com/#/view/3d/webpack)もある。）

```shell

npm install -g npm-remote-ls
npm-remote-ls webpack

 webpack@4.19.1
   ├─ acorn-dynamic-import@3.0.0
   │  └─ acorn@5.7.3
   ├─ ajv-keywords@3.2.0
   ├─ @webassemblyjs/helper-module-context@1.7.6
   │  └─ mamacro@0.0.3
   ├─ @webassemblyjs/ast@1.7.6
   │  ├─ @webassemblyjs/helper-module-context@1.7.6
   │  ├─ mamacro@0.0.3
   │  ├─ @webassemblyjs/helper-wasm-bytecode@1.7.6
   │  └─ @webassemblyjs/wast-parser@1.7.6
   │     ├─ @webassemblyjs/helper-api-error@1.7.6
   │     ├─ mamacro@0.0.3
   │     ├─ @webassemblyjs/helper-code-frame@1.7.6
   │     │  └─ @webassemblyjs/wast-printer@1.7.6
　・
　・
　・
```
と1000件以上の依存パッケージがある

というわけで**package-lock.json**は自動生成されるファイルだが(npm5以降自動生成されるようになった）、**gitにcommitすることが推奨**されている。


### ダウンロードしてきた依存パッケージはどこに保存される？

さて、いま依存パッケージがたくさんあることをみてきたが、それらパッケージは**npm install**されたあと、どこに保存されるのか。

現在のディレクトリ構成↓を再度みてみると、**node_modules**というディレクトリも自動的に生成されている。

**現在のディレクトリ構成**

```
es6hello
├── node_modules
├── package.json
└── package-lock.json
```

この**node_modules**デイレクトリが、ダウンロードしたパッケージの保存先となる。

### node_modulesはgit管理しない

node_modulesはダウンロードされてきた依存パッケージが保存されているが、これらはgit管理したくないので、以下のように**.gitignore**ファイルを作成してgit管理対象から外す。

```text:.gitignore
/node_modules/
```

**＜現在のディレクトリ構成＞**

```
es6hello
├── node_modules
├── .gitignore
├── package.json
└── package-lock.json
```

# 超ミニマムなwebアプリを記述する

さて、ここではブラウザで動作する一番シンプルなアプリを作る。


### シンプルなhtmlとjsのソースコードを用意する

まず作業ディレクトリes6hello直下にブラウザで開く用の index.htmlを作成する

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

このindex.htmlはbodyに 

```html
<script src="main.js"></script>
```

を入れただけの非常にシンプルなもの。

次に、jsのソースコードを格納するための**src**ディレクトリを作り、そこに**index.js**という名前のファイルを作る。

```js:index.js
alert("hello");
```


index.htmlとsrc/index.jsを加えたので
ディレクトリ構成は↓のようになる

```text

es6hello
├── node_modules
├── src
│   └── index.js
├── .gitignore
├── index.html
├── package.json
└── package-lock.json
```


### webサーバーを使えるようにする

webpackにはwebpack-dev-serverという開発用のwebサーバーが準備されている。
このサーバーを起動するためにpackage.jsonの**scripts**以下に

```json
"start": "webpack-dev-server",
```
を追加する。

package.jsonの全体は以下のようになる。

```json:package.json
{
  "name": "es6hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Tom Misawa <riversun.org@gmail.com> (https://github.com/riversun)",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.19.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.8"
  }
}
```

``` "start": "webpack-dev-server"```のように記述すると
コマンドラインで**npm run start**と入力したときに、**webpack-dev-server**というコマンドが実行される。

### webアプリの実行

以下を入力するとwebアプリを実行できる

```shell:コマンドライン
npm run start
```

と入力すると以下のように、webサーバーが起動してアプリを試すことができるようになる。

```
> es6hello@1.0.0 start dev/es6hello
> webpack-dev-server

i ｢wds｣: Project is running at http://localhost:8080/
i ｢wds｣: webpack output is served from /
? ｢wdm｣: Hash: 6a10213e244bb78370d8
Version: webpack 4.19.1
Time: 949ms
Built at: 2018-10-01 12:41:23
  Asset     Size  Chunks             Chunk Names
main.js  139 KiB       0  [emitted]  main
Entrypoint main = main.js
 [2] multi (webpack)-dev-server/client?http://localhost:8080 ./src 40 bytes {0} [built]
 [3] (webpack)-dev-server/client?http://localhost:8080 7.78 KiB {0} [built]
 [4] ./node_modules/url/url.js 22.8 KiB {0} [built]
 [7] ./node_modules/url/util.js 314 bytes {0} [built]
 [8] ./node_modules/querystring-es3/index.js 127 bytes {0} [built]
[11] (webpack)-dev-server/node_modules/strip-ansi/index.js 161 bytes {0} [built]
[12] (webpack)-dev-server/node_modules/ansi-regex/index.js 135 bytes {0} [built]
[13] ./node_modules/loglevel/lib/loglevel.js 7.68 KiB {0} [built]
[14] (webpack)-dev-server/client/socket.js 1.05 KiB {0} [built]
[15] ./node_modules/sockjs-client/dist/sockjs.js 177 KiB {0} [built]
[16] (webpack)-dev-server/client/overlay.js 3.58 KiB {0} [built]
[18] ./node_modules/html-entities/index.js 231 bytes {0} [built]
[21] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {0} [built]
[23] (webpack)/hot/emitter.js 75 bytes {0} [built]
[25] ./src/index.js 15 bytes {0} [built]
    + 11 hidden modules
```

この状態で、http://localhost:8080 にアクセスすると以下のようになる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/dc19aaee-a03e-8f0f-ad4c-477612719c51.png)

alertでダイアログを出すだけだが、これでもっともシンプルなwebアプリができた。

★ここまでの全ソースコードは[こちら](https://github.com/riversun/es6hello/tree/20181001_simple_example)★

さて、**npm run start**で起動されたWebサーバーはwebpack-dev-serverといい、コマンドラインで**webpack-dev-server**と入力するだけでも起動できる。

この webpack-dev-server の起動条件（起動パラメータ）は細かく定義できるが、いまはとくに何も設定していない。つまりデフォルト動作となる。

**webpack-dev-serverのデフォルト動作** は以下のとおり。

<table>
<tr>
<td>エントリポイント</td><td>./src/index.js</td>
</tr>
<tr><td>コンテンツのルート(content-base)</td><td>/ (ワークディレクトリの直下)</td></tr>
<tr><td>ホスト</td><td>http://localhost:8080</td></tr>
<tr><td>バンドル</td><td>http://localhost:8080/main.js</td></tr>
</table>


### npm runとnpm start

そもそもnpm runとは何か。
npm runとは以下のような構文をとる。

```text
npm run <command>
```

**command**部分は、package.jsonの**script**以下に定義する。

```json:package.json(抜粋)
 "scripts": {
    "start": "webpack-dev-server",
```

この場合は command部分はキーが"start"で実行したいコマンドは "webpack-dev-server"となる。

仮に以下のような定義をしていた場合には

```json:package.json(抜粋)
 "scripts": {
    "dev": "webpack-dev-server",
```

これを実行する場合は **npm run dev**で実行することができる。

```shell
npm run dev
```

ちなみに**npm run**は[**npm run-script**](https://docs.npmjs.com/cli/run-script)のエイリアス（つまり別名）なので[**npm run-script**](https://docs.npmjs.com/cli/run-script)としてもOK。通常**npm run**のほうが短いのでそっちを使う人が多い。

よく使うコマンドは特別扱いされていて、**"start"**、**"stop"**、**"restart"**、**"test"**などは、

```shell
npm start
```
のようにrunをつけずに使うことができる。

つまり **npm run-script start** は **npm run start** とできて、さらに **npm start** でもOKとなる。
今後は **npm start** を使っていく。

# クラスを定義する

ES6からは**クラス**が使えるようになったので、クラスを使ってコードを書いていく。

以下のように./src/hello.jsを作成し、あいさつをするクラスを作ってそれをブラウザで実行できるようにしていく。

```js:hello.js
export default class Hello {

    //コンストラクタ
    constructor() {
    }

    /**
     * 挨拶をする
     * @returns {string}
     */
    sayHello() {
        const hello = 'Hi, there!';
        console.log(hello);
        return hello;
    }
}
```

このクラスは**sayHelloメソッド**を呼び出すと、"Hi,there!"と挨拶するだけのシンプルなプログラム。


## exportとは何か？

exportとは、このモジュールにあるクラスや変数を外部のファイルからも使えるよ、という宣言のこと。
外部のファイル側からは **import**文を使うことで利用できるようになる。


## export default とは何か

export defaultとは何か。

```js
export default class Hello 
```

あるモジュール(jsファイル)には複数の変数や関数やクラスを入れることができ、それぞれの変数や関数やクラスは、それぞれ個別にexportすることができる。

**export default class**のように**default**をつけると、複数のうちこのクラスがメインの処理になりますよ、という風に特別視することができる。
defaultはモジュールにつき1つだけしか宣言できない。

今後、**クラスを使う場合は export default class**のみを使っていく。

export で**default**を使うか使わないかは**import**側での取り扱いが変わってくるのでそちらでみる。

## さっそく exportしたクラスをimportしてみる

ということで、いまexportしたクラスをエントリポイントである./src/index.jsでインポートして使ってみる。

さきほど最初につくったindex.js内容を消して以下のようにする

```js:index.js
import Greeting from './hello.js';

const greeting = new Greeting();
alert(greeting.sayHello());
```

import文は

```js
import Greeting from './hello.js';
```

となる。これは hello.js にある default で宣言されたクラスを **「Greeting という名前で参照するよ」**という宣言となる。ここではあえて参照名を Greetingにしたが、つまり、もとのhello.jsで定義されていた _Hello という名前と同一のものである必要は無い_ということ。

import以降このクラスは Greeting という名前で使うことができるので、
このクラスを new するには以下のようになる。

```js
const greeting = new Greeting();
```

※ 参考：importのバリエーションは[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import)

### 起動してみる

```shell
npm start
```

**npm start** をして http://localhost:8080 にアクセスすると、以下のようになる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/d66cb519-22f0-3b10-03ce-ffcd5a19c965.png)

無事実行できている。
（実際にはJavaScriptをES6の記法のまま実行しているので古いブラウザだと動作しない場合がある、その為の対策=babelは後で説明する）

ちなみに、コンソールのほうにも出力されている。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/2c56f458-ab5c-e0ae-1f6b-97f4fbbebd71.png)

★ここまで(「**クラスを定義する**」)の全ソースコードは[こちら](https://github.com/riversun/es6hello/tree/20181009_es6_class_style_simple_example)★

現在のディレクトリ構成は以下のとおり。

```text

es6hello
├── node_modules
├── src
│   ├── hello.js
│   └── index.js
├── .gitignore
├── index.html
├── package.json
└── package-lock.json
```

jsのコードをブラウザから呼び出す場合は、

```html
<script src="main.js"></script>
```

のようにする。
いままでに作った index.jsとhello.jsはどうなったかというと、それらは main.jsとして1つにマージされ、ブラウザから main.js として呼び出すことができる。

では、**index.jsとhello.jsは、いつマージされるのか**。

こたえ、**ブラウザからのリクエスト時**となる。

ブラウザからの呼び出しに応答するのはwebサーバーでもあるwebpack-dev-serverだが、呼び出し時にwebpack-dev-server経由でindex.jsとhello.jsがマージされ、**main.js**としてアクセスできるようになる。

webpack-dev-serverでホストされているように見せかけられるmain.jsは、ブラウザからアクセスすることができるが、ファイルとしての実体は無く**メモリ上に存在する**。

# webpack-dev-server を便利に設定する

これまでwebpack-dev-serverは特にカスタマイズせずデフォルト動作でつかってきたが、より便利に活用するためにいくつか設定をしていく。

## webpack.config.js とは何か

webpack.config.jsは、webpackやwebpack-dev-serverの挙動を決めるための設定ファイルとなる。
早速、webpack-dev-serverの挙動を設定したいのでルートディレクトリにwebpack.config.jsファイルを作成する。

**現在のディレクトリ構成**

```
es6hello
├── node_modules
├── src
│   ├── hello.js
│   └── index.js
├── .gitignore
├── index.html
├── package.json
├── package-lock.json
└── webpack.config.js
```

## webpack.config.jsを編集する

webpack.config.jsの中身は以下のようにする。

```js:webpack.config.js
const path = require("path");

module.exports = {
    mode: 'development',
    devServer: {
        open: true,
        openPage: "index.html",
        contentBase: path.join(__dirname, "public"),
        watchContentBase: true,
        port: 8080,
    }
};

```

```js
const path = require("path");
```

ここでrequireしている**path**はNode.jsの[標準モジュール](https://nodejs.org/api/path.html#path_path)で、ファイルやディレクトリのパス関連のユーティリティを提供しているモジュール。

下にでてくる

```js
  contentBase: path.join(__dirname, ''),
```
で使われる。（説明はcontentBaseのところで)

```js
 mode: 'development',
```

**mode**=モードの指定はwebpack4以降に必要となっている。指定しないと警告が出る。
[モード](https://webpack.js.org/concepts/mode/)は、webpackによるコードの最適化に関する指定で、"development"と"production"(デフォルト)がある。

今は開発中なので最適化など不要のため "development" を指定する。

### webpack-dev-server関連の設定

webpack.config.jsの**devServer**以下は、webpack-dev-server用の設定となる。
早速みていく。

```js:webpack.config.jsの抜粋
  devServer: {
        open: true,
        openPage: "index.html",
        contentBase: path.join(__dirname, "public"),
        watchContentBase: true,
        port: 8080,
    }
```

上からみていくと、

```js
open: true,
openPage: "index.html",
```

**open:true**は、webpack-dev-server起動時(npm startなどで）に自動的にブラウザを起動する。
**openPage: "index.html"**は、自動的にブラウザを起動するときに開くページを指定している。

```js
contentBase: path.join(__dirname, "public"),
```

**contentBase**には、htmlファイルや画像、CSSなどの**コンテンツのルートディレクトリ**を指定する。

ここで指定している**path.join(__dirname, "public")**をみていく。

[**__dirname**](https://nodejs.org/docs/latest/api/modules.html#modules_dirname)には、現在のモジュールのディレクトリ名が格納される。つまり、es6helloディレクトリが絶対パスで格納される。

**path.join**は複数のパスを区切り文字で連結する関数で、
```path.join("/temp/es6hello","bar")```と指定した場合は ```/temp/es6hello/bar``` を返す。
それなら、```path.join(__dirname, "public")```は ```___dirname+"/public"``` でいいじゃん、と思うかもしれないが、 path.join を使うことによってプラットフォーム間（例えば windowsとlinux)の区切り文字の違いを吸収してくれるので path.join を使っておいた方が良い。

ということで、```contentBase: path.join(__dirname, "public")```によって、es6hello作業ディレクトリ以下**public**というディレクトリがコンテンツのルートディレクトリという設定をした。

そこで、**public**というディレクトリを作り、そこに **index.htmlを移動**させる。
ちなみにwebpack.config.jsを作る前は、webpack-dev-serverのデフォルトの挙動で contentBaseは**/**(ルートディレクトリ直下）に設定されていた。

```js
 watchContentBase: true,
```

**watchContentBase**は、いま設定した contentBase 以下にあるファイルに変更があった場合に自動的にブラウザをリロードする機能の設定となり、これをtrueに設定すると、有効になる。

これにより index.html などを編集して保存すると即座にブラウザがリロードされる。

ちなみに、jsのコードのほうはデフォルトでオートリフレッシュ機能が有効となっているので、これでjsファイルもhtmlも編集したらブラウザのリロードが自動で動作するようになった。

```shell:コマンドライン
npm start
```

npm startでブラウザが自動的に起動し、アプリが実行される。


★ここまで(「**webpack-dev-server を便利に設定する**」)の全ソースコードは[こちら](https://github.com/riversun/es6hello/tree/20181009_added_basic_webpack_config
)★

**現在のディレクトリ構成**

```
es6hello
├── node_modules
├── public
│   └── index.html
├── src
│   ├── hello.js
│   └── index.js
├── .gitignore
├── package.json
├── package-lock.json
└── webpack.config.js
```


## Helloクラスを外部から参照する

いまは、index.jsの中に import 文を書いて Hello クラスを参照しているが、index.html内に書いた```<script>```内から直接 Hello クラスを参照できるようにしたい。

### （１）index.htmlの編集

その為に、まず index.htmlを編集する。

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example</title>
</head>
<body>
<script src="main.js"></script>
<script>
const greeting = new Greeting();
alert(greeting.sayHello());
</script>
</body>
</html>
```

追加した部分は以下となる。

```html
<script>
const greeting = new Greeting();
alert(greeting.sayHello());
</script>
```

つまり、直接、index.htmlの中に```<script>```タグを追加して、Greetingクラスをnewする処理を記述している。

（さきほども書いたが、JavaScriptのこの<font color=red>記法は ES6(ECMAScript6) なので、古いブラウザでは動作しないかも</font>しれない。これに対しては、後で対策をする。最新のChromeなら動作する）

### （２）index.js の編集

index.htmlを修正したが、このままでは動かない。
なぜなら、 Greeting というクラスが外に公開されていないため、外からはアクセスできない。
そこで、index.jsを以下のようにする。


```js:index.js(変更前)
import Greeting from './hello.js';

const greeting = new Greeting();
alert(greeting.sayHello());
```


```js:index.js(変更後)
export { default as Greeting }  from './hello.js';
```

これは、hello.jsにある```default```、つまり```export default class Hello ```と定義されたクラスを```Greeting```という名前でエクスポートしますよ、という宣言となる。

### （３）webpack.config.jsの編集

さらに、index.html内の```<script>```タグからの参照のようにライブラリ的に使いたい場合は、webpack.config.jsを以下のように編集する。

```js:webpack.config.js
const path = require("path");

module.exports = {
    mode: 'development',
    devServer: {
        open: true,
        openPage: "index.html",
        contentBase: path.join(__dirname, 'public'),
        watchContentBase: true,
        port: 8080,
    },
    output: {
        libraryTarget: 'umd'
    }
};

```

追加した部分は

```js
    output: {
        libraryTarget: 'umd'
    }
```

**libraryTarget: 'umd'**をoutput以下に追加することで、ライブラリモードが有効になり、バンドル main.js にあるexportされたクラスや関数にアクセスできるようになる。
**umd**については次の章で触れる。


### 実行

ここまでで実行すると

```shell
npm start
```

以下のように、うまくいった！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/ff270d36-57c9-e5d2-1242-7301942c2e33.png)


★ここまで(「**Helloクラスを外部から参照する**」)の全ソースコードは[こちら](https://github.com/riversun/es6hello/tree/20181108_es6_class_use_externally)★


# webpackを使ってライブラリを作る

ライブラリとは、ある機能（群）の入った独立したjsモジュール。要は**jquery**みたなもので、ブラウザから使う場合には```<script>```タグの中に```<script src="hogehoge.js></script>```のように読み込んで使うことができるものを作る。

もちろん、npmモジュールにしてnpmリポジトリに登録しておけば、package.jsonに依存関係を書くだけで簡単につかえるようにすることも可能。

## webpack.config.jsの編集

webpack.config.jsを以下のようにする


```js:webpack.config.js
const path = require("path");

module.exports = {
    mode: 'development',
    devServer: {
        open: true,
        openPage: "index.html",
        contentBase: path.join(__dirname, 'public'),
        watchContentBase: true,
        port: 8080,
    },
    entry: {app: './src/index.js'},
    output: {
        publicPath: "/js/",
        filename: '[name].js',
        library: ["com", "example"],
        libraryTarget: 'umd'
    }
};

```

以下がポイントなので１つずつみていく。

```js:webpack.config.jsの変更点
    entry: {app: './src/index.js'},
    output: {
        publicPath: "/js/",
        filename: '[name].js',
        library: ["com", "example"],
        libraryTarget: 'umd'
    }
```

<hr>

```js:エントリーをセットする
entry: {app: './src/index.js'},
```

エントリーとはそもそも何か、複数のjsファイルをimportしているファイルと考えておけばOK。
複数のエントリーを扱いときのため、↑のように、連想配列にして指定できる。この例では「**app**というキーに対して**./src/index.js**がエントリーとしてセットされますよ」という意味となる。このペアを複数セットしておくと、複数のバンドルを生成することができる。今は複数不要だが、複数になってもいいようにこの記法で書いておく。

<hr>

```js:バンドルjsのファイル名をセットする
        filename: '[name].js',
```

生成されるバンドルの名前をセットする。
[name]というのはメタ記法で、[name]の中に、上のエントリーで書いたkey名が入るようになる。
上では```{app: './src/index.js'}```としているので、キーが**app**となるので、バンドル生成時には **app.js** というファイルが生成される。webpack-dev-serverからアクセスする場合も同じ。


<hr>

```js:publicPathをセットする
       publicPath: "/js/",
```

ブラウザからバンドルにアクセスする際のjsのパスを指定する。
この例だと、ブラウザには```<script src="js/app.js"></script>```と記述する。つまり**js/**というパスでアクセスできるようになるということ。

<hr>

```js:パッケージ名をセットする
  library: ["com", "example"],
```

これはいわゆるパッケージ名。配列に複数指定すると、
**com.example** のようにピリオドでつないだパッケージ名にすることができる。

パッケージ名は、以下のような形式でexportしたクラスをnewするときに使える。

```js
const greeting = new com.example.Greeting();
```
<hr>

```js:libraryTargetでライブラリ化の方式を指定
  libraryTarget: 'umd'
```

**umd**とは[Universal Module Definition](https://github.com/umdjs/umd)のことで、ライブラリ化するときの方式を指定している。よほどの事情がなければ、**umd**を指定しておけばOK。
ほかにも **amd**(Asynchronous Module Definition)などが指定できるので、詳しくは、https://webpack.js.org/configuration/output/ にて。

## index.htmlを編集

全体は以下の通り、

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example</title>
</head>
<body>
<script src="js/app.js"></script>
<script>
const greeting = new com.example.Greeting();
alert(greeting.sayHello());
</script>
</body>
</html>
```

変更したのは、以下の```js/app.js```のところ。さきほど設定したpublicPathにあわせ**js**にしたところ。

```html
<script src="js/app.js"></script>
```

もう１つの変更は

```html
<script>
const greeting = new com.example.Greeting();
alert(greeting.sayHello());
</script>
```


```com.example``` というパッケージ名で```Greeting```クラスにアクセスしている部分となる。

### 実行する

```
npm start
```

こちらも無事動作！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/4b56a070-8976-6a72-1d5d-3f0c6c44f3f2.png)

# babel(バベル)を使ってすべてのブラウザで動作するようにする

ここまでいくらかJSコードを書いてきたが、これらのコードはすべて ES6 (ECMAScript 6)の記法で書いてきた。

ES6をサポートしていない古いブラウザも未だあるため、こうした古いjsランタイムを搭載したブラウザ向けのjsコードは古いjsコードつまりES5 (ECMAScript 5)のほうが無難である。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/57c18c9d-d779-aa48-d925-0e8ac264173a.png)

でも ES6 のクラスなどを使った方が見通しの良いコードがかけるなど ES6のメリットも多いため、コーディングするときは基本 新しいjs記法(ES7,ES6など) で書いて、ブラウザ向けには書いたコードを古いjsに変換して使う、ということが一般的に行われている。

**babel**というツールを使うと、ES6のコードをES5に自動的に変換できる。つまりコンパイルできる。（トランスパイルと言っているひともいる）


## babelとは何か？
babelは（新しい記法の）jsコードの構造を解析して古いランタイムでも動作するようにコードを変換してくれるもの。

babelの使い方は簡単。何も難しいことは無いので１つずつ見ていく。

### Babel v7をインストールする

以下により、最新のBabel v7をインストールする。

```shell
npm install --save-dev babel-loader @babel/core @babel/preset-env
```

```save-dev``` すると、このプロジェクト用にbabelがインストールされる。
自動的にpackage.jsonのdevDependencies以下にbabel関連の依存関係が追加される


```json:package.json(抜粋)
  "devDependencies": {
    "@babel/core": "^7.1.5",
    "@babel/preset-env": "^7.1.5",
    "babel-loader": "^8.0.4",
    "webpack": "^4.19.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.8"
  }
```


ここまでで、package.jsonは以下のようになっている。

```json:package.json
{
  "name": "es6hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server",
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config webpack.config.js"
  },
  "author": "Tom Misawa <riversun.org@gmail.com> (https://github.com/riversun)",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.1.5",
    "@babel/preset-env": "^7.1.5",
    "babel-loader": "^8.0.4",
    "webpack": "^4.19.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.8"
  }
}

```

これでbabelが利用可能になった。

### webpack4とBabel v7を連携できるようにする

webpack.config.jsに以下を追加する。

```json:webpack.config.js
 module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            [
                                "@babel/preset-env",
                                {
                                    "useBuiltIns": "usage",
                                    "targets": "> 0.25%, not dead"
                                }
                            ]
                        ]
                    }
                }
            }
        ]
    },
    devtool: 'inline-source-map'
```

jsファイルがみつかった場合は babel-loader を呼び出して処理せよ、という意味になる。
```options``` 以下にはbabel側に伝える挙動を記載する。

### @babel/preset-envの意味

```json:(webpack.config.jsから抜粋)
    presets: [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "targets": "> 0.25%, not dead"
            }
        ]
    ]

```


babelをつかって、古いブラウザでも動作するように変換したいが、preset-envでは何をサポートしたいのかを柔軟に指定することができる。

**targets**
ターゲットとなるブラウザ（やelectronなどのjsランタイムを利用した環境）を指定する。
この柔軟なターゲット指定こそbabelの特長でもあり、ありがたい機能でもある。
ここで、 ``` "targets": "> 0.25%, not dead"``` の部分では、市場シェアが0.25％を超えるブラウザーで実行可能な最低限のコード出力せよ、という意味。

**useBuiltIns**
useBuiltInsは polyfill(ポリフィル=ブラウザが新しい機能に対応していない場合、それを補う為に古いブラウザでも動作する代替コードをあてがうこと)に関する設定をするためのもの。

``` "useBuiltIns": "usage"``` は自動的に必要なポリフィルをインポートしてくれる機能で、さらに各ファイルでポリフィルが必要な場合でもバンドルしたときにはポリフィルの読み込みが１回で済むように工夫してくれるオプションとなる。公式では experimental　となっているので、この点を重視しないなら、```"useBuiltIns": "false"``` でもOK。（デフォルトもfalseなので省略も可能）

**targetを省略することも可能**
ちなみに、以下のようにtargetを何も設定しない場合は、すべて強制的にES5に変換される（@babel/preset-es2015、@babel/preset-es2016、@babel/preset-es2017を同時に指定したのと同じ状態）が、せっかくの柔軟にターゲットを指定するbabelの能力を生かせないので<font color=red>推奨しない</font>だそう。

```json:babelでjsコードをとりあえずES5に変換する設定
{
  "presets": ["@babel/preset-env"]
}
```

**@babel/preset-env**のそのほか詳細は以下を参照
https://babeljs.io/docs/en/next/babel-preset-env.html

### ソースマップを出力する

さて、そろそろ終盤に入ってきた。

webpack.config.jsに追加した以下の部分は、ソースマップの出力を有効にしている。

```json
devtool: 'inline-source-map'
```

ブラウザ上でコードを実行するとバグがあってエラーが発生したときには、元のコードの行番号でスタックトレースが表示される。
今回はソースはES6記法で書くが、実際にブラウザ上で実行されるコードはbabelによって変換されたコードとなるため、もしエラーが発生してもこのままだと変換後のコードの行番号でスタックトレースが表示されてしまう。
ここで、上記のソースマップの設定をしておくと、ブラウザで実行するときにも、ソースコードの情報がきちんと埋め込まれる。

```
npm start
```

見た目ではわからないが、ES5のコードが出力された状態で無事実行された。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/9d9b571a-1035-f9c9-5d37-643c628b9978.png)

ここまでで webpack.config.jsは以下のようになっている。

```js:webpack.config.js
const path = require("path");

module.exports = {
    mode: 'development',
    devServer: {
        open: true,
        openPage: "index.html",
        contentBase: path.join(__dirname, 'public'),
        watchContentBase: true,
        port: 8080,
    },
    entry: {app: './src/index.js'},
    output: {
        publicPath: "/js/",
        filename: '[name].js',
        library: ["com", "example"],
        libraryTarget: 'umd'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            [
                                "@babel/preset-env",
                                {
                                    "useBuiltIns": "usage",
                                    "targets": "> 0.25%, not dead"
                                }
                            ]
                        ]
                    }
                }
            }
        ]
    },
    devtool: 'inline-source-map'

};
```

### (コラム)先頭に＠（atmark)がついているパッケージは何か
ちなみに、***@babel/core***のように先頭に＠（atmark)がついているパッケージは何か。
違和感あり？
これは、スコープモジュール(scoped module)という。**@babel**にあたるところをスコープといい、ユーザー名をつけたり組織名をつけたりすることができる。
何でそんなことをしたいかというと、公開されているnpmパッケージの**名前**は早いモンがちで取得できるルールなので、たとえばbabel制作元でもない第三者が babel-xxxx みたいなnpmパッケージ名で登録することもできてしまう。
このように、パッケージ名のバッティングを防いただり、スコープとして組織名をつけて一連のパッケージ名の公式感を出すなどのメリットが期待できる。

詳しくは↓を参照
https://docs.npmjs.com/about-scopes

## バンドルの出力先を指定する

さて、いままでは npm startでwebpack-dev-serverが起動するようにしていたので、
バンドルをファイルとして出力せず webpack-dev-serverのメモリ上に保持していた。

ここでは、バンドルをファイルとして出力してみる。

webpack.config.jsのoutputに以下の1行追加する

```js
path: path.join(__dirname, "dist"),
```

すると↓のようになる。

```js:wbpack.config.js(抜粋)
   output: {
        path: path.join(__dirname, "dist"),
        publicPath: "/js/",
        filename: '[name].js',
        library: ["com", "example"],
        libraryTarget: 'umd'
    },
```

```path: path.join(__dirname, "dist")``` によって、バンドルjs、この場合は、app.js が**[作業ディレクトリ]/dist/app.js** として生成される。

次に、実際にバンドルを生成するためのコマンドをpackage.jsonで設定する
package.jsonのscriptsに

```json
   "build": "webpack --config webpack.config.js"
```

の１行を追加してscript以下を↓のようにする。

```json:package.json
 "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
```

これでpackage.jsonの全体は以下のようになった


```json:package.json
{
  "name": "es6hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Tom Misawa <riversun.org@gmail.com> (https://github.com/riversun)",
  "license": "ISC",
  
  "devDependencies": {
    "@babel/core": "^7.1.5",
    "@babel/preset-env": "^7.1.5",
    "babel-loader": "^8.0.4",
    "webpack": "^4.19.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.8"
  }
}

```

### バンドルjsを生成する

コマンドラインで **npm run build**を実行する

```shell
npm run build

> es6hello@1.0.0 build dev/es6hello
> webpack --config webpack.config.js

Hash: 4c781264bbf44ceb06b4
Version: webpack 4.19.1
Time: 562ms
Built at: 2018-11-10 20:55:40
 Asset      Size  Chunks             Chunk Names
app.js  12.6 KiB     app  [emitted]  app
Entrypoint app = app.js
[./src/hello.js] 1.12 KiB {app} [built]
[./src/index.js] 49 bytes {app} [built]
```

実行すると、distディレクトリに app.js が生成された。

ここまでのディレクトリ構成

```
es6hello
├── dist
│   └── app.js
├── node_modules
├── public
│   └── index.html
├── src
│   ├── hello.js
│   └── index.js
├── .gitignore
├── package.json
├── package-lock.json
└── webpack.config.js
```

★ここまで(「**babel(バベル)を使ってすべてのブラウザで動作するようにする**」)の全ソースコードは[こちら](https://github.com/riversun/es6hello/tree/20181110_es6hello_with_babel_support)★

#ライブラリをnpmモジュールとして公開する

## 公開するために必要な情報を package.jsonに追記する

さて、これまで作ってきたライブラリをnpmモジュールとして公開する準備にとりかかる。

リポジトリの情報やホームページの情報を含む以下のデータをpackage.jsonに挿入する。

```json
  "repository": {
    "type": "git",
    "url": "git+https://github.com/riversun/es6hello.git"
  },
  "bugs": {
    "url": "https://github.com/riversun/es6hello/issues"
  },
  "homepage": "https://github.com/riversun/es6hello#readme",
```

上記をふくめたpackage.jsonの全体は↓のようになる。いよいよこれが**完成版！**となる。

```json:package.json
{
  "name": "es6hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Tom Misawa <riversun.org@gmail.com> (https://github.com/riversun)",
  "license": "ISC",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/riversun/es6hello.git"
  },
  "bugs": {
    "url": "https://github.com/riversun/es6hello/issues"
  },
  "homepage": "https://github.com/riversun/es6hello#readme",
  "devDependencies": {
    "@babel/core": "^7.1.5",
    "@babel/preset-env": "^7.1.5",
    "babel-loader": "^8.0.4",
    "webpack": "^4.19.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.8"
  }
}

```

## 作ってきたすべてのファイルをcommit/pushする

作ってきたファイルをすべてcommitして、
最初に作った GitHubにpushする。

```shell
git push
```

このようにGitHubにプロジェクトを公開しておくことで、ライブラリがnpmとして公開されたとき、GitHubのreadmeを取り込んだ説明ページや、GitHubへのリンクが、npmモジュールのカバーページとしてnpmjs.com側で自動生成される。

## npmjs.comにサインアップする

npmモジュールを公開するにはnpmjs.comにサインアップする必要がある。

https://www.npmjs.com/
にて、画面に従いサインアップする（サインアップがまだの場合）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/cb979d08-bf80-7b72-24d4-cf8a2adc4294.png)


## npmにログインする

サインアップしたら、以下のようにコマンドラインから**npm login**をして、npmjs.comで登録した username、passwordでログインする。

```shell
npm login
Username: riversun
Password:
Email: (this IS public) riversun.org@gmail.com
Logged in as riversun on https://registry.npmjs.org/.
```

## npm publishする

**npm publish**コマンドで、今作ったライブラリをnpmモジュールとして公開することができる。


```shell
npm publish

+ es6hello@1.0.0
```

これで今作った　挨拶クラス　がnpmモジュールとしてライブラリ登録され公開された♪

https://www.npmjs.com/package/es6hello

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170905/cda5fd34-1fe6-5ca1-a0ac-2b23078ca8cb.png)

# まとめ

今風のjs開発の知識がゼロ状態から、Node.jsの環境、npm、webpack4、babelなど使いハンズオンでnpmモジュールを作るところまで説明してきました。

このプロジェクトは https://github.com/riversun/es6hello に公開しています。
jsフロントエンドプロジェクトのひな形としても活用可能です。