Angular + webpack + bootstrap の開発環境構築③

環境が整ったので、実際にサンプルを作成していきたいと思います。
Angular + webpack + bootstrap の開発環境構築①、②での内容のまとめ的にもなるかと思います。

ソースについては、Githubで公開していますので、そちらも合わせてどうぞ。
むしろ、説明読むよりソース見たほうが分かりやすいかも
https://github.com/yohei-takara/JavaScriptEnvironment.git

# ディレクトリ構成

以前も書いたが、サーバサイドにJavaやRubyを使用することを想定しているので、
webpack で生成されるソースと、元のソースは、別ディレクトにて管理を行うことにした。
元のソースを管理するディレクトリ名が良いのが思いつかなかったので、webpackとしている・・・
う〜ん。なんか微妙な気もするが取り敢えず気にしないことにした(*´﹃｀*)

実際のディレクトリ構成はこんな感じにしていこうと思う。

```
|--- public                // 外部に公開するディレクトリ  
|  |-- assets              // webpack で 生成したjs,cssが吐かれるディレクトリ  
|  |-- index.html          // サンプルHTML。
|
|--- webpack               // webpack でのコンパイル対象となるファイルはここに配置  
|  |-- src                 // コンパイル前のソースを配置
|  |-- package.json        // npm 設定ファイル
|  |-- webpack.config.js   // webpack 設定ファイル
|
```

# HTMLの作成

動作確認としては、Angularとbootstrapが動くのを確認できれば良いと思うので、
angular は、双方向データバインド、bootstrap は、tooltipをだすようなシンプルなhtmlにしたいと思う。

