webpack + gulp + karma でファイルの監視を Dockerを使って試したメモ

[前回][link]の続きです。

# 環境作成

```share/Dockr/karma/Dockerfile.
FROM node:4.2.4

RUN mkdir -p /usr/karma/share
WORKDIR /usr/karma

#package.jsonを書き出し
RUN echo '{ "name": "my_karma","scripts": {"tests": "karma start", "watch":"gulp watch", "build":"webpack" } }' > package.json

# karmaのインストール
RUN npm install --save-dev jasmine-core
RUN npm install --save-dev karma
RUN npm install --save-dev karma-jasmine
RUN npm install --save-dev jasmine
RUN npm install --save-dev karma-phantomjs-launcher

# webpackのインストール
RUN npm install --save-dev webpack
RUN npm install --save-dev babel-core babel-preset-es2015 babel-preset-react
RUN npm install --save-dev eslint
RUN npm install --save-dev pre-commit precommit-hook
RUN npm install --save-dev lodash
RUN npm install --save-dev react

RUN npm install --save-dev eslint-loader
RUN npm install --save-dev babel-loader
RUN npm install --save-dev css-loader
RUN npm install --save-dev react-hot-loader
RUN npm install --save-dev style-loader

# タスクランナーインストール
RUN npm install --save-dev gulp 
RUN npm install --save-dev require-dir 
RUN npm install --save-dev gulp-if 

#gulpfileを書き出し
RUN echo "var requireDir = require('require-dir'); requireDir('share/karma/gulp/tasks', { recurse: true }); " > gulpfile.js 

# babelで使用するpresetsの書き出し
RUN echo '{"presets": ["es2015"]}' > .babelrc
```

# フォルダ構造

```
share
  + Docker
  + shell
  - dev
    - karma
      - gulp
        - tasks
           - watch.tasks.js
           - webpack.tasks.js
           - karma.tasks.js
      - webpack
          - webpack.config.js
          - configs
              - _base.js
              - development.js
      - test
        + dist
        - test-context.js
        - source
          - .eslintrc
          - calculator.js
        - spec
          - .eslintrc
          - calclator-spec.js
```

# webpackの設定
```share/dev/karma/webpack/webpack.config.js
// @file webpack.config.js
require('babel-core/register');
module.exports = require('./configs/development');
```

```share/dev/karma/webpack/configs/_base.js
// @file configs/webpack/_base.js
// 共通の設定を記述します

import path from 'path';

export const src = path.resolve(__dirname, '../../test');
export const dist = path.resolve(__dirname, '../../test/dist');

export default {
  entry: [
    `${src}/test-context.js` // entry point
  ],
  output: {
    path: dist,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      }
    ]
  },
  resolve: {
    extensions: ['', '.js']  // require, import時に拡張子を省略できるようにする
  },
  plugins: []
};
```

```share/dev/karma/webpack/configs/development.js
// @file configs/webpack/development.js
// 開発時の設定を記述します

import base from './_base';

const webpackConfig = Object.assign(base, {
  // custom configs on development
  devtool: 'source-map'
});

export default webpackConfig;
```

# karmaの設定

```share/dev/karma/karma.conf.js
module.exports = function(config) {
  config.set({
    browsers: ['PhantomJS'],
    files: [ { pattern: './test/dist/bundle.js', watched: false } ],
    frameworks: ['jasmine'],
    singleRun:true,
    port: 9876,
    colors:false
  }); 
};
```

# gulpの設定

ファイルの監視をgulpに任せて、後はそれぞれのツールを一度ずつ実行する設定にしてみた。


```share/dev/karma/gulp/tasks/watch.tasks.js
var gulp = require('gulp');

gulp.task('watch',['karma',"webpack"],function(){
  gulp.watch([__dirname + '/../../test/source/*.js',__dirname + '/../../test/spec/*.js'],['webpack']);

  gulp.watch([__dirname + '/../../test/dist/*.js'],['karma']);
});
```

```share/dev/karma/gulp/tasks/webpack.tasks.js
var gulp = require('gulp');
var spawn = require('child_process').spawn;

gulp.task('webpack',function(){
  spawn('npm', ['run-script', 'build', "--", "--config", "./share/karma/webpack/webpack.config.js", "--progess", "--colors"], {stdio: ['pipe', process.stdout, 'pipe']});
});

```

```share/dev/karma/gulp/tasks/karma.tasks.js
var gulp = require('gulp');
var spawn = require('child_process').spawn;

gulp.task('karma',function(){
  spawn('npm', ['run-script', 'tests', "--", "./share/karma/karma.conf.js"], {stdio: ['pipe', process.stdout, 'pipe']} );
});

```

# テストファイルの設定

```dev/karma/test/test-context.js
var context = require.context(
                './spec', 
                true, 
                /-spec\.js$/
              );
context.keys().forEach(context);
```

```dev/karma/test/source/calculator.js
export class Calculator{ 
  add(op1,op2){ return op1 + op2; } 
  subtract(op1,op2){ return op1 - op2; }
}
```

```dev/karma/test/spec/calculator-spec.js
import {Calculator} from '../source/calculator'; 

describe('Calculator', () => { 
  it('should add two numbers', () => { 
    let calculator = new Calculator(); 
    let sum = calculator.add(1,4); 
    expect(sum).toBe(5); 
  });

  it('should subtract two numbers', () => { 
    let calculator = new Calculator(); 
    let sum = calculator.subtract(4,1); 
    expect(sum).toBe(3); 
  });

});
```

# 実行
```share/shell/karma_docker_start.sh
#!/bin/bash

source "/home/vagrant/share/shell/env.conf"
docker run -it --name $containerName_karma --rm \
           -v $path_dev_dir:/usr/karma/share \
           $imageName_karma /bin/bash -c \
           'npm run-script watch'
```
これで実行してやると、ファイルの監視を行ってテストまでできる。
結果、重い。
karmaもwebpackも自身で監視ができるので、大分冗長になっているのかもしれない。


#参考サイト
[karma Configuration File][link-1]
[webpack+babel-loader+power-assert+jsdomでフロントエンド開発環境を作る][link-2]
[gulp.jsを使ってフロントエンドのビルドをする【webpack, stylus】][link-3]
[node.js 4.2 doc child process][link-4]
[「Jasmine」、「Node.js」、「jasmine-node」、「Jenkins」でJavaScriptをテストしてみた。][link-5]
[Writing Jasmine unit tests in ES6][link-6]

[link]:http://qiita.com/hibohiboo/items/fc2aeac8193ba26b45af

[link-1]:http://karma-runner.github.io/0.8/config/configuration-file.html
[link-2]:http://yutapon.hatenablog.com/entry/webpack%2Bbabel-loader%2Bpower-assert%2Bjsdom-skeleton
[link-3]:http://yutapon.hatenablog.com/entry/2014/12/06/123000
[link-4]:https://nodejs.org/dist/latest-v4.x/docs/api/child_process.html#child_process_child_process
[link-5]:http://d.hatena.ne.jp/yamap_55/20140425/1398436457
[link-6]:http://www.syntaxsuccess.com/viewarticle/writing-jasmine-unit-tests-in-es6