gulpfile.js 8.6 KB

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