blob: d5b70d8d7e0659f1aef9d019d239bcd242793f8b [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001/**
2 *
3 * Material Design Lite
4 * Copyright 2015 Google Inc. All rights reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
17 *
18 */
19
20// jscs:disable jsDoc
21
22'use strict';
23
24// Include Gulp & Tools We'll Use
25import fs from 'fs';
26import path from 'path';
27import mergeStream from 'merge-stream';
28import del from 'del';
29import vinylPaths from 'vinyl-paths';
30import runSequence from 'run-sequence';
31import browserSync from 'browser-sync';
32import through from 'through2';
33import swig from 'swig';
34import gulp from 'gulp';
35import closureCompiler from 'gulp-closure-compiler';
36import gulpLoadPlugins from 'gulp-load-plugins';
37import uniffe from './utils/uniffe.js';
38import pkg from './package.json';
39
40const $ = gulpLoadPlugins();
41const reload = browserSync.reload;
42const hostedLibsUrlPrefix = 'https://code.getmdl.io';
43const templateArchivePrefix = 'mdl-template-';
44const bucketProd = 'gs://www.getmdl.io';
45const bucketStaging = 'gs://mdl-staging';
46const bucketCode = 'gs://code.getmdl.io';
47const banner = ['/**',
48 ' * <%= pkg.name %> - <%= pkg.description %>',
49 ' * @version v<%= pkg.version %>',
50 ' * @license <%= pkg.license %>',
51 ' * @copyright 2015 Google, Inc.',
52 ' * @link https://github.com/google/material-design-lite',
53 ' */',
54 ''].join('\n');
55
56let codeFiles = '';
57
58const AUTOPREFIXER_BROWSERS = [
59 'ie >= 10',
60 'ie_mob >= 10',
61 'ff >= 30',
62 'chrome >= 34',
63 'safari >= 7',
64 'opera >= 23',
65 'ios >= 7',
66 'android >= 4.4',
67 'bb >= 10'
68];
69
70const SOURCES = [
71 // Component handler
72 'src/mdlComponentHandler.js',
73 // Polyfills/dependencies
74 'src/third_party/**/*.js',
75 // Base components
76 'src/button/button.js',
77 'src/checkbox/checkbox.js',
78 'src/icon-toggle/icon-toggle.js',
79 'src/menu/menu.js',
80 'src/progress/progress.js',
81 'src/radio/radio.js',
82 'src/slider/slider.js',
83 'src/snackbar/snackbar.js',
84 'src/spinner/spinner.js',
85 'src/switch/switch.js',
86 'src/tabs/tabs.js',
87 'src/textfield/textfield.js',
88 'src/tooltip/tooltip.js',
89 // Complex components (which reuse base components)
90 'src/layout/layout.js',
91 'src/data-table/data-table.js',
92 // And finally, the ripples
93 'src/ripple/ripple.js'
94];
95
96// ***** Development tasks ****** //
97
98// Lint JavaScript
99gulp.task('lint', () => {
100 return gulp.src([
101 'src/**/*.js',
102 'gulpfile.babel.js'
103 ])
104 .pipe(reload({stream: true, once: true}))
105 .pipe($.jshint())
106 .pipe($.jscs())
107 .pipe($.jshint.reporter('jshint-stylish'))
108 .pipe($.jscs.reporter())
109 .pipe($.if(!browserSync.active, $.jshint.reporter('fail')))
110 .pipe($.if(!browserSync.active, $.jscs.reporter('fail')));
111});
112
113// ***** Production build tasks ****** //
114
115// Optimize Images
116// TODO: Update image paths in final CSS to match root/images
117gulp.task('images', () => {
118 return gulp.src('src/**/*.{svg,png,jpg}')
119 .pipe($.flatten())
120 .pipe($.cache($.imagemin({
121 progressive: true,
122 interlaced: true
123 })))
124 .pipe(gulp.dest('dist/images'))
125 .pipe($.size({title: 'images'}));
126});
127
128// Compile and Automatically Prefix Stylesheets (dev)
129gulp.task('styles:dev', () => {
130 return gulp.src('src/**/*.scss')
131 .pipe($.sass({
132 precision: 10,
133 onError: console.error.bind(console, 'Sass error:')
134 }))
135 .pipe($.cssInlineImages({
136 webRoot: 'src'
137 }))
138 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
139 .pipe(gulp.dest('.tmp/styles'))
140 .pipe($.size({title: 'styles'}));
141});
142
143// Compile and Automatically Prefix Stylesheet Templates (production)
144gulp.task('styletemplates', () => {
145 // For best performance, don't add Sass partials to `gulp.src`
146 return gulp.src('src/template.scss')
147 // Generate Source Maps
148 .pipe($.sourcemaps.init())
149 .pipe($.sass({
150 precision: 10,
151 onError: console.error.bind(console, 'Sass error:')
152 }))
153 .pipe($.cssInlineImages({webRoot: 'src'}))
154 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
155 .pipe(gulp.dest('.tmp'))
156 // Concatenate Styles
157 .pipe($.concat('material.css.template'))
158 .pipe(gulp.dest('dist'))
159 // Minify Styles
160 .pipe($.if('*.css.template', $.csso()))
161 .pipe($.concat('material.min.css.template'))
162 .pipe($.header(banner, {pkg}))
163 .pipe($.sourcemaps.write('.'))
164 .pipe(gulp.dest('dist'))
165 .pipe($.size({title: 'styles'}));
166});
167
168// Compile and Automatically Prefix Stylesheets (production)
169gulp.task('styles', () => {
170 // For best performance, don't add Sass partials to `gulp.src`
171 return gulp.src('src/material-design-lite.scss')
172 // Generate Source Maps
173 .pipe($.sourcemaps.init())
174 .pipe($.sass({
175 precision: 10,
176 onError: console.error.bind(console, 'Sass error:')
177 }))
178 .pipe($.cssInlineImages({webRoot: 'src'}))
179 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
180 .pipe(gulp.dest('.tmp'))
181 // Concatenate Styles
182 .pipe($.concat('material.css'))
183 .pipe($.header(banner, {pkg}))
184 .pipe(gulp.dest('dist'))
185 // Minify Styles
186 .pipe($.if('*.css', $.csso()))
187 .pipe($.concat('material.min.css'))
188 .pipe($.header(banner, {pkg}))
189 .pipe($.sourcemaps.write('.'))
190 .pipe(gulp.dest('dist'))
191 .pipe($.size({title: 'styles'}));
192});
193
194// Only generate CSS styles for the MDL grid
195gulp.task('styles-grid', () => {
196 return gulp.src('src/material-design-lite-grid.scss')
197 .pipe($.sass({
198 precision: 10,
199 onError: console.error.bind(console, 'Sass error:')
200 }))
201 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
202 .pipe(gulp.dest('.tmp'))
203 // Concatenate Styles
204 .pipe($.concat('material-grid.css'))
205 .pipe($.header(banner, {pkg}))
206 .pipe(gulp.dest('dist'))
207 // Minify Styles
208 .pipe($.if('*.css', $.csso()))
209 .pipe($.concat('material-grid.min.css'))
210 .pipe($.header(banner, {pkg}))
211 .pipe(gulp.dest('dist'))
212 .pipe($.size({title: 'styles-grid'}));
213});
214
215// Build with Google's Closure Compiler, requires Java 1.7+ installed.
216gulp.task('closure', () => {
217 return gulp.src(SOURCES)
218 .pipe(closureCompiler({
219 compilerPath: 'node_modules/google-closure-compiler/compiler.jar',
220 fileName: 'material.closure.min.js',
221 compilerFlags: {
222 // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
223 compilation_level: 'ADVANCED_OPTIMIZATIONS',
224 language_in: 'ECMASCRIPT6_STRICT',
225 language_out: 'ECMASCRIPT5_STRICT',
226 warning_level: 'VERBOSE'
227 // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
228 }
229 }))
230 .pipe(gulp.dest('./dist'));
231});
232
233// Concatenate And Minify JavaScript
234gulp.task('scripts', ['lint'], () => {
235 return gulp.src(SOURCES)
236 .pipe($.if(/mdlComponentHandler\.js/, $.util.noop(), uniffe()))
237 .pipe($.sourcemaps.init())
238 // Concatenate Scripts
239 .pipe($.concat('material.js'))
240 .pipe($.iife({useStrict: true}))
241 .pipe(gulp.dest('dist'))
242 // Minify Scripts
243 .pipe($.uglify({
244 sourceRoot: '.',
245 sourceMapIncludeSources: true
246 }))
247 .pipe($.header(banner, {pkg}))
248 .pipe($.concat('material.min.js'))
249 // Write Source Maps
250 .pipe($.sourcemaps.write('.'))
251 .pipe(gulp.dest('dist'))
252 .pipe($.size({title: 'scripts'}));
253});
254
255// Clean Output Directory
256gulp.task('clean', () => del(['dist', '.publish']));
257
258// Copy package manger and LICENSE files to dist
259gulp.task('metadata', () => {
260 return gulp.src([
261 'package.json',
262 'bower.json',
263 'LICENSE'
264 ])
265 .pipe(gulp.dest('dist'));
266});
267
268// Build Production Files, the Default Task
269gulp.task('default', ['clean'], cb => {
270 runSequence(
271 ['styles', 'styles-grid'],
272 ['scripts'],
273 ['mocha'],
274 cb);
275});
276
277// Build production files and microsite
278gulp.task('all', ['clean'], cb => {
279 runSequence(
280 ['styletemplates'],
281 ['styles-grid', 'styles:gen'],
282 ['scripts'],
283 ['mocha'],
284 ['assets', 'pages',
285 'templates', 'images', 'metadata'],
286 ['zip'],
287 cb);
288});
289
290// ***** Testing tasks ***** //
291
292gulp.task('mocha', ['styles'], () => {
293 return gulp.src('test/index.html')
294 .pipe($.mochaPhantomjs({reporter: 'tap'}));
295});
296
297gulp.task('mocha:closure', ['closure'], () => {
298 return gulp.src('test/index.html')
299 .pipe($.replace('src="../dist/material.js"',
300 'src="../dist/material.closure.min.js"'))
301 .pipe($.rename('temp.html'))
302 .pipe(gulp.dest('test'))
303 .pipe($.mochaPhantomjs({reporter: 'tap'}))
304 .on('finish', () => del.sync('test/temp.html'))
305 .on('error', () => del.sync('test/temp.html'));
306});
307
308gulp.task('test', [
309 'lint',
310 'mocha',
311 'mocha:closure'
312]);
313
314gulp.task('test:visual', () => {
315 browserSync({
316 notify: false,
317 server: '.',
318 startPath: 'test/visual/index.html'
319 });
320
321 gulp.watch('test/visual/**', reload);
322});
323
324// ***** Landing page tasks ***** //
325
326/**
327 * Site metadata for use with templates.
328 * @type {Object}
329 */
330const site = {};
331
332/**
333 * Generates an HTML file based on a template and file metadata.
334 */
335function applyTemplate() {
336 return through.obj((file, enc, cb) => {
337 const data = {
338 site,
339 page: file.page,
340 content: file.contents.toString()
341 };
342
343 const templateFile = path.join(
344 __dirname, 'docs', '_templates', `${file.page.layout}.html`);
345 const tpl = swig.compileFile(templateFile, {cache: false});
346
347 file.contents = new Buffer(tpl(data));
348 cb(null, file);
349 });
350}
351
352/**
353 * Generates an index.html file for each README in MDL/src directory.
354 */
355gulp.task('components', ['demos'], () => {
356 return gulp.src('src/**/README.md', {base: 'src'})
357 // Add basic front matter.
358 .pipe($.header('---\nlayout: component\nbodyclass: component\ninclude_prefix: ../../\n---\n\n'))
359 .pipe($.frontMatter({
360 property: 'page',
361 remove: true
362 }))
363 .pipe($.marked())
364 .pipe((() => {
365 return through.obj((file, enc, cb) => {
366 file.page.component = file.relative.split('/')[0];
367 cb(null, file);
368 });
369 })())
370 .pipe(applyTemplate())
371 .pipe($.rename(path => path.basename = 'index'))
372 .pipe(gulp.dest('dist/components'));
373});
374
375/**
376 * Copies demo files from MDL/src directory.
377 */
378gulp.task('demoresources', () => {
379 return gulp.src([
380 'src/**/demos.css',
381 'src/**/demo.css',
382 'src/**/demo.js'
383 ], {base: 'src'})
384 .pipe($.if('*.scss', $.sass({
385 precision: 10,
386 onError: console.error.bind(console, 'Sass error:')
387 })))
388 .pipe($.cssInlineImages({webRoot: 'src'}))
389 .pipe($.if('*.css', $.autoprefixer(AUTOPREFIXER_BROWSERS)))
390 .pipe(gulp.dest('dist/components'));
391});
392
393/**
394 * Generates demo files for testing made of all the snippets and the demo file
395 * put together.
396 */
397gulp.task('demos', ['demoresources'], () => {
398 /**
399 * Retrieves the list of component folders.
400 */
401 function getComponentFolders() {
402 return fs.readdirSync('src')
403 .filter(file => fs.statSync(path.join('src', file)).isDirectory());
404 }
405
406 const tasks = getComponentFolders().map(component => {
407 return gulp.src([
408 path.join('src', component, 'snippets', '*.html'),
409 path.join('src', component, 'demo.html')
410 ])
411 .pipe($.concat('/demo.html'))
412 // Add basic front matter.
413 .pipe($.header('---\nlayout: demo\nbodyclass: demo\ninclude_prefix: ../../\n---\n\n'))
414 .pipe($.frontMatter({
415 property: 'page',
416 remove: true
417 }))
418 .pipe($.marked())
419 .pipe((() => {
420 return through.obj((file, enc, cb) => {
421 file.page.component = component;
422 cb(null, file);
423 });
424 })())
425 .pipe(applyTemplate())
426 .pipe(gulp.dest(path.join('dist', 'components', component)));
427 });
428
429 return mergeStream(tasks);
430});
431
432/**
433 * Generates an HTML file for each md file in _pages directory.
434 */
435gulp.task('pages', ['components'], () => {
436 return gulp.src('docs/_pages/*.md')
437 .pipe($.frontMatter({
438 property: 'page',
439 remove: true
440 }))
441 .pipe($.marked())
442 .pipe(applyTemplate())
443 .pipe($.replace('$$version$$', pkg.version))
444 .pipe($.replace('$$hosted_libs_prefix$$', hostedLibsUrlPrefix))
445 .pipe($.replace('$$template_archive_prefix$$', templateArchivePrefix))
446 /* Replacing code blocks class name to match Prism's. */
447 .pipe($.replace('class="lang-', 'class="language-'))
448 /* Translate html code blocks to "markup" because that's what Prism uses. */
449 .pipe($.replace('class="language-html', 'class="language-markup'))
450 .pipe($.rename(path => {
451 if (path.basename !== 'index') {
452 path.dirname = path.basename;
453 path.basename = 'index';
454 }
455 }))
456 .pipe(gulp.dest('dist'));
457});
458
459/**
460 * Copies assets from MDL and _assets directory.
461 */
462gulp.task('assets', () => {
463 return gulp.src([
464 'docs/_assets/**/*',
465 'node_modules/clippy/build/clippy.swf',
466 'node_modules/swfobject-npm/swfobject/src/swfobject.js',
467 'node_modules/prismjs/prism.js',
468 'node_modules/prismjs/components/prism-markup.min.js',
469 'node_modules/prismjs/components/prism-javascript.min.js',
470 'node_modules/prismjs/components/prism-css.min.js',
471 'node_modules/prismjs/components/prism-bash.min.js',
472 'node_modules/prismjs/dist/prism-default/prism-default.css'
473 ])
474 .pipe($.if(/\.js/i, $.replace('$$version$$', pkg.version)))
475 .pipe($.if(/\.js/i, $.replace('$$hosted_libs_prefix$$', hostedLibsUrlPrefix)))
476 .pipe($.if(/\.(svg|jpg|png)$/i, $.imagemin({
477 progressive: true,
478 interlaced: true
479 })))
480 .pipe($.if(/\.css/i, $.autoprefixer(AUTOPREFIXER_BROWSERS)))
481 .pipe($.if(/\.css/i, $.csso()))
482 .pipe($.if(/\.js/i, $.uglify({
483 preserveComments: 'some',
484 sourceRoot: '.',
485 sourceMapIncludeSources: true
486 })))
487 .pipe(gulp.dest('dist/assets'));
488});
489
490/**
491 * Defines the list of resources to watch for changes.
492 */
493function watch() {
494 gulp.watch(['src/**/*.js', '!src/**/README.md'],
495 ['scripts', 'demos', 'components', reload]);
496 gulp.watch(['src/**/*.{scss,css}'],
497 ['styles', 'styles-grid', 'styletemplates', reload]);
498 gulp.watch(['src/**/*.html'], ['pages', reload]);
499 gulp.watch(['src/**/*.{svg,png,jpg}'], ['images', reload]);
500 gulp.watch(['src/**/README.md'], ['pages', reload]);
501 gulp.watch(['templates/**/*'], ['templates', reload]);
502 gulp.watch(['docs/**/*'], ['pages', 'assets', reload]);
503 gulp.watch(['package.json', 'bower.json', 'LICENSE'], ['metadata']);
504}
505
506/**
507 * Serves the landing page from "out" directory.
508 */
509gulp.task('serve:browsersync', () => {
510 browserSync({
511 notify: false,
512 server: {
513 baseDir: ['dist']
514 }
515 });
516
517 watch();
518});
519
520gulp.task('serve', () => {
521 $.connect.server({
522 root: 'dist',
523 port: 5000,
524 livereload: true
525 });
526
527 watch();
528
529 gulp.src('dist/index.html')
530 .pipe($.open({uri: 'http://localhost:5000'}));
531});
532
533// Generate release archive containing just JS, CSS, Source Map deps
534gulp.task('zip:mdl', () => {
535 return gulp.src([
536 'dist/material?(.min)@(.js|.css)?(.map)',
537 'LICENSE',
538 'bower.json',
539 'package.json'
540 ])
541 .pipe($.zip('mdl.zip'))
542 .pipe(gulp.dest('dist'));
543});
544
545/**
546 * Returns the list of children directories inside the given directory.
547 * @param {string} dir the parent directory
548 * @return {Array<string>} list of child directories
549 */
550function getSubDirectories(dir) {
551 return fs.readdirSync(dir)
552 .filter(file => fs.statSync(path.join(dir, file)).isDirectory());
553}
554
555// Generate release archives containing the templates and assets for templates.
556gulp.task('zip:templates', () => {
557 const templates = getSubDirectories('dist/templates');
558
559 // Generate a zip file for each template.
560 const generateZips = templates.map(template => {
561 return gulp.src([
562 `dist/templates/${template}/**/*.*`,
563 'LICENSE'
564 ])
565 .pipe($.rename(path => {
566 path.dirname = path.dirname.replace(`dist/templates/${template}`, '');
567 }))
568 .pipe($.zip(`${templateArchivePrefix}${template}.zip`))
569 .pipe(gulp.dest('dist'));
570 });
571
572 return mergeStream(generateZips);
573});
574
575gulp.task('zip', [
576 'zip:templates',
577 'zip:mdl'
578]);
579
580gulp.task('genCodeFiles', () => {
581 return gulp.src([
582 'dist/material.*@(js|css)?(.map)',
583 'dist/mdl.zip',
584 `dist/${templateArchivePrefix}*.zip`
585 ], {read: false})
586 .pipe($.tap(file => {
587 codeFiles += ` dist/${path.basename(file.path)}`;
588 }));
589});
590
591// Push the latest version of code resources (CSS+JS) to Google Cloud Storage.
592// Public-read objects in GCS are served by a Google provided and supported
593// global, high performance caching/content delivery network (CDN) service.
594// This task requires gsutil to be installed and configured.
595// For info on gsutil: https://cloud.google.com/storage/docs/gsutil.
596gulp.task('pushCodeFiles', () => {
597 const dest = bucketCode;
598 console.log(`Publishing ${pkg.version} to CDN (${dest})`);
599
600 // Build cache control and gsutil cmd to copy
601 // each object into a GCS bucket. The dest is a version specific path.
602 // The gsutil -m option requests parallel copies.
603 // The gsutil -h option is used to set metadata headers
604 // (cache control, in this case).
605 // Code files should NEVER be touched after uploading, therefore
606 // 30 days caching is a safe value.
607 const cacheControl = '-h "Cache-Control:public,max-age=2592000"';
608 const gsutilCpCmd = 'gsutil -m cp -z js,css,map ';
609 const gsutilCacheCmd = `gsutil -m setmeta -R ${cacheControl}`;
610
611 // Upload the goodies to a separate GCS bucket with versioning.
612 // Using a sep bucket avoids the risk of accidentally blowing away
613 // old versions in the microsite bucket.
614 return gulp.src('')
615 .pipe($.shell([
616 `${gsutilCpCmd}${codeFiles} ${dest}/${pkg.version}`,
617 `${gsutilCacheCmd} ${dest}/${pkg.version}`
618 ]));
619});
620
621gulp.task('publish:code', cb => {
622 runSequence(
623 ['zip:mdl', 'zip:templates'],
624 'genCodeFiles',
625 'pushCodeFiles',
626 cb);
627});
628
629/**
630 * Function to publish staging or prod version from local tree,
631 * or to promote staging to prod, per passed arg.
632 * @param {string} pubScope the scope to publish to.
633 */
634function mdlPublish(pubScope) {
635 let cacheTtl = null;
636 let src = null;
637 let dest = null;
638
639 if (pubScope === 'staging') {
640 // Set staging specific vars here.
641 cacheTtl = 0;
642 src = 'dist/*';
643 dest = bucketStaging;
644 } else if (pubScope === 'prod') {
645 // Set prod specific vars here.
646 cacheTtl = 60;
647 src = 'dist/*';
648 dest = bucketProd;
649 } else if (pubScope === 'promote') {
650 // Set promote (essentially prod) specific vars here.
651 cacheTtl = 60;
652 src = `${bucketStaging}/*`;
653 dest = bucketProd;
654 }
655
656 let infoMsg = `Publishing ${pubScope}/${pkg.version} to GCS (${dest})`;
657 if (src) {
658 infoMsg += ` from ${src}`;
659 }
660 console.log(infoMsg);
661
662 // Build gsutil commands:
663 // The gsutil -h option is used to set metadata headers.
664 // The gsutil -m option requests parallel copies.
665 // The gsutil -R option is used for recursive file copy.
666 const cacheControl = `-h "Cache-Control:public,max-age=${cacheTtl}"`;
667 const gsutilCacheCmd = `gsutil -m setmeta ${cacheControl} ${dest}/**`;
668 const gsutilCpCmd = `gsutil -m cp -r -z html,css,js,svg ${src} ${dest}`;
669
670 gulp.src('').pipe($.shell([gsutilCpCmd, gsutilCacheCmd]));
671}
672
673// Push the local build of the MDL microsite and release artifacts to the
674// production Google Cloud Storage bucket for general serving to the web.
675// Public-read objects in GCS are served by a Google provided and supported
676// global, high performance caching/content delivery network (CDN) service.
677// This task requires gsutil to be installed and configured.
678// For info on gsutil: https://cloud.google.com/storage/docs/gsutil.
679//
680gulp.task('publish:prod', () => {
681 mdlPublish('prod');
682});
683
684// Promote the staging version of the MDL microsite and release artifacts
685// to the production Google Cloud Storage bucket for general serving.
686// Public-read objects in GCS are served by a Google provided and supported
687// global, high performance caching/content delivery network (CDN) service.
688// This task requires gsutil to be installed and configured.
689// For info on gsutil: https://cloud.google.com/storage/docs/gsutil.
690//
691gulp.task('publish:promote', () => {
692 mdlPublish('promote');
693});
694
695// Push the staged version of the MDL microsite and release artifacts
696// to a production Google Cloud Storage bucket for staging and pre-production testing.
697//
698// This task requires gsutil to be installed and configured.
699// For info on gsutil: https://cloud.google.com/storage/docs/gsutil.
700//
701gulp.task('publish:staging', () => {
702 mdlPublish('staging');
703});
704
705gulp.task('_release', () => {
706 return gulp.src([
707 'dist/material?(.min)@(.js|.css)?(.map)',
708 'LICENSE',
709 'README.md',
710 'bower.json',
711 'package.json',
712 '.jscsrc',
713 '.jshintrc',
714 './sr?/**/*',
715 'gulpfile.babel.js',
716 './util?/**/*'
717 ])
718 .pipe(gulp.dest('_release'));
719});
720
721gulp.task('publish:release', ['_release'], () => {
722 return gulp.src('_release')
723 .pipe($.subtree({
724 remote: 'origin',
725 branch: 'release'
726 }))
727 .pipe(vinylPaths(del));
728});
729
730gulp.task('templates:styles', () => {
731 return gulp.src('templates/**/*.css')
732 .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
733 // FIXME: This crashes. It's a bug in gulp-csso,
734 // not csso itself.
735 //.pipe($.csso())
736 .pipe(gulp.dest('dist/templates'));
737});
738
739gulp.task('templates:static', () => {
740 return gulp.src('templates/**/*.html')
741 .pipe($.replace('$$version$$', pkg.version))
742 .pipe($.replace('$$hosted_libs_prefix$$', hostedLibsUrlPrefix))
743 .pipe(gulp.dest('dist/templates'));
744});
745
746// This task can be used if you want to test the templates against locally
747// built version of the MDL libraries.
748gulp.task('templates:localtestingoverride', () => {
749 return gulp.src('templates/**/*.html')
750 .pipe($.replace('$$version$$', '.'))
751 .pipe($.replace('$$hosted_libs_prefix$$', ''))
752 .pipe(gulp.dest('dist/templates'));
753});
754
755gulp.task('templates:images', () => {
756 return gulp.src('templates/*/images/**/*')
757 .pipe($.imagemin({
758 progressive: true,
759 interlaced: true
760 }))
761 .pipe(gulp.dest('dist/templates'));
762});
763
764gulp.task('templates:fonts', () => {
765 return gulp.src('templates/*/fonts/**/*')
766 .pipe(gulp.dest('dist/templates/'));
767});
768
769gulp.task('templates', [
770 'templates:static',
771 'templates:images',
772 'templates:fonts',
773 'templates:styles'
774]);
775
776gulp.task('styles:gen', ['styles'], () => {
777 const MaterialCustomizer = require('./docs/_assets/customizer.js');
778 const templatePath = path.join(__dirname, 'dist', 'material.min.css.template');
779 // TODO: This task needs refactoring once we turn MaterialCustomizer
780 // into a proper Node module.
781 const mc = new MaterialCustomizer();
782 mc.template = fs.readFileSync(templatePath).toString();
783
784 let stream = gulp.src('');
785
786 mc.paletteIndices.forEach(primary => {
787 mc.paletteIndices.forEach(accent => {
788 if (primary === accent) {
789 return;
790 }
791
792 if (mc.forbiddenAccents.indexOf(accent) !== -1) {
793 return;
794 }
795
796 const primaryName = primary.toLowerCase().replace(' ', '_');
797 const accentName = accent.toLowerCase().replace(' ', '_');
798
799 stream = stream.pipe($.file(
800 `material.${primaryName}-${accentName}.min.css`,
801 mc.processTemplate(primary, accent)
802 ));
803 });
804 });
805
806 stream.pipe(gulp.dest('dist'));
807});