最近のフロントエンド事情には全然詳しくないのですが、ちょっと以下のようなことをやろうかなと思いまして。
- 複数のJavaScriptをまとめたい
- まとめたJavaScriptはminifyしたい
- SourceMapも作成したい
- Bowerを使って依存関係も解決したい
Bowerで解決しようとしているのは、他に手段をよく知らないのとクライアントサイドのJavaScriptの依存関係を書くのは、Bowerが一般的なのかなと思いまして。
で、こういうことをやろうとした時、webpackとBrowserifyが目につくのですが、今回はwebpackでやってみました。
以降に、やったことを書いていきます。なお、Bowerで引き込むライブラリは、jQueryとします。
あとで、Browseriry版も書きました。
Broserifyを使ってJavaScriptのビルド/minify(+Bower) - CLOVER
※このエントリ公開後に、@makingさんから「Bowerいらないのでは?」というツッコミをいただいたので、最後にBowerなし版を追記しました
セットアップ
まずは、以下のコマンドを実行。
$ npm init $ npm install -g gulp webpack bower $ npm install gulp gulp-util bower webpack --save-dev $ bower init $ bower install jquery --save
バージョン情報。
$ node --version v4.1.0 $ npm --version 2.14.3 $ bower --version 1.5.2
対象のスクリプトとHTML
動作確認用のソースコードとして、内容はちょっと微妙ですが、このようなものを用意。
エントリポイントです。
scripts/main.js
var $ = require("jquery"); var init = require("./init"); var messages = require("./messages"); init(); $(function() { $("#show-message1").on("click", function() { $("#message1").text(messages.get("message1")); }); $("#show-message2").on("click", function() { $("#message2").text(messages.get("message2")); }); });
scripts/init.js
var $ = require("jquery"); module.exports = function() { $(function() { $("#title").text("webpackとBowerのテストです"); }); };
scripts/messages.js
module.exports = { msgs: { "message1": "Hello Workd", "message2": "こんにちは、世界" }, get: function(id) { return this.msgs[id]; } };
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>webpack & Bower テストページ</title> </head> <body> <h1 id="title"></h1> <div> <input id="show-message1" type="button" value="メッセージ1を表示"> <input id="show-message2" type="button" value="メッセージ2を表示"> </div> <span id="message1"></span><br> <span id="message2"></span><br> <script type="text/javascript" src="dist/scripts/app.js"></script> </body> </html>
gulpfile.jsとwebpack.config.jsを書く
続いて、gulpとwebpackの設定を書いていきます。
まずは、gulpの設定から。
gulpfile.js
var gulp = require("gulp"); var gutil = require("gulp-util"); var webpack = require("webpack"); var webpackConfig = require("./webpack.config.js"); gulp.task("build", function(callback) { var config = Object.create(webpackConfig); webpack(config, function(err, stats) { if(err) throw new gutil.PluginError("webpack", err); gutil.log("[webpack]", stats.toString({ // output options })); callback(); }); }); gulp.task("default", ["build"]);
ほぼ、ここのまんまです。今回はwebpack-dev-serverは外していますが。
http://webpack.github.io/docs/usage-with-gulp.html
続いて、webpackの設定。
webpack.config.js var path = require("path"); var webpack = require("webpack"); module.exports = { cache: true, entry: { app: "./scripts/main.js" // エントリポイント }, output: { path: path.join(__dirname, "dist/scripts"), // 出力先 publicPath: "dist/scripts/", // HTMLなどから参照する時のパス filename: "[name].js", // 生成されるファイルの名前 chunkFilename: "[chunkhash].js", // sourceMapFilename: "[file].map" }, devtool: "#source-map", // sourcemapの作成 resolve: { root: [path.join(__dirname, "bower_components")] }, plugins: [ new webpack.ResolverPlugin( new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"]) ), new webpack.optimize.UglifyJsPlugin() // minify ] };
resolveの部分と、ResolverPluginの中身でBowerとの連携、UglifyJsPluginでminifyの設定となります。
SourceMapを出力するのは、devtoolの指定です。
参考)
http://webpack.github.io/docs/usage-with-bower.html
https://github.com/webpack/webpack-with-common-libs/blob/master/gulpfile.js
https://github.com/webpack/webpack-with-common-libs/blob/master/webpack.config.js
http://webpack.github.io/docs/configuration.html
webpackでbower使って外部ライブラリの依存解決する
実行
この状態でビルドしてみます。
$ gulp [16:08:31] Using gulpfile ~/xxxxx/gulpfile.js [16:08:31] Starting 'build'... [16:08:34] [webpack] Hash: 4cc1371f9c4dbb2c89f2 Version: webpack 1.12.2 Time: 3314ms Asset Size Chunks Chunk Names app.js 86.1 kB 0 [emitted] app app.js.map 704 kB 0 [emitted] app chunk {0} app.js, app.js.map (app) 248 kB [rendered] [0] ./scripts/main.js 348 bytes {0} [built] [1] ./bower_components/jquery/dist/jquery.js 248 kB {0} [built] [2] ./scripts/init.js 136 bytes {0} [built] [3] ./scripts/messages.js 167 bytes {0} [built] WARNING in app.js from UglifyJs Condition always true [./bower_components/jquery/dist/jquery.js:9170,0] [16:08:34] Finished 'build' after 3.34 s [16:08:34] Starting 'default'... [16:08:34] Finished 'default' after 11 μs
ビルド後のファイルと、SourceMapができています、と。
$ ls -l dist/scripts 合計 776 -rw-rw-r-- 1 xxxxx xxxxx 86161 9月 21 16:08 app.js -rw-rw-r-- 1 xxxxx xxxxx 704141 9月 21 16:08 app.js.map
あとは、一緒に置いていたindex.htmlをブラウザで開いて確認すれば、動作していることが確認できます。
Bowerなし版
このエントリを公開後、@makingさんにこんなツッコミをいただきました。
@kazuhira_r webpack使うのならbowerいらないのでは。npm install jquery --save-devでよ
ふむ、npmだけで完結できる場合はBowerなくてもいいんですか。それならそれでもよいですね。
ただし…
@kazuhira_r あ、bowerにはあってnpmにはないってもの(今風でないのもの)もちょいちょいありそうですね。
@kazuhira_r npmが用意されていないライブラリはメンテナンスされていなさげ・・
手順としては、構築時のコマンドがこうなって
※Bower関連がなくなり、jQueryがnpm installになりました
$ npm init $ npm install -g gulp webpack $ npm install gulp gulp-util webpack jquery --save-dev
gulpfile.jsは変わりません。
gulpfile.js
var gulp = require("gulp"); var gutil = require("gulp-util"); var webpack = require("webpack"); var webpackConfig = require("./webpack.config.js"); gulp.task("build", function(callback) { var config = Object.create(webpackConfig); webpack(config, function(err, stats) { if(err) throw new gutil.PluginError("webpack", err); gutil.log("[webpack]", stats.toString({ // output options })); callback(); }); }); gulp.task("default", ["build"]);
webpackの設定から、Bowerまわりをごっそり落としました。
webpack.config.js
var path = require("path"); var webpack = require("webpack"); module.exports = { cache: true, entry: { app: "./scripts/main.js" // エントリポイント }, output: { path: path.join(__dirname, "dist/scripts"), // 出力先 publicPath: "dist/scripts/", // HTMLなどから参照する時のパス filename: "[name].js", // 生成されるファイルの名前 chunkFilename: "[chunkhash].js", // sourceMapFilename: "[file].map" }, devtool: "#source-map", // sourcemapの作成 plugins: [ new webpack.optimize.UglifyJsPlugin() // minify ] };
@makingさん、ありがとうございました!