Help us understand the problem. What is going on with this article?

ES2015(ES6)+webpack+babel-loaderで開発環境を構築

More than 1 year has passed since last update.

やること

ES2015(ES6)とwebpackを組み合わせて、簡単なWebアプリケーションを作ってみます。
webpack はjsやcssなど、webページで読み込まれる部品の依存関係を解決し、合成してくれるモジュールバンドラーです。

webpackはgulp,gruntなどのタスクランナーと組み合わせて使うことも多いですが、今回は使用しません。

以下の条件を満たすプロジェクトを作成します。

  • classを継承する
  • classをimportして使用する
  • IE11が対応していない、ES6のPromiseを使う

開発環境

  • Mac OS X High Sierra
  • Webpack 4.20.2

Node.jsをインストール

必要なモジュールはnpm(Node Package manager)でインストールが出来ます。
まずはNode.jsをインストールします。
brew install node

これでnpmが使えるようになります。

ディレクトリ構成

今回は以下のようなディレクトリ構成を実現します。

dist
└── main.js
lib
├── BusinessMember.js
└── Member.js
node_modules
.babelrc
index.js
index.html
package.json
webpack.config.js

プロジェクトの作成

まずは任意のディレクトリを作成し、その中で以下コマンドでプロジェクトを作成します。
-yオプションをつけないと、各種項目について都度聞かれます。
-yを付けずにそのままEnterを連打してもかまいません。

$ npm init -y

実行するとpackage.jsonが出来上がります。
後述しますが、このファイルに記載されたライブラリ全てをnpm installで
インストールできるようになりますので、他の人に配布する際に環境構築が簡単にできます。

各種モジュールのインストール

npmで必要な各種モジュールのインストールをします。

2018/10/3現在、babel-loaderの最新バージョンは8系になります。
8系と7系でコマンドやファイルの内容が異なりますので、2つのバージョンについて説明をします。
以下、バージョンについて特に記載がないものは、どちらでも使用可能です。

babel-loader8用
$ npm install --save-dev @babel/core @babel/polyfill @babel/preset-env babel-loader webpack webpack-cli
babel-loader7用
$ npm install --save-dev babel-core babel-polyfill babel-preset-env babel-loader@7 webpack webpack-cli

ビルド時には必要ですが実行時には不要なパッケージなので、--save-dev で入れます。

また、特定のバージョンをインストールしたい場合には、インストールできるバージョンの一覧が以下のコマンドで確認できますので、使用するといいでしょう。

$ npm info パッケージ名 versions --json

--save-devを付けると package.json のdevDependenciesに記載されます。

モジュールが無い状態でnpm installを実行すると、
devDependenciesに書かれたライブラリがnode_modulesにインストールされます。
そのためgit管理からはnode_modulesディレクトリは外して問題ありません。

これでライブラリのインストールが終わりました。

確認をしてみましょう。
npm ls で確認が出来ます。--depth 0をつけるとトップのモジュールのみが確認できます。

$ npm ls --depth 0
├── @babel/core@7.1.2
├── @babel/polyfill@7.0.0
├── @babel/preset-env@7.1.0
├── babel-loader@8.0.4
├── webpack@4.20.2
└── webpack-cli@3.1.2

HTML,jsファイルの作成

次にHTML,jsファイルを作成します。

lib/Member.js

lib/Member.js
'use strict';

export default class Member {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getName() {
        return this.lastName + ' ' + this.firstName;
    }

    get firstName() {
        return this._firstName;
    }

    set firstName(value) {
        this._firstName = value;
    }

    get lastName() {
        return this._lastName;
    }

    set lastName(value) {
        this._lastName = value;
    }
}

lib/BusinessMember.js

lib/BusinessMember.js
'use strict';

import Member from './Member';

export default class BusinessMember extends Member{
    constructor(firstName, lastName, company) {
        super(firstName, lastName);  // 親クラスのコンストラクタは、コンストラクタの1行目で記載する必要がある
        this.company = company;
    }

    get company() {
        return this._company;
    }

    set company(value) {
        this._company = value;
    }

    getName() {
        return this.lastName + ' ' + this.firstName + '/' + this.company;
    }
}

index.js

index.js
'use strict';

import BusinessMember from './lib/BusinessMember';

let pro = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('ok');
    }, 500)
});

pro.then(response => {
    let user = new BusinessMember('taro', 'yamada', 'G社');
    console.log(user.getName());
});

index.html

index.html
<!DOCTYPE html>
<html lang="ja-jp">
<head>
    <meta charset="UTF-8">
    <script src="dist/main.js"></script>
    <title>ES6のテスト</title>
