なぜタスクランナーを使ったほうがいいのかをデザイナーに伝えるためにまとめた

近年のフロントエンド制作現場ではgrunt, gulp などのタスクランナーや、
browserify, webpackなどのビルドツールを使用するのが半ば常識となっています。
なぜこういったツールを使うのか、社内のデザイナーに伝えるためにまとめてみました。

##タスクランナーとは?
現在要求されるレベルで成果物のクオリティを担保するためには、以下のような多岐にわたる処理が必要になります。

必要になる処理の例

  • テンプレートエンジンによるHTMLファイルの生成
  • CSSプリプロセッサによるCSSの生成&圧縮
  • CSSスプライトの作成
  • JavaScriptファイルの依存関係解決&圧縮
  • Alt-JSファイルの変換
  • 各種画像の最適化
  • 他多数…

これら全てを手作業で行うのは、非現実的な選択肢と言えます。
そこで、こういったタスクを全て自動化するためのツールがgrunt/gulpに代表される、タスクランナーと呼ばれるツールです。

###ビルドツール
極々小規模なプロジェクト(数十行で完結する程度のもの)を除いて、browserify, webpackなどのビルドツールを用いて
JavaScriptファイルを生成する事が、スタンダードになってきています。

これには以下のような理由があります。

  • CoffeeScriptTypeScriptなど、AltJSの普及によって、実行用のJavaScriptファイルへの変換が必要になった
  • 既存のJavaScriptにはモジュール機構が存在しないため、全ての関数がグローバルになってしまう問題があった(※2015年夏頃より勧告されるES6ではimport文によるモジュール機構が実装される)
  • モジュール機構が存在しないため、サードパーティ製ライブラリに対する依存状態が管理できず、運用が進むにつれてライブラリの要・不要が判別できなくなることが多かった
  • モジュール機構が存在しないため、手作業によるライブラリの読み込みの設定を余儀なくされた。そのため読み込み順によっては動作しないコードが出てくる問題があった

こういった問題を解決するために、browserify, webpackに代表される、ビルドツールが用いられるようになりました。
ビルドツールによるビルド処理も、タスクランナーを用いて行われます。

##導入
grunt, gulpは共に、node.jsというサーバーサイドJavaScript実行環境(PCで直接JavaScriptを実行出来るようになるソフトウェア、と考えれば大体正しいです)を用いて実装されています。
grunt, gulpのどちらも、使い方や導入方法、出来ることに大きな差はありません。
各タスクの処理の仕方の差で、gulpの方が動作が速いので、新規のプロジェクトであればgulpを使うのをお勧めします。

詳しい導入方法を説明した記事は無数にあるので、grunt 導入とかgrunt how to useなどでググって下さい。

以下なんかはわりと詳しく載っていてお勧めです。
Web デザイナーさん向け Grunt を使った コーディング作業の効率化、はじめの一歩

###大体の手順

  1. node.jsをインストール
  2. grunt-cli(Gruntコマンドラインクライアント)をインストール
  3. 各プロジェクトでGruntタスクを実行可能に

