webpackを使った開発の効率化方法やloaderの種類をTLで話してきました【スライド付き】


webpackを使った開発の効率化方法やloaderの種類をTLで話してきました【スライド付き】

こんにちは、まろCです。
2月に2本のLTに登壇してきたのですが、どちらもwebpackを題材にして喋ってきました。

今回は、そのときのスライドを共有したいと思います。また、すぐに使えるインストール方法もあわせて解説したいと思います。

webpackとは

webpack-module-bundler1

webpackとは、一言でいうと依存性を解決するツールです。
HTML上に、何本もscriptタグでJavaScriptを読み込んでいたものを、1本のJSにしてパックします。
エントリーポイントと呼ばれるJSにrequireと書いて、他のJSを読み込むことで、ビルド時にそれを探して1つのJSファイルの中に書き出してくれます。
自作のモジュールを、パスから引っ張ってきたりbowerから引っ張ってきたりできるのはもちろん、node_modulesからも使えるものは使えたりと何でもありなツール。
とは言え、できることが多いわりに日本語の情報が少なく、理解に時間がかかることもあります。

では、早速LTのスライドからご紹介したいと思います。

2/12 LIG・SHIFTBRAIN・Uniba合同LT会:別冊ライトニングトーク Vol.1

こちらでは、概要といいところをざっくり挙げました。
browserifyなどの他のツールではなくwebpackを選択したのは、複数のエントリーポイントと、JSだけでなくHTMLやCSS、画像といったところまでパックできるからです。
いいところとしては、以下のとおり。

  • requireを意識することで、JSを機能ごとの部品でつくる意識になる(共通で使えるものはファイルを分けてclassな書き方でmodule.exportsしておくなど)。
  • 例えば、PC/SPディレクトリに分けている開発環境の場合、共通に使いたいJSを1つの場所からrequireすれば、わざわざコピーして使わなくてもいい。
  • jQueryなどグローバルに出す設定をすることで、requireせずに使用できる。
  • loaderが素晴らしい。

2/18 第7回 HTML5minutes! 〜triton-js〜

こちらではwebpackのハイライト的な機能であるloaderの中から、使ってみてよかったものをランキングとして発表したので、ご紹介したいと思います。

第3位 coffee-loader

CoffeeScriptで書いたモジュールをrequireできるloader。ビルド時にJSにコンパイルしてパックしてくれます。

インストール

npm install coffee-loader --save-dev

第2位 url-loader

画像などのファイルをrequireできるloader。小さいサイズの画像なら、data-uriで保持してくれます。
Google マップを使うJSで使いました。開発用のパスでビルドしても、データとして保持しているので本番がWordPressでディレクトリが違っても、画像が404にならないところがいいですね。

 markerOptions =
    position: latlngTokyo
    map: map
    icon: require 'url?mimetype=image/png!../../../assets/images/icon-pin.png'
    title: ''
marker = new google.maps.Marker markerOptions

インストール

npm install url-loader --save-dev

第1位 underscore-template-loader

HTMLで記述したunderscoreのテンプレートをrequireできるloader。ビルド時は文字列を返す関数としてパックされる。元のHTMLファイルにscriptで書いていたものを分離することで、メンテナンス性や再利用性が上がります。

インストール

npm install underscore-template-loader --save-dev

まだまだ使えるloaderはたくさんありますので、探してみてください!

参照ページ:loaders – webpack

gulpと一緒に軽く使ってみる

せっかくなので、gulpなプロジェクト上で動かしてみます。必要なのはいつもの通り、node.jsとgulpです。

インストール

npm install webpack gulp-webpack --save-dev

設定ファイルとタスクファイル

gulp上で動かすので、webpackのタスクファイルとそれを動かす設定ファイルを作成します。その設定ファイルを、webpack.config.jsという名前で作成します。
bowerでインストールしたプラグインなどを使いやすいようにaliasで書くところ、loaderを設定するところがポイントとなります。

var webpack = require("webpack");
var path = require('path');

module.exports = {
    output: {
        filename: "module.js" //出力されるファイル名
    },
    resolve: {
        extensions: ['', '.js', '.coffee', '.html'], //拡張子を省略できる
        modulesDirectories: ['node_modules', 'bower_components'],
        alias: { //bowerでインストールしたjqueryプラグインで以下にaliasを貼るとrequire('TweenMax');のようにパス無しでつかえる
            bower: 'bower_components',
            TweenLite: __dirname + '/bower_components/gsap/src/uncompressed/TweenLite.js',
            TweenMax: __dirname + '/bower_components/gsap/src/uncompressed/TweenMax.js',
            TimelineLite: __dirname + '/bower_components/gsap/src/uncompressed/TimelineLite.js',
            TimelineMax: __dirname + '/bower_components/gsap/src/uncompressed/TimelineMax.js',
            ScrollMagic: __dirname + '/bower_components/ScrollMagic/js/jquery.scrollmagic.js',
            bxSlier: __dirname + '/bower_components/bxslider/jquery.bxSlider.min.js',
            niceScroll: __dirname + '/bower_components/nicescroll/jquery.nicescroll.js',
            colorbox: __dirname + '/bower_components/colorbox/jquery.colorbox.js'
        }
    },
    module: {
        loaders: [ //使用するloaderを記述ココに書く場合とrequire時にパスの前に書くものとがある
            { test: /\.coffee$/, loader: 'coffee' },
            { test: /\.html/, loader: "underscore-template-loader" }
        ]
    },
    plugins: [
        new webpack.ResolverPlugin(
            new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
        ),
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.AggressiveMergingPlugin(),
        new webpack.ProvidePlugin({ //jqueryはグローバルに出す設定。これでrequireせず使えるのでjqueryプラグインもそのまま動く。
            jQuery: "jquery",
            $: "jquery",
            jquery: "jquery"
        })
    ]
};

 
タスクファイルはこんな感じです。