webpackで生成されたcssは、public/assets/stylesheets/***.bundle.css
javascriptは、public/assets/javascript/***.bundle.js
とする予定なので、読み込むスタイルは、

```
<link rel="stylesheet" href="assets/stylesheets/application.bundle.css">
```

javascriptについては、

```
<script type="text/javascript" src="assets/javascript/application.bundle.js"></script>
```

### bootstrap tooltipの確認

bootstrapのtooltipについては、公式に使い方なども細かく載っているので割愛します。
http://v4-alpha.getbootstrap.com/components/tooltips/

tooltipは、fontoAwesomeのアイコンに対して出すことにします。

```
<div data-toggle="tooltip" data-placement="top" data-html="true" title="<div class='tooltip-inner'>Webpack Environment!!!!!</div>">
    <i class="fa fa-thumbs-o-up fa-5x" aria-hidden="true"></i>
</div>
```

### angular 双方向データバインドの確認

inputで入力した内容と同じものが画面に表示されるような構成にする。
inputの内容を変更すれば、表示されている文字も変わるので、データバインドの確認ができる。

```
<div ng-app="app"  ng-cloak>
    <div ng-controller="webpackEnvironmentCtrl" ng-init="init()">
        <input type="text" ng-model="demo" ng-value="demo">
        <div>{{ demo }} </div>
    </div>
</div>
```

# Scriptの作成

javascriptとしては、angularとbootstrap tooltipを動作させるために、jqueryの二つを書く必要があります。


### tooltip

公式ページだと

```
$(function () {
  $('[data-toggle="tooltip"]').tooltip()
})
```

このように書かれていますが、これだと、angularのng-repeatなどで、Domを動的に変更した際に、tooltipが出ない(動的に生成した箇所については)ので、ちょっと変更し、

```js:actionTooltip.js
$(function() {
    //ツールチップ
    $('body').tooltip({
        selector: '[data-toggle="tooltip"]'
    });
});
```

とします。


### angular

angularについては、
webpackの確認もあるので、わざわざ分ける必要もないですが、
moduleとcontorllerの二つを別ファイルとして作成することにします。

moduleは、今後SAPとして、拡張させたいと思うので、予め ngRoute を DIしています。
今回行う内容だけでいうといらないです。

```js:module.js
module.exports.angApp = angular.module("app", ["ngRoute"]);
```

controller もシンプルにinit処理のみを記述したものを作成します。

```js:controller.js
let angModule = require('./module');
require('./config');

angModule.angApp.controller("webpackEnvironmentCtrl", ['$scope', "$log", function($scope, $log) {
    $scope.init = function() {
        $log.debug('Webpack Environment!!!!!!!!!!!');
        $scope.demo = 'Webpack Environment!!!!!!!!!!!';
    };

}]);
```

書いていて、Debug logについては、開発時のみ出したいと思い、config も追加しました。

```js:config.js
let angModule = require('./module');

angModule.angApp.config(["$logProvider", function($logProvider) {
    // $log.debug の表示設定
    $logProvider.debugEnabled(true);
}]);
```

とします。


# Webpack でのコンパイル

コンパイル対象となるjsを作成します。

```js:webpackEnvironment.js
// style library
require("bootstrap/dist/css/bootstrap.css");
require("bootstrap/dist/css/bootstrap-theme.min.css");
require("font-awesome/css/font-awesome.css");

// javascript library
let $ = require("jquery");
let angular = require("angular");
require("bootstrap/dist/js/bootstrap.js");
require("angular-cookies");
require("angular-route");

// jquery module
require("./javascript/jquery/actionTooltip");
// angular module
require("./javascript/angular/controller");
```

この作成したjsについてwebpackでコンパイルを行うようにします。

```js:webpack.config.js
var DEBUG = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === undefined;
var webpack = require('webpack');
var path = require('path');

var ExtractTextPlugin = require('extract-text-webpack-plugin');

var devtool = DEBUG ? '#inline-source-map' : '#eval';
var plugins = [ new webpack.ProvidePlugin({ jQuery: "jquery", $: "jquery", jquery: "jquery" }), new ExtractTextPlugin('stylesheets/[name].bundle.css') ];

if (!DEBUG) {
    plugins.push( new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) );
}

module.exports = {
    entry: {
        'application': './src/webpackEnvironment.js',
    },
    output: {
        path: '../public/assets',
        filename: 'javascript/[name].bundle.js'
    },
    devtool: devtool,
    plugins: plugins,
    resolve: {
      root: [ path.join(__dirname, "node_modules") ],
      extensions: ['', '.js', '.css']
    },
    module: {
        loaders: [
            // **IMPORTANT** This is needed so that each bootstrap js file required by
            // bootstrap-webpack has access to the jQuery object
            { test: /bootstrap\/js\//, loader: 'imports?jQuery=jquery' },

            // loads css
            { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
            { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?mimetype=image/svg+xml' },
            { test: /\.woff(\d+)?(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?mimetype=application/font-woff' },
            { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?mimetype=application/font-woff' },
            { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?mimetype=application/font-woff' }
        ]
    }
};
```

productionとdevelopmentを変更できるように、npm のスクリプトを作成します。

```js:package.json
{
  "name": "webpackTest",
  "version": "1.0.0",
  "description": "webpack test project",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "clean": "rm -r node_modules/ && npm cache clean",
    "devBuild": "NODE_ENV=development webpack --display-error-details",
    "build": "NODE_ENV=production webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "angular": "^1.5.9",
    "angular-cookies": "^1.5.9",
    "angular-route": "^1.5.9",
    "bootstrap": "^3.3.7",
    "font-awesome": "^4.7.0",
    "jquery": "^2.2.4"
  },
  "devDependencies": {
    "css-loader": "^0.26.1",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.9.0",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.13.3"
  }
}
```


これで、準備が整いましたので、webpackを動かしていきます。

```
$ npm run build
```

または、

```
$ npm run devBuild
```

本番用と開発用の違いとしては、
本番用は、「souce-mapなし,minify化しコンパイルを行う」
開発用は、「souce-mapあり,minify化せずにコンパイルを行う」
といった感じです。

これで、public/assets/ 以下に生成されたjsとcssができているので
index.htmlをブラウザで開き動作するか確認が取れれば完了です。

# 今回やってみての課題

angularのconfigで、$logProviderの設定を

```
$logProvider.debugEnabled(true);
```

としてしまっている。
これだと、折角webpackでproductionとdevelopを分けられるようにしていても、debug log については、ソースを手修正しなければならなく、とても良くない。

どうにか、ここについても、webpackで切り替えられるようにしたい╭( ･ㅂ･)و ̑̑ ｸﾞｯ !


### 2016/12/09 追記

http://qiita.com/mikakane/items/5ab96c4c7e187ab6c9f1
の記事を真似して、debug log の出力有無をwebpackで変更できるように修正。

```webpack.config.js
var LOG_ENV = false;
var plugins = [];

if (DEBUG) {
  LOG_ENV = true;
}

plugins.push( new webpack.DefinePlugin( { DEBUG_LOG_ENV: LOG_ENV  }) );
```

```angular.js
$logProvider.debugEnabled( DEBUG_LOG_ENV );
```

1. webpack plugin のDefinePlugin　を使用し、DEBUG_LOG_ENV を設定する。
2. DEBUG_LOG_ENV は、productionの場合 true, develop の場合 false となるように設定
3. angular の config にて, $logProvider.debugEnabled() の値に、 DEBUG_LOG_ENV を設定する。

これで、開発時は、log出力し、デバッグを行いやすいようにし、本番環境では、log出力を行わないようにする設定が、webpackのトランスパイルで行えるようになった。

これと同様にして、環境毎に異なる値を設定しなくてはいけない場合もソースを変更せずに設定できるはずなので色々と使いどころが多そうな気がする。

[Angular + webpack + bootstrap の開発環境構築①](http://qiita.com/TKR/items/d886c584925a291b785e)
[Angular + webpack + bootstrap の開発環境構築②](http://qiita.com/TKR/items/0a0eb0b25a72eb16134f)
[Angular + webpack + bootstrap の開発環境構築③](http://qiita.com/TKR/items/a6556d2b84318648ef4d)