一応これで伝わるかな。。。
ついでに普段使ってるgulpfile.jsの雛形も置いておきます

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
gulp = require 'gulp'
browserSync = require 'browser-sync'
reload = browserSync.reload
data = require 'gulp-data'
util = require('gulp-util')
debug = require 'gulp-debug'
newer = require 'gulp-newer'
compass = require 'gulp-compass'
sourcemaps = require 'gulp-sourcemaps'
minify = require 'gulp-minify-css'
del = require('del')
# browserify
browserify = require 'browserify'
debowerify = require 'debowerify'
licensify = require 'licensify'
source = require 'vinyl-source-stream'
streamify = require 'gulp-streamify'
uglify = require 'gulp-uglify'
buffer = require 'vinyl-buffer'
# jade
jade = require 'gulp-jade'
# images
pngmin = require 'gulp-pngmin'
imagemin = require 'gulp-imagemin'
jpegtran = require 'imagemin-jpegtran'
# watch
watch = require 'gulp-watch'
# deploy
scp = require 'scp'
src =
js : './src/javascript'
css : './src/sass'
html : './src/jade'
image : './src/image'
copy : './src/copy'
build =
js : './build/public'
css : './build/public'
html : './build'
image : './build/public/image'
env =
isProduct : false
deployToProduct : false
rootDev: '/path/to/staging'
rootPro: '/path/to/production'
gulp.task 'deploy', ->
dest = env.rootDev
if env.deployToProduct
dest = env.rootPro
else
dest = env.rootDev
scp.send(
file : './deploy/*'
host : 'hostname'
user : 'username'
path : dest
, (e) ->
util.beep()
console.log e
)
gulp.task 'changeEnv', ->
env.isProduct = true
build =
js : './deploy/public'
css : './deploy/public'
html : './deploy'
image : './deploy/public/image'
gulp.task 'changeDeployEnv', ->
env.deployToProduct = true
gulp.task 'css', ->
if env.isProduct
gulp.src(src.css + '/*.sass')
.pipe compass(
css : build.css
sass : src.css
)
.pipe minify()
.pipe gulp.dest(build.css)
else
gulp.src(src.css + '/*.sass')
.pipe sourcemaps.init()
.pipe compass(
css : build.css
sass : src.css
)
.pipe sourcemaps.write('./')
.pipe gulp.dest(build.css)
gulp.task 'html', ->
if env.isProduct
opt = pretty : false
else
opt = pretty : true
gulp.src(src.html + '/*.jade')
.pipe data (file) ->
return require src.html + '/index.json'
.pipe(jade(opt))
.pipe gulp.dest(build.html)
.on 'error', (e) ->
util.beep();
console.log e
return
gulp.task 'js', ->
if env.isProduct
browserify
entries : [src.js + '/index.coffee']
extensions : ['.coffee', '.js']
.plugin licensify
.transform 'coffeeify'
.transform 'debowerify'
.bundle()
.pipe source('bundle.min.js')
.pipe buffer()
.pipe streamify uglify()
.pipe gulp.dest(build.js)
else
browserify
entries : [src.js + '/index.coffee']
extensions : ['.coffee', '.js']
.plugin licensify
.transform 'coffeeify'
.transform 'debowerify'
.bundle()
.pipe source('bundle.min.js')
.pipe buffer()
.pipe sourcemaps.init
loadMaps : true
.pipe streamify uglify()
.pipe sourcemaps.write('./')
.pipe gulp.dest(build.js)
gulp.task 'pngmin', ->
gulp.src([
src.image + '/*.png'
src.image + '/**/*.png'
])
.pipe newer build.image
.pipe pngmin()
.pipe gulp.dest build.image
gulp.task 'jpgmin', ->
gulp.src([
src.image + '/*.jpg'
src.image + '/**/*.jpg'
])
.pipe imagemin(
prpgressive : true
svgoPlugins : [{removeViewBox : false}]
use : [jpegtran()]
)
.pipe gulp.dest build.image
gulp.task 'copy-dir', ->
gulp.src([
src.copy + "/*"
src.copy + "/**/*"
src.copy + "/**/**/*"
])
.pipe(gulp.dest(build.html))
gulp.task 'copy-img', ->
gulp.src([
src.image + '/*.gif'
src.image + '/**/*.gif'
src.image + '/**/**/*.gif'
])
.pipe(gulp.dest(build.image))
gulp.task 'img', [
'pngmin'
'jpgmin'
'copy-img'
]
gulp.task 'browser', ->
browserSync server :
baseDir : 'build'
directory : true
return
gulp.task 'clean', (cb) ->
del([
'deploy/'
], cb)
gulp.task 'watch', ->
gulp.watch([
src.js + '/*.coffee'
src.js + '/**/*.coffee'
], [
'js'
reload
])
gulp.watch([
src.html + '/*.jade'
src.html + '/**/*.jade'
], [
'html'
reload
])
gulp.watch([
src.css + '/*.sass'
src.css + '/**/*.sass'
], [
'css'
reload
])
gulp.watch([
src.image + '/*'
src.image + '/**/*'
], [
'img'
reload
])
return
gulp.task 'default', [
'css'
'js'
'html'
'img'
'copy-dir'
]
gulp.task 'server', [
'default'
'browser'
'watch'
]
gulp.task 'build', [
'clean'
'changeEnv'
], ->
gulp.run 'default'
gulp.task 'staging', [
'deploy'
]
gulp.task 'production', [
'changeDeployEnv'
'deploy'
]