Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. | 2 Copyright 2016 The LUCI Authors. All rights reserved. |
| 3 Use of this source code is governed under the Apache License, Version 2.0 | 3 Use of this source code is governed under the Apache License, Version 2.0 |
| 4 that can be found in the LICENSE file. | 4 that can be found in the LICENSE file. |
| 5 | 5 |
| 6 This document has been largely derived from the Polymer Starter Kit: | 6 This document has been largely derived from the Polymer Starter Kit: |
| 7 https://github.com/PolymerElements/polymer-starter-kit | 7 https://github.com/PolymerElements/polymer-starter-kit |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 'use strict'; | 10 'use strict'; |
| 11 | 11 |
| 12 var path = require('path'); | 12 var path = require('path'); |
| 13 var argv = require('yargs').argv; | 13 var argv = require('yargs').argv; |
| 14 | 14 |
| 15 var exports = module.exports = {} | 15 var exports = module.exports = {} |
| 16 exports.base = path.join(__dirname, '..'); | 16 exports.base = path.join(__dirname, '..'); |
| 17 exports.out = (argv.out || exports.base); | 17 exports.out = (argv.out || exports.base); |
| 18 exports.plugins = require('gulp-load-plugins')({ | 18 exports.plugins = require('gulp-load-plugins')({ |
| 19 config: path.join(exports.base, 'package.json'), | 19 config: path.join(exports.base, 'package.json'), |
| 20 }); | 20 }); |
| 21 | 21 |
| 22 // Include Gulp & tools we'll use | 22 // Include Gulp & tools we'll use |
| 23 var $ = exports.plugins; | 23 var $ = exports.plugins; |
| 24 var browserSync = require('browser-sync'); | |
| 25 var debug = require('gulp-debug'); | |
| 24 var del = require('del'); | 26 var del = require('del'); |
| 25 var requireDir = require('require-dir'); | 27 var foreach = require('gulp-foreach'); |
| 26 var runSequence = require('run-sequence'); | |
| 27 var browserSync = require('browser-sync'); | |
| 28 var reload = browserSync.reload; | |
| 29 var merge = require('merge-stream'); | |
| 30 var fs = require('fs'); | 28 var fs = require('fs'); |
| 31 var glob = require('glob-all'); | 29 var glob = require('glob-all'); |
| 32 var historyApiFallback = require('connect-history-api-fallback'); | 30 var historyApiFallback = require('connect-history-api-fallback'); |
| 33 var crypto = require('crypto'); | 31 var hyd = require('hydrolysis'); |
|
Ryan Tseng
2016/12/06 03:38:11
I'm but a simple python engineer, but the number o
| |
| 32 var merge = require('merge-stream'); | |
| 33 var pathExists = require('path-exists'); | |
| 34 var reload = browserSync.reload; | |
| 35 var rename = require('gulp-rename'); | |
| 36 var requireDir = require('require-dir'); | |
| 37 var runSequence = require('run-sequence'); | |
| 38 var through = require('through2'); | |
| 39 var ts = require('gulp-typescript'); | |
| 40 | |
| 34 | 41 |
| 35 var AUTOPREFIXER_BROWSERS = [ | 42 var AUTOPREFIXER_BROWSERS = [ |
| 36 'ie >= 10', | 43 'ie >= 10', |
| 37 'ie_mob >= 10', | 44 'ie_mob >= 10', |
| 38 'ff >= 30', | 45 'ff >= 30', |
| 39 'chrome >= 34', | 46 'chrome >= 34', |
| 40 'safari >= 7', | 47 'safari >= 7', |
| 41 'opera >= 23', | 48 'opera >= 23', |
| 42 'ios >= 7', | 49 'ios >= 7', |
| 43 'android >= 4.4', | 50 'android >= 4.4', |
| 44 'bb >= 10' | 51 'bb >= 10' |
| 45 ]; | 52 ]; |
| 46 | 53 |
| 47 exports.setup = function(gulp, config) { | 54 exports.setup = function(gulp, config) { |
| 48 var APP = path.basename(config.dir); | 55 var APP = path.basename(config.dir); |
| 56 var BUILD = path.join('.tmp', 'build'); | |
| 49 var DIST = path.join(exports.out, 'dist', APP); | 57 var DIST = path.join(exports.out, 'dist', APP); |
| 50 | 58 |
| 51 var layout = { | 59 var layout = { |
| 52 app: APP, | 60 app: APP, |
| 53 distPath: DIST, | 61 distPath: DIST, |
| 54 | 62 |
| 55 // NOTE: Takes vararg via "arguments". | 63 // NOTE: Takes vararg via "arguments". |
| 56 dist: function() { | 64 dist: function() { |
| 57 return extendPath(DIST).apply(null, arguments); | 65 return extendPath(DIST).apply(null, arguments); |
| 58 }, | 66 }, |
| 59 }; | 67 }; |
| 60 | 68 |
| 61 var extendPath = function() { | 69 var extendPath = function() { |
| 62 var base = [].slice.call(arguments); | 70 var base = [].slice.call(arguments); |
| 63 return function() { | 71 return function() { |
| 64 // Simple case: only base, no additional elements. | 72 // Simple case: only base, no additional elements. |
| 65 if (base.length === 1 && arguments.length === 0) { | 73 if (base.length === 1 && arguments.length === 0) { |
| 66 return base[0]; | 74 return base[0]; |
| 67 } | 75 } |
| 68 | 76 |
| 69 var parts = base.concat(); | 77 var parts = base.concat(); |
| 70 parts.push.apply(parts, arguments) | 78 parts.push.apply(parts, arguments) |
| 71 return path.join.apply(null, parts); | 79 return path.join.apply(null, parts); |
| 72 }; | 80 }; |
| 73 }; | 81 }; |
| 74 | 82 |
| 75 var styleTask = function(stylesPath, srcs) { | 83 var styleTask = function(stylesPath, srcs) { |
| 76 return gulp.src(srcs.map(function(src) { | 84 return gulp.src(srcs.map(function(src) { |
| 77 return path.join(stylesPath, src); | 85 return path.join(BUILD, stylesPath, src); |
| 78 })) | 86 })) |
| 79 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS)) | 87 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS)) |
| 80 .pipe(gulp.dest('.tmp/' + stylesPath)) | 88 .pipe(gulp.dest('.tmp/' + stylesPath)) |
| 81 .pipe($.minifyCss()) | 89 .pipe($.minifyCss()) |
| 82 .pipe(gulp.dest(layout.dist(stylesPath))) | 90 .pipe(gulp.dest(layout.dist(stylesPath))) |
| 83 .pipe($.size({title: stylesPath})); | 91 .pipe($.size({title: stylesPath})); |
| 84 }; | 92 }; |
| 85 | 93 |
| 86 var imageOptimizeTask = function(src, dest) { | 94 var imageOptimizeTask = function(src, dest) { |
| 87 return gulp.src(src) | 95 return gulp.src(path.join(BUILD, src)) |
| 88 .pipe($.imagemin({ | 96 .pipe($.imagemin({ |
| 89 progressive: true, | 97 progressive: true, |
| 90 interlaced: true | 98 interlaced: true |
| 91 })) | 99 })) |
| 92 .pipe(gulp.dest(dest)) | 100 .pipe(gulp.dest(dest)) |
| 93 .pipe($.size({title: 'images'})); | 101 .pipe($.size({title: 'images'})); |
| 94 }; | 102 }; |
| 95 | 103 |
| 96 var optimizeHtmlTask = function(src, dest) { | 104 var optimizeHtmlTask = function(src, dest) { |
| 97 var assets = $.useref.assets({ | 105 var assets = $.useref.assets({ |
| 98 searchPath: ['.tmp', 'app'] | 106 searchPath: ['.tmp', config.dir] |
| 99 }); | 107 }); |
| 100 | 108 |
| 101 return gulp.src(src) | 109 return gulp.src(src, {cwd: BUILD}) |
| 102 .pipe(assets) | 110 .pipe(assets) |
| 103 // Concatenate and minify JavaScript | 111 // Concatenate and minify JavaScript |
| 104 .pipe($.if('*.js', $.uglify({ | 112 .pipe($.if('*.js', $.uglify({ |
| 105 preserveComments: 'some' | 113 preserveComments: 'some' |
| 106 }))) | 114 }))) |
| 107 // Concatenate and minify styles | 115 // Concatenate and minify styles |
| 108 // In case you are still using useref build blocks | 116 // In case you are still using useref build blocks |
| 109 .pipe($.if('*.css', $.minifyCss())) | 117 .pipe($.if('*.css', $.minifyCss())) |
| 110 .pipe(assets.restore()) | 118 .pipe(assets.restore()) |
| 111 .pipe($.useref()) | 119 .pipe($.useref()) |
| 112 // Minify any HTML | 120 // Minify any HTML |
| 113 .pipe($.if('*.html', $.minifyHtml({ | 121 .pipe($.if('*.html', $.minifyHtml({ |
| 114 quotes: true, | 122 quotes: true, |
| 115 empty: true, | 123 empty: true, |
| 116 spare: true | 124 spare: true |
| 117 }))) | 125 }))) |
| 118 // Output files | 126 // Output files |
| 119 .pipe(gulp.dest(dest)) | 127 .pipe(gulp.dest(dest)) |
| 120 .pipe($.size({ | 128 .pipe($.size({ |
| 121 title: 'html' | 129 title: 'html' |
| 122 })); | 130 })); |
| 123 }; | 131 }; |
| 124 | 132 |
| 133 gulp.task('build', function() { | |
| 134 // Copy application directories. | |
| 135 var app = gulp.src([ | |
| 136 '**', | |
| 137 '!inc', | |
| 138 ]).pipe(gulp.dest(BUILD)); | |
| 139 | |
| 140 var inc = gulp.src('inc/**/*', { cwd: exports.base }) | |
| 141 .pipe(gulp.dest(path.join(BUILD, 'inc'))); | |
| 142 return merge(app, inc); | |
| 143 }); | |
| 144 | |
| 125 // Compile and automatically prefix stylesheets | 145 // Compile and automatically prefix stylesheets |
| 126 gulp.task('styles', function() { | 146 gulp.task('styles', ['build'], function() { |
| 127 return styleTask('styles', ['**/*.css']); | 147 return styleTask('styles', ['**/*.css']); |
| 128 }); | 148 }); |
| 129 | 149 |
| 130 gulp.task('elements', function() { | 150 gulp.task('elements', ['build'], function() { |
| 131 return styleTask('elements', ['**/*.css']); | 151 return styleTask('elements', ['**/*.css']); |
| 132 }); | 152 }); |
| 133 | 153 |
| 134 // Optimize images | 154 // Optimize images |
| 135 gulp.task('images', function() { | 155 gulp.task('images', ['build'], function() { |
| 136 return imageOptimizeTask('images/**/*', layout.dist('images')); | 156 return imageOptimizeTask('images/**/*', layout.dist('images')); |
| 137 }); | 157 }); |
| 138 | 158 |
| 159 // Transpiles "inc/*/*.ts" and deposits the result alongside their source | |
| 160 // "ts" files. | |
| 161 gulp.task('tsinline', function() { | |
| 162 // Transpile each TypeScript module independently into JavaScript in the | |
| 163 // BUILD directory. | |
| 164 var incDir = path.join(exports.base, 'inc') | |
| 165 var tsconfigPath = path.join(incDir, 'tsconfig.json'); | |
| 166 var tsProj = ts.createProject(tsconfigPath, { | |
| 167 typeRoots: [path.join(exports.base, 'node_modules', '@types')], | |
| 168 }); | |
| 169 return gulp.src('*/*.ts', { cwd: incDir }) | |
| 170 .pipe(tsProj()) | |
| 171 .pipe(gulp.dest(incDir)); | |
| 172 }); | |
| 173 | |
| 174 var tsCompileSingle = function(tsconfigPath, dest) { | |
| 175 // Transpile each TypeScript module independently into JavaScript in the | |
| 176 // BUILD directory. | |
| 177 return pathExists(tsconfigPath).then( (exists) => { | |
| 178 if ( !exists ) { | |
| 179 return; | |
| 180 } | |
| 181 | |
| 182 var tsProj = ts.createProject(tsconfigPath, { | |
| 183 target: 'ES5', // Vulcanize can't handle ES6 ATM. | |
| 184 removeComments: true, | |
| 185 module: "amd", | |
| 186 outFile: 'ts-app.js', | |
| 187 typeRoots: [path.join(exports.base, 'node_modules', '@types')], | |
| 188 }); | |
| 189 return gulp.src('main.ts', { cwd: path.join(BUILD, 'scripts-ts') }) | |
| 190 .pipe(tsProj()) | |
| 191 .pipe(rename(function(fpath) { | |
| 192 fpath.dirname = "."; | |
| 193 })) | |
| 194 .pipe(gulp.dest(dest)); | |
| 195 } ); | |
| 196 }; | |
| 197 | |
| 198 // Builds the project's "ts-app.js" into the project directory. | |
| 199 gulp.task('tsproject', function() { | |
| 200 return tsCompileSingle( | |
| 201 path.join(BUILD, 'scripts-ts', 'tsconfig.json'), | |
| 202 path.join('scripts') ); | |
| 203 }); | |
| 204 | |
| 205 gulp.task('ts', ['build'], function() { | |
| 206 return tsCompileSingle( | |
| 207 path.join(BUILD, 'scripts-ts', 'tsconfig.json'), | |
| 208 path.join(path.join(BUILD, 'scripts')) ); | |
| 209 }); | |
| 210 | |
| 139 // Copy all files at the root level (app) | 211 // Copy all files at the root level (app) |
| 140 gulp.task('copy', function() { | 212 gulp.task('copy', ['build'], function() { |
| 141 // Application files. | 213 // Application files. |
| 142 var app = gulp.src([ | 214 var app = gulp.src([ |
| 143 '*', | 215 '*', |
| 144 '!inc', | 216 '!inc', |
| 145 '!test', | 217 '!test', |
| 146 '!elements', | 218 '!elements', |
| 147 '!bower_components', | 219 '!inc/bower_components', |
| 148 '!cache-config.json', | 220 '!cache-config.json', |
| 149 '!**/.DS_Store', | 221 '!**/.DS_Store', |
| 150 '!gulpfile.js', | 222 '!gulpfile.js', |
| 151 '!package.json', | 223 '!package.json', |
| 152 ]).pipe(gulp.dest(layout.dist())); | 224 '!scripts-ts', |
| 225 ], { | |
| 226 cwd: BUILD, | |
| 227 }).pipe(gulp.dest(layout.dist())); | |
| 153 | 228 |
| 154 // Copy over only the bower_components we need | 229 // Copy over only the bower_components we need |
| 155 // These are things which cannot be vulcanized | 230 // These are things which cannot be vulcanized |
| 156 var webcomponentsjs = gulp.src([ | 231 var webcomponentsjs = gulp.src([ |
| 157 'inc/bower_components/webcomponentsjs/webcomponents-lite.min.js', | 232 'inc/bower_components/webcomponentsjs/webcomponents-lite.min.js', |
| 158 ]).pipe(gulp.dest(layout.dist('inc/bower_components/webcomponentsjs/'))); | 233 ], { |
| 234 cwd: BUILD, | |
| 235 }).pipe(gulp.dest(layout.dist('inc/bower_components/webcomponentsjs/'))); | |
| 236 | |
| 237 var requirejs = gulp.src([ | |
| 238 'inc/bower_components/requirejs/require.js', | |
| 239 ], { | |
| 240 cwd: BUILD, | |
| 241 }).pipe(gulp.dest(layout.dist('inc/bower_components/requirejs/'))); | |
| 159 | 242 |
| 160 var includes = (config.includes) ? (config.includes(gulp, layout)) : ([]); | 243 var includes = (config.includes) ? (config.includes(gulp, layout)) : ([]); |
| 161 return merge(app, includes, webcomponentsjs) | 244 return merge(app, includes, webcomponentsjs, requirejs) |
| 162 .pipe($.size({ | 245 .pipe($.size({ |
| 163 title: 'copy' | 246 title: 'copy' |
| 164 })); | 247 })); |
| 165 }); | 248 }); |
| 166 | 249 |
| 167 // Copy web fonts to dist | 250 // Copy web fonts to dist |
| 168 gulp.task('fonts', function() { | 251 gulp.task('fonts', ['build'], function() { |
| 169 return gulp.src(['fonts/**']) | 252 return gulp.src(['fonts/**'], {cwd: BUILD}) |
| 170 .pipe(gulp.dest(layout.dist('fonts'))) | 253 .pipe(gulp.dest(layout.dist('fonts'))) |
| 171 .pipe($.size({ | 254 .pipe($.size({ |
| 172 title: 'fonts' | 255 title: 'fonts' |
| 173 })); | 256 })); |
| 174 }); | 257 }); |
| 175 | 258 |
| 176 // Scan your HTML for assets & optimize them | 259 // Scan your HTML for assets & optimize them |
| 177 gulp.task('html', function() { | 260 gulp.task('html', ['build'], function() { |
| 178 return optimizeHtmlTask( | 261 return optimizeHtmlTask( |
| 179 ['**/*.html', '!{elements,test,inc}/**/*.html'], | 262 ['**/*.html', '!{elements,test,inc}/**/*.html'], |
| 180 layout.dist()); | 263 layout.dist()); |
| 181 }); | 264 }); |
| 182 | 265 |
| 183 // Vulcanize granular configuration | 266 // Vulcanize granular configuration |
| 184 gulp.task('vulcanize', function() { | 267 gulp.task('vulcanize', ['build', 'ts'], function() { |
| 185 return gulp.src('elements/elements.html') | 268 var fsResolver = hyd.FSResolver |
| 269 return gulp.src('elements/elements.html', {cwd: BUILD}) | |
| 186 .pipe($.vulcanize({ | 270 .pipe($.vulcanize({ |
| 187 stripComments: true, | 271 stripComments: true, |
| 188 inlineCss: true, | 272 inlineCss: true, |
| 189 inlineScripts: true | 273 inlineScripts: true, |
| 190 })) | 274 })) |
| 191 .pipe(gulp.dest(layout.dist('elements'))) | 275 .pipe(gulp.dest(layout.dist('elements'))) |
| 192 .pipe($.size({title: 'vulcanize'})); | 276 .pipe($.size({title: 'vulcanize'})); |
| 193 }); | 277 }); |
| 194 | 278 |
| 195 // Clean output directory | 279 // Clean output directory |
| 196 gulp.task('clean', function() { | 280 gulp.task('clean', function() { |
| 197 var dist = layout.dist(); | 281 var dist = layout.dist(); |
| 198 var remove = ['.tmp', path.join(dist, '*')]; | 282 var remove = ['.tmp', path.join(dist, '*')]; |
| 199 var keep = '!'+path.join(dist, '.keep'); | 283 var keep = '!'+path.join(dist, '.keep'); |
| 200 return del(remove.concat(keep), {force: true, dot:true}); | 284 return del(remove.concat(keep), {force: true, dot:true}); |
| 201 }); | 285 }); |
| 202 | 286 |
| 203 // Watch files for changes & reload | 287 // Watch files for changes & reload |
| 204 gulp.task('serve', ['styles', 'elements'], function() { | 288 gulp.task('servebuild', ['build'], function() { |
| 289 gulp.watch([ | |
| 290 '**', | |
| 291 '!.tmp', | |
| 292 ], ['build']); | |
| 293 }); | |
| 294 | |
| 295 // Watch files for changes & reload | |
| 296 gulp.task('serve', ['default'], function() { | |
| 205 browserSync({ | 297 browserSync({ |
| 206 port: 5000, | 298 port: 8000, |
| 299 ui: { | |
| 300 port: 8080, | |
| 301 }, | |
| 207 notify: false, | 302 notify: false, |
| 208 logPrefix: 'PSK', | 303 logPrefix: 'PSK', |
| 209 snippetOptions: { | 304 snippetOptions: { |
| 210 rule: { | 305 rule: { |
| 211 match: '<span id="browser-sync-binding"></span>', | 306 match: '<span id="browser-sync-binding"></span>', |
| 212 fn: function(snippet) { | 307 fn: function(snippet) { |
| 213 return snippet; | 308 return snippet; |
| 214 } | 309 } |
| 215 } | 310 } |
| 216 }, | 311 }, |
| 217 // Run as an https by uncommenting 'https: true' | 312 // Run as an https by uncommenting 'https: true' |
| 218 // Note: this uses an unsigned certificate which on first access | 313 // Note: this uses an unsigned certificate which on first access |
| 219 // will present a certificate warning in the browser. | 314 // will present a certificate warning in the browser. |
| 220 // https: true, | 315 // https: true, |
| 221 server: { | 316 server: { |
| 222 baseDir: ['.tmp', 'app'], | 317 baseDir: [BUILD], |
| 223 middleware: [historyApiFallback()] | 318 middleware: [historyApiFallback()] |
| 224 } | 319 } |
| 225 }); | 320 }); |
| 226 | 321 |
| 227 gulp.watch(['**/*.html'], reload); | 322 gulp.watch(['**/*.html'], ['html', reload]); |
| 228 gulp.watch(['styles/**/*.css'], ['styles', reload]); | 323 gulp.watch(['styles/**/*.css'], ['styles', reload]); |
| 229 gulp.watch(['elements/**/*.css'], ['elements', reload]); | 324 gulp.watch(['elements/**/*.css'], ['elements', reload]); |
| 230 gulp.watch(['images/**/*'], reload); | 325 gulp.watch(['images/**/*'], ['build', reload]); |
| 326 gulp.watch(['inc/**/*'], { cwd: exports.base }, ['ts', reload]); | |
| 231 }); | 327 }); |
| 232 | 328 |
| 233 // Build and serve the output from the dist build | 329 // Build and serve the output from the dist build |
| 234 gulp.task('serve:dist', ['default'], function() { | 330 gulp.task('serve:dist', ['default'], function() { |
| 235 browserSync({ | 331 browserSync({ |
| 236 port: 5001, | 332 port: 8000, |
|
Ryan Tseng
2016/12/06 03:38:11
is this configurable?
| |
| 333 ui: { | |
| 334 port: 8080, | |
| 335 }, | |
| 237 notify: false, | 336 notify: false, |
| 238 logPrefix: 'PSK', | 337 logPrefix: 'PSK', |
| 239 snippetOptions: { | 338 snippetOptions: { |
| 240 rule: { | 339 rule: { |
| 241 match: '<span id="browser-sync-binding"></span>', | 340 match: '<span id="browser-sync-binding"></span>', |
| 242 fn: function(snippet) { | 341 fn: function(snippet) { |
| 243 return snippet; | 342 return snippet; |
| 244 } | 343 } |
| 245 } | 344 } |
| 246 }, | 345 }, |
| 247 // Run as an https by uncommenting 'https: true' | 346 // Run as an https by uncommenting 'https: true' |
| 248 // Note: this uses an unsigned certificate which on first access | 347 // Note: this uses an unsigned certificate which on first access |
| 249 // will present a certificate warning in the browser. | 348 // will present a certificate warning in the browser. |
| 250 // https: true, | 349 // https: true, |
| 251 server: layout.dist(), | 350 server: layout.dist(), |
| 252 middleware: [historyApiFallback()] | 351 middleware: [historyApiFallback()] |
| 253 }); | 352 }); |
| 254 }); | 353 }); |
| 255 | 354 |
| 256 // Build production files, the default task | 355 // Build production files, the default task |
| 257 gulp.task('default', ['clean'], function(cb) { | 356 gulp.task('default', ['clean'], function(cb) { |
| 258 runSequence( | 357 runSequence( |
| 259 ['copy', 'styles', 'images', 'fonts', 'html'], | 358 ['ts', 'copy', 'styles', 'images', 'fonts', 'html'], |
| 260 'vulcanize', | 359 'vulcanize', |
| 261 cb); | 360 cb); |
| 262 }); | 361 }); |
| 263 }; | 362 }; |
| 264 | 363 |
| 265 require('es6-promise').polyfill(); | 364 require('es6-promise').polyfill(); |
| 266 | 365 |
| 267 // Load custom tasks from the `tasks` directory | 366 // Load custom tasks from the `tasks` directory |
| 268 try { | 367 try { |
| 269 require('require-dir')('tasks'); | 368 require('require-dir')('tasks'); |
| 270 } catch (err) {} | 369 } catch (err) {} |
| OLD | NEW |