gulpfile.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
  3. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
  4. The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
  5. The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
  6. Code distributed by Google as part of the polymer project is also
  7. subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
  8. */
  9. 'use strict';
  10. // Include Gulp & tools we'll use
  11. var gulp = require('gulp');
  12. var $ = require('gulp-load-plugins')();
  13. var del = require('del');
  14. var runSequence = require('run-sequence');
  15. var browserSync = require('browser-sync');
  16. var reload = browserSync.reload;
  17. var merge = require('merge-stream');
  18. var path = require('path');
  19. var fs = require('fs');
  20. var glob = require('glob-all');
  21. var historyApiFallback = require('connect-history-api-fallback');
  22. var packageJson = require('./package.json');
  23. var crypto = require('crypto');
  24. var ensureFiles = require('./tasks/ensure-files.js');
  25. // var ghPages = require('gulp-gh-pages');
  26. var AUTOPREFIXER_BROWSERS = [
  27. 'ie >= 10',
  28. 'ie_mob >= 10',
  29. 'ff >= 30',
  30. 'chrome >= 34',
  31. 'safari >= 7',
  32. 'opera >= 23',
  33. 'ios >= 7',
  34. 'android >= 4.4',
  35. 'bb >= 10'
  36. ];
  37. var DIST = 'dist';
  38. var dist = function(subpath) {
  39. return !subpath ? DIST : path.join(DIST, subpath);
  40. };
  41. var styleTask = function(stylesPath, srcs) {
  42. return gulp.src(srcs.map(function(src) {
  43. return path.join('app', stylesPath, src);
  44. }))
  45. .pipe($.changed(stylesPath, {extension: '.css'}))
  46. .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
  47. .pipe(gulp.dest('.tmp/' + stylesPath))
  48. .pipe($.minifyCss())
  49. .pipe(gulp.dest(dist(stylesPath)))
  50. .pipe($.size({title: stylesPath}));
  51. };
  52. var imageOptimizeTask = function(src, dest) {
  53. return gulp.src(src)
  54. .pipe($.imagemin({
  55. progressive: true,
  56. interlaced: true
  57. }))
  58. .pipe(gulp.dest(dest))
  59. .pipe($.size({title: 'images'}));
  60. };
  61. var optimizeHtmlTask = function(src, dest) {
  62. var assets = $.useref.assets({
  63. searchPath: ['.tmp', 'app']
  64. });
  65. return gulp.src(src)
  66. .pipe(assets)
  67. // Concatenate and minify JavaScript
  68. .pipe($.if('*.js', $.uglify({
  69. preserveComments: 'some'
  70. })))
  71. // Concatenate and minify styles
  72. // In case you are still using useref build blocks
  73. .pipe($.if('*.css', $.minifyCss()))
  74. .pipe(assets.restore())
  75. .pipe($.useref())
  76. // Minify any HTML
  77. .pipe($.if('*.html', $.minifyHtml({
  78. quotes: true,
  79. empty: true,
  80. spare: true
  81. })))
  82. // Output files
  83. .pipe(gulp.dest(dest))
  84. .pipe($.size({
  85. title: 'html'
  86. }));
  87. };
  88. // Compile and automatically prefix stylesheets
  89. gulp.task('styles', function() {
  90. return styleTask('styles', ['**/*.css']);
  91. });
  92. gulp.task('elements', function() {
  93. return styleTask('elements', ['**/*.css']);
  94. });
  95. // Ensure that we are not missing required files for the project
  96. // "dot" files are specifically tricky due to them being hidden on
  97. // some systems.
  98. gulp.task('ensureFiles', function(cb) {
  99. var requiredFiles = ['.jscsrc', '.jshintrc', '.bowerrc'];
  100. ensureFiles(requiredFiles.map(function(p) {
  101. return path.join(__dirname, p);
  102. }), cb);
  103. });
  104. // Lint JavaScript
  105. gulp.task('lint', ['ensureFiles'], function() {
  106. return gulp.src([
  107. 'app/scripts/**/*.js',
  108. 'app/elements/**/*.js',
  109. 'app/elements/**/*.html',
  110. 'gulpfile.js'
  111. ])
  112. .pipe(reload({
  113. stream: true,
  114. once: true
  115. }))
  116. // JSCS has not yet a extract option
  117. .pipe($.if('*.html', $.htmlExtract()))
  118. .pipe($.jshint())
  119. .pipe($.jscs())
  120. .pipe($.jscsStylish.combineWithHintResults())
  121. .pipe($.jshint.reporter('jshint-stylish'))
  122. .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
  123. });
  124. // Optimize images
  125. gulp.task('images', function() {
  126. return imageOptimizeTask('app/images/**/*', dist('images'));
  127. });
  128. // Copy all files at the root level (app)
  129. gulp.task('copy', function() {
  130. var app = gulp.src([
  131. 'app/*',
  132. '!app/test',
  133. '!app/elements',
  134. '!app/bower_components',
  135. '!app/cache-config.json'
  136. ], {
  137. dot: true
  138. }).pipe(gulp.dest(dist()));
  139. // Copy over only the bower_components we need
  140. // These are things which cannot be vulcanized
  141. var bower = gulp.src([
  142. 'app/bower_components/{webcomponentsjs,platinum-sw,sw-toolbox,promise-polyfill}/**/*'
  143. ]).pipe(gulp.dest(dist('bower_components')));
  144. return merge(app, bower)
  145. .pipe($.size({
  146. title: 'copy'
  147. }));
  148. });
  149. // Copy web fonts to dist
  150. gulp.task('fonts', function() {
  151. return gulp.src(['app/fonts/**'])
  152. .pipe(gulp.dest(dist('fonts')))
  153. .pipe($.size({
  154. title: 'fonts'
  155. }));
  156. });
  157. // Scan your HTML for assets & optimize them
  158. gulp.task('html', function() {
  159. return optimizeHtmlTask(
  160. ['app/**/*.html', '!app/{elements,test,bower_components}/**/*.html'],
  161. dist());
  162. });
  163. // Vulcanize granular configuration
  164. gulp.task('vulcanize', function() {
  165. return gulp.src('app/elements/elements.html')
  166. .pipe($.vulcanize({
  167. stripComments: true,
  168. inlineCss: true,
  169. inlineScripts: true
  170. }))
  171. .pipe(gulp.dest(dist('elements')))
  172. .pipe($.size({title: 'vulcanize'}));
  173. });
  174. // Generate config data for the <sw-precache-cache> element.
  175. // This include a list of files that should be precached, as well as a (hopefully unique) cache
  176. // id that ensure that multiple PSK projects don't share the same Cache Storage.
  177. // This task does not run by default, but if you are interested in using service worker caching
  178. // in your project, please enable it within the 'default' task.
  179. // See https://github.com/PolymerElements/polymer-starter-kit#enable-service-worker-support
  180. // for more context.
  181. gulp.task('cache-config', function(callback) {
  182. var dir = dist();
  183. var config = {
  184. cacheId: packageJson.name || path.basename(__dirname),
  185. disabled: false
  186. };
  187. glob([
  188. 'index.html',
  189. './',
  190. 'bower_components/webcomponentsjs/webcomponents-lite.min.js',
  191. '{elements,scripts,styles}/**/*.*'],
  192. {cwd: dir}, function(error, files) {
  193. if (error) {
  194. callback(error);
  195. } else {
  196. config.precache = files;
  197. var md5 = crypto.createHash('md5');
  198. md5.update(JSON.stringify(config.precache));
  199. config.precacheFingerprint = md5.digest('hex');
  200. var configPath = path.join(dir, 'cache-config.json');
  201. fs.writeFile(configPath, JSON.stringify(config), callback);
  202. }
  203. });
  204. });
  205. // Clean output directory
  206. gulp.task('clean', function() {
  207. return del(['.tmp', dist()]);
  208. });
  209. // Watch files for changes & reload
  210. gulp.task('serve', ['lint', 'styles', 'elements', 'images'], function() {
  211. browserSync({
  212. port: 5000,
  213. notify: false,
  214. logPrefix: 'PSK',
  215. snippetOptions: {
  216. rule: {
  217. match: '<span id="browser-sync-binding"></span>',
  218. fn: function(snippet) {
  219. return snippet;
  220. }
  221. }
  222. },
  223. // Run as an https by uncommenting 'https: true'
  224. // Note: this uses an unsigned certificate which on first access
  225. // will present a certificate warning in the browser.
  226. // https: true,
  227. server: {
  228. baseDir: ['.tmp', 'app'],
  229. middleware: [historyApiFallback()]
  230. }
  231. });
  232. gulp.watch(['app/**/*.html'], reload);
  233. gulp.watch(['app/styles/**/*.css'], ['styles', reload]);
  234. gulp.watch(['app/elements/**/*.css'], ['elements', reload]);
  235. gulp.watch(['app/{scripts,elements}/**/{*.js,*.html}'], ['lint']);
  236. gulp.watch(['app/images/**/*'], reload);
  237. });
  238. // Build and serve the output from the dist build
  239. gulp.task('serve:dist', ['default'], function() {
  240. browserSync({
  241. port: 5001,
  242. notify: false,
  243. logPrefix: 'PSK',
  244. snippetOptions: {
  245. rule: {
  246. match: '<span id="browser-sync-binding"></span>',
  247. fn: function(snippet) {
  248. return snippet;
  249. }
  250. }
  251. },
  252. // Run as an https by uncommenting 'https: true'
  253. // Note: this uses an unsigned certificate which on first access
  254. // will present a certificate warning in the browser.
  255. // https: true,
  256. server: dist(),
  257. middleware: [historyApiFallback()]
  258. });
  259. });
  260. // Build production files, the default task
  261. gulp.task('default', ['clean'], function(cb) {
  262. // Uncomment 'cache-config' if you are going to use service workers.
  263. runSequence(
  264. ['copy', 'styles'],
  265. 'elements',
  266. ['lint', 'images', 'fonts', 'html'],
  267. 'vulcanize', // 'cache-config',
  268. cb);
  269. });
  270. // Build then deploy to GitHub pages gh-pages branch
  271. gulp.task('build-deploy-gh-pages', function(cb) {
  272. runSequence(
  273. 'default',
  274. 'deploy-gh-pages',
  275. cb);
  276. });
  277. // Deploy to GitHub pages gh-pages branch
  278. gulp.task('deploy-gh-pages', function() {
  279. return gulp.src(dist('**/*'))
  280. // Check if running task from Travis CI, if so run using GH_TOKEN
  281. // otherwise run using ghPages defaults.
  282. .pipe($.if(process.env.TRAVIS === 'true', $.ghPages({
  283. remoteUrl: 'https://$GH_TOKEN@github.com/polymerelements/polymer-starter-kit.git',
  284. silent: true,
  285. branch: 'gh-pages'
  286. }), $.ghPages()));
  287. });
  288. // Load tasks for web-component-tester
  289. // Adds tasks for `gulp test:local` and `gulp test:remote`
  290. require('web-component-tester').gulp.init(gulp);
  291. // Load custom tasks from the `tasks` directory
  292. try {
  293. require('require-dir')('tasks');
  294. } catch (err) {}