</head>
<body>

</body>
</html>

webpackの準備

最後にwebpackを実行するための設定ファイルを作成します。
.babelrcには、Babelの設定を記載します。
webpack.config.jsの中に書くことも出来ますが、本格的な開発では分けることが多いと思いますので、分けました。

envの指定は、よくあるbabel-preset-envの書き方です。
https://babeljs.io/docs/plugins/preset-env/

.babelrc(babel-loader8用)

.babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry"
      }
    ]
  ]
}

.babelrc(babel-loader7用)

.babelrc
{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

webpack.config.js にはwebpackコマンド実行時の設定を記載します。

webpack.config.js(babel-loader8用)

webpack.config.js
module.exports = {
  mode: 'development',
  devtool: 'source-map',
  entry: ['@babel/polyfill', './index.js'], // polyfill はIE11などで必要
  output: {
    path: `${__dirname}/dist`,
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  }
};

webpack.config.js(babel-loader7用)

webpack.config.js
module.exports = {
  mode: 'development',
  devtool: 'source-map',
  entry: ['babel-polyfill', './index.js'], // babel-polyfill はIE11などで必要
  output: {
    path: `${__dirname}/dist`,
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  }
};

webpack実行

それではwebpackを実行します。

$ npx webpack
Hash: 53476175c174b19d1a89
Version: webpack 4.20.2
Time: 2695ms
Built at: 2018/10/03 1:56:45
      Asset     Size  Chunks             Chunk Names
    main.js  370 KiB    main  [emitted]  main
main.js.map  294 KiB    main  [emitted]  main
Entrypoint main = main.js main.js.map
[./index.js] 300 bytes {main} [built]
[./lib/BusinessMember.js] 2.95 KiB {main} [built]
[./lib/Member.js] 1.37 KiB {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 509 bytes {main} [built]
[0] multi @babel/polyfill ./index.js 40 bytes {main} [built]
    + 276 hidden modules

これでmain.jsが出来上がりました。

動作確認

ChromeやIE11でindex.htmlにアクセスし、コンソールに yamada taro/G社 と表示されれば成功です。

npm scriptsの編集

npm scriptsにコマンドを記載することで、簡単に処理が実行できます。
package.jsonの scripts にコマンドを記載します。
webpackは --watch を付けることで、対象となるファイルが更新されたときに自動でビルドを実行することが可能です。
watch という名前で実行できるようにしましょう。
ついでに、webpack自体はbuildという名前で実行できるようにしておきます。

package.json

  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch"
  },

以下のようにコマンドを実行すると監視のジョブが常駐します。
jsファイルに何かしら処理の変更を加えると、ビルドが自動的に走ることが確認できます。

$ npm run watch

おまけ

Jestでテストを行う

Jestを使ってテストを書いていきます。
JestはFacebook製のJSのテストツールです。
https://facebook.github.io/jest/en/

まずはJestをインストールしましょう。

$ npm install --save-dev jest

次にテスト用のディレクトリであるtestを作成します。

$ mkdir test

testディレクトリの中にテストを作っていきます。

test/BusinessMember.test.js
'use strict';

import BusinessMember from '../lib/BusinessMember';

test('BusinessMember.getName() to be "firstName lastName/company"', function() {
  let user = new BusinessMember('ken', 'sato', 'A社');
  expect(user.getName()).toBe('sato ken/A社');
});
test/Member.test.js
'use strict';

import Member from '../lib/Member';

test('Member.getName() to be "firstName lastName"', function() {
  let user = new Member('ken', 'sato');
  expect(user.getName()).toBe('sato ken');
});

それではテストを実行しましょう。

$ npx jest
 PASS  test/BusinessMember.test.js
 PASS  test/Member.test.js

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.195s
Ran all test suites.

testという名前で npm scripts にも記載します。

package.json

  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch",
    "test": "jest"
  },

testというコマンドについては、npm runrunは不要ですので、以下のように実行できます。

$ npm test

以下のように引数を渡せば、カバレッジを取ることも可能です。

$ npm test -- --coverage
> jest "--coverage"

 PASS  test/BusinessMember.test.js
 PASS  test/Member.test.js
-------------------|----------|----------|----------|----------|-------------------|
File               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files          |      100 |      100 |      100 |      100 |                   |
 BusinessMember.js |      100 |      100 |      100 |      100 |                   |
 Member.js         |      100 |      100 |      100 |      100 |                   |
-------------------|----------|----------|----------|----------|-------------------|

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.352s
Ran all test suites.

参考記事

d-dai
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away