var gulp = require('gulp');    
var conf = require('../webpack.config.js');
var webpack = require("gulp-webpack");

module.exports = function () {
    gulp.task('webpack',function() {
        gulp.src('main.coffee') //エントリーポイントはmain.coffeeです
        .pipe(webpack(conf)) //gulp-webpackを実行します。
        .pipe($.uglify()) //圧縮します
        .pipe(gulp.dest('module.js'))
        .pipe($.browser.reload({stream: true}));
    });
}();

ちょっと調略して書いていますので、パスなどは適宜お使いの環境に合わせてください。

エントリーポイントとモジュール

webpackはエントリーポイントに使いたいモジュールをrequireすることで、ビルド時にその先のJSであったりファイルであったりの中身を見に行って、1つのJSにパックしてくれます。

エントリーポイント

main.coffee

window._ = require 'underscore'
ScrollMagicObject = require 'ScrollMagic'
window.ScrollMagic = ScrollMagicObject.Controller
window.ScrollScene = ScrollMagicObject.Scene

require './module/corporate'
require './module/index'
require './module/interview'

お気付きかと思いますが、webpack.config.jsで書く拡張子の省略をする設定をしていますので、わざわざ拡張子まで書く必要はありません。jQueryも、グローバルに出す設定をしているので、わざわざrequireする必要はありません。

windowにunderscoreをrequireして読み込みます。jQueryプラグインであるScrollMagicは一工夫必要で、一旦requireしたものをControllerとSceneで2つに分けてグローバルに出します。他のプラグインは使いたい箇所でrequireしてその場で読み込みます。
./moduleでrequireしているファイルは、各ページで使うモジュールです。

 
例えば、「./module/index.coffee」はどうなっているかというと・・・

---抜粋---
$window = $(window)
ajaxData = require './AjaxData'
FadeSlider = require './FadeSlider'
SETTING = require './setting'

newsData = new ajaxData SETTING.NEWS_URL+'?count=5', 'GET', 'json' //requireしたものをnewして使います
$.when newsData.getData()
.done (NewsData) ->
    drawNews feedData

drawNews = (data) ->
    html = require '../template/news.html' //underscoreのテンプレートをrequireしています。
    template = _.template html()
    $newsListInner.html template
        data: data

$slider = $('#js-mainSlider')
    slider = new FadeSlider
        $wrapper: $slider
        $target: $slider.find('li')
        speed: 1
        duration: 5000

ちなみにFadeSlider.coffeeはプラグインとして作成したので、commonjsの形式で記述しました。
webpackは基本的にどんな書き方でも受け付けてくれますが、commonjsの形式で書くことで、node.jsと同じ考えでJSを書けます。

 
今回のモジュールだけは、それにならって書いていきます。

---抜粋---
class FadeSlider
    constructor: (option) ->
      ------

module.exports = FadeSlider

こうすると、newしたときにconstructorが呼ばれて〜というようなクラスを持つ言語のように記述できます(coffeescriptの書き方です)。

モジュールをrequireして、定数などのSETTINGファイルもrequireしています。あとはだいたいnewして、その中の機能を呼び出すだけです。
このようにビルド時にはmain.coffee内でrequireされたindex.coffeeをたどった際、index.coffee内でrequireしているものの中まで再帰的にたどって中身をパックします。

ビルド

gulpタスクを呼び出せば、任意の場所にmodule.jsが出力されます。

gulp webpack

こいつをHTML内に、

<script src="module.js"></script>

と書けばOKです。

まとめ

いかがでしたか?
このすばらしい依存性解決ツールを使って、順番を気にしてJSを圧縮して1つにするだけだった生活から抜け出しましょう!
初の登壇ということで、資料を作るのも苦労しました。5分で伝えたいことをまとめるのは難しいし、それを人前で話すのも思っていたようにはいきませんでした。
これから場数を踏んで思いを伝えることができるようになっていきたいです。

それでは。

 

【webpackの関連記事】

エンジニアがいい感じにフロントエンド開発を爆速化できる環境構築の手順

ECMAScript6で書こう!WebPackとES6-loaderで環境を作り、ES6を先取り体験する方法

WebPackを使ってJavaScriptを効率的に書くチュートリアル【入門編】

この記事を書いた人

まろ
まろ フロントエンドエンジニア 2014年入社
フロントエンドエンジニアのまろCです。
コンセプト設計中心でものづくりしています。