gulpfile.js 11 KB

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