gulpfile.js 10 KB

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