diff --git a/.travis.yml b/.travis.yml index b17bbb8332183cebef1f5c2c5d256e97a1c69ae7..af749ff25dd40bfe830e0307a911c67ffc280df8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ before_install: - if [ "$TRAVIS_REPO_SLUG" = twbs-savage/bootstrap ]; then export TWBS_DO_VALIDATOR=0; fi install: - bundle install --deployment --jobs=3 - - cp grunt/npm-shrinkwrap.json ./ + - cp gulp/npm-shrinkwrap.json ./ - npm install cache: directories: diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 0deece20ce61f00c1dc12a27de20380b3d26a7fa..0000000000000000000000000000000000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,402 +0,0 @@ -/*! - * Bootstrap's Gruntfile - * http://getbootstrap.com - * Copyright 2013-2016 The Bootstrap Authors - * Copyright 2013-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -module.exports = function (grunt) { - 'use strict'; - - // Force use of Unix newlines - grunt.util.linefeed = '\n'; - - RegExp.quote = function (string) { - return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&'); - }; - - var fs = require('fs'); - var path = require('path'); - var isTravis = require('is-travis'); - - var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' }); - - Object.keys(configBridge.paths).forEach(function (key) { - configBridge.paths[key].forEach(function (val, i, arr) { - arr[i] = path.join('./docs', val); - }); - }); - - // Project configuration. - grunt.initConfig({ - - // Metadata. - pkg: grunt.file.readJSON('package.json'), - banner: '/*!\n' + - ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + - ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + - ' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' + - ' */\n', - jqueryCheck: 'if (typeof jQuery === \'undefined\') {\n' + - ' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\')\n' + - '}\n', - jqueryVersionCheck: '+function ($) {\n' + - ' var version = $.fn.jquery.split(\' \')[0].split(\'.\')\n' + - ' if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] >= 4)) {\n' + - ' throw new Error(\'Bootstrap\\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0\')\n' + - ' }\n' + - '}(jQuery);\n\n', - - // Task configuration. - clean: { - dist: 'dist', - docs: 'docs/dist' - }, - - // JS build configuration - babel: { - dev: { - options: { - sourceMap: true, - modules: 'ignore' - }, - files: { - 'js/dist/util.js' : 'js/src/util.js', - 'js/dist/alert.js' : 'js/src/alert.js', - 'js/dist/button.js' : 'js/src/button.js', - 'js/dist/carousel.js' : 'js/src/carousel.js', - 'js/dist/collapse.js' : 'js/src/collapse.js', - 'js/dist/dropdown.js' : 'js/src/dropdown.js', - 'js/dist/modal.js' : 'js/src/modal.js', - 'js/dist/scrollspy.js' : 'js/src/scrollspy.js', - 'js/dist/tab.js' : 'js/src/tab.js', - 'js/dist/tooltip.js' : 'js/src/tooltip.js', - 'js/dist/popover.js' : 'js/src/popover.js' - } - }, - dist: { - options: { - modules: 'ignore' - }, - files: { - '<%= concat.bootstrap.dest %>' : '<%= concat.bootstrap.dest %>' - } - } - }, - - stamp: { - options: { - banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>\n+function ($) {\n', - footer: '\n}(jQuery);' - }, - bootstrap: { - files: { - src: '<%= concat.bootstrap.dest %>' - } - } - }, - - concat: { - options: { - // Custom function to remove all export and import statements - process: function (src) { - return src.replace(/^(export|import).*/gm, ''); - }, - stripBanners: false - }, - bootstrap: { - src: [ - 'js/src/util.js', - 'js/src/alert.js', - 'js/src/button.js', - 'js/src/carousel.js', - 'js/src/collapse.js', - 'js/src/dropdown.js', - 'js/src/modal.js', - 'js/src/scrollspy.js', - 'js/src/tab.js', - 'js/src/tooltip.js', - 'js/src/popover.js' - ], - dest: 'dist/js/<%= pkg.name %>.js' - } - }, - - uglify: { - options: { - compress: { - warnings: false - }, - mangle: true, - preserveComments: /^!|@preserve|@license|@cc_on/i - }, - core: { - src: '<%= concat.bootstrap.dest %>', - dest: 'dist/js/<%= pkg.name %>.min.js' - }, - docsJs: { - src: configBridge.paths.docsJs, - dest: 'docs/assets/js/docs.min.js' - } - }, - - qunit: { - options: { - inject: 'js/tests/unit/phantom.js' - }, - files: 'js/tests/index.html' - }, - - // CSS build configuration - scsslint: { - options: { - bundleExec: true, - config: 'scss/.scss-lint.yml', - reporterOutput: null - }, - core: { - src: ['scss/*.scss', '!scss/_normalize.scss'] - }, - docs: { - src: ['docs/assets/scss/*.scss', '!docs/assets/scss/docs.scss'] - } - }, - - cssmin: { - options: { - // TODO: disable `zeroUnits` optimization once clean-css 3.2 is released - // and then simplify the fix for https://github.com/twbs/bootstrap/issues/14837 accordingly - compatibility: 'ie9', - keepSpecialComments: '*', - sourceMap: true, - advanced: false - }, - core: { - files: [ - { - expand: true, - cwd: 'dist/css', - src: ['*.css', '!*.min.css'], - dest: 'dist/css', - ext: '.min.css' - } - ] - }, - docs: { - src: 'docs/assets/css/docs.min.css', - dest: 'docs/assets/css/docs.min.css' - } - }, - - copy: { - docs: { - expand: true, - cwd: 'dist/', - src: [ - '**/*' - ], - dest: 'docs/dist/' - } - }, - - connect: { - server: { - options: { - port: 3000, - base: '.' - } - } - }, - - jekyll: { - options: { - bundleExec: true, - config: '_config.yml', - incremental: false - }, - docs: {}, - github: { - options: { - raw: 'github: true' - } - } - }, - - htmllint: { - options: { - ignore: [ - 'Attribute “autocomplete†is only allowed when the input type is “colorâ€, “dateâ€, “datetimeâ€, “datetime-localâ€, “emailâ€, “hiddenâ€, “monthâ€, “numberâ€, “passwordâ€, “rangeâ€, “searchâ€, “telâ€, “textâ€, “timeâ€, “urlâ€, or “weekâ€.', - 'Attribute “autocomplete†not allowed on element “button†at this point.', - 'Consider using the “h1†element as a top-level heading only (all “h1†elements are treated as top-level headings by many screen readers and other tools).', - 'Element “div†not allowed as child of element “progress†in this context. (Suppressing further errors from this subtree.)', - 'Element “img†is missing required attribute “srcâ€.', - 'The “color†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', - 'The “date†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', - 'The “datetime†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', - 'The “datetime-local†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', - 'The “month†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', - 'The “time†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', - 'The “week†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.' - ] - }, - src: ['_gh_pages/**/*.html', 'js/tests/visual/*.html'] - }, - - watch: { - src: { - files: '<%= concat.bootstrap.src %>', - tasks: ['babel:dev'] - }, - sass: { - files: 'scss/**/*.scss', - tasks: ['dist-css', 'docs'] - }, - docs: { - files: 'docs/assets/scss/**/*.scss', - tasks: ['dist-css', 'docs'] - } - }, - - 'saucelabs-qunit': { - all: { - options: { - build: process.env.TRAVIS_JOB_ID, - concurrency: 10, - maxRetries: 3, - maxPollRetries: 4, - urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'], - browsers: grunt.file.readYAML('grunt/sauce_browsers.yml') - } - } - }, - - exec: { - postcss: { - command: 'npm run postcss' - }, - 'postcss-docs': { - command: 'npm run postcss-docs' - }, - htmlhint: { - command: 'npm run htmlhint' - }, - 'upload-preview': { - command: './grunt/upload-preview.sh' - } - }, - - buildcontrol: { - options: { - dir: '_gh_pages', - commit: true, - push: true, - message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%' - }, - pages: { - options: { - remote: 'git@github.com:twbs/derpstrap.git', - branch: 'gh-pages' - } - } - }, - - compress: { - main: { - options: { - archive: 'bootstrap-<%= pkg.version %>-dist.zip', - mode: 'zip', - level: 9, - pretty: true - }, - files: [ - { - expand: true, - cwd: 'dist/', - src: ['**'], - dest: 'bootstrap-<%= pkg.version %>-dist' - } - ] - } - } - - }); - - - // These plugins provide necessary tasks. - require('load-grunt-tasks')(grunt, { scope: 'devDependencies', - // Exclude Sass compilers. We choose the one to load later on. - pattern: ['grunt-*', '!grunt-sass', '!grunt-contrib-sass'] }); - require('time-grunt')(grunt); - - // Docs HTML validation task - grunt.registerTask('validate-html', ['jekyll:docs', 'htmllint', 'exec:htmlhint']); - - var runSubset = function (subset) { - return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset; - }; - var isUndefOrNonZero = function (val) { - return val === undefined || val !== '0'; - }; - - // Test task. - var testSubtasks = []; - // Skip core tests if running a different subset of the test suite - if (runSubset('core') && - // Skip core tests if this is a Savage build - process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') { - testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'test-scss', 'qunit', 'docs']); - } - // Skip HTML validation if running a different subset of the test suite - if (runSubset('validate-html') && - isTravis && - // Skip HTML5 validator when [skip validator] is in the commit message - isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) { - testSubtasks.push('validate-html'); - } - // Only run Sauce Labs tests if there's a Sauce access key - if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' && - // Skip Sauce if running a different subset of the test suite - runSubset('sauce-js-unit')) { - testSubtasks = testSubtasks.concat(['dist', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs', 'exec:upload-preview']); - // Skip Sauce on Travis when [skip sauce] is in the commit message - if (isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) { - testSubtasks.push('connect'); - testSubtasks.push('saucelabs-qunit'); - } - } - grunt.registerTask('test', testSubtasks); - - // JS distribution task. - grunt.registerTask('dist-js', ['babel:dev', 'concat', 'babel:dist', 'stamp', 'uglify:core']); - - grunt.registerTask('test-scss', ['scsslint:core']); - - // CSS distribution task. - // Supported Compilers: sass (Ruby) and libsass. - (function (sassCompilerName) { - require('./grunt/bs-sass-compile/' + sassCompilerName + '.js')(grunt); - })(process.env.TWBS_SASS || 'libsass'); - // grunt.registerTask('sass-compile', ['sass:core', 'sass:extras', 'sass:docs']); - grunt.registerTask('sass-compile', ['sass:core', 'sass:docs']); - - grunt.registerTask('dist-css', ['sass-compile', 'exec:postcss', 'cssmin:core', 'cssmin:docs']); - - // Full distribution task. - grunt.registerTask('dist', ['clean:dist', 'dist-css', 'dist-js']); - - // Default task. - grunt.registerTask('default', ['clean:dist', 'test']); - - // Docs task. - grunt.registerTask('docs-css', ['cssmin:docs', 'exec:postcss-docs']); - grunt.registerTask('lint-docs-css', ['scsslint:docs']); - grunt.registerTask('docs-js', ['uglify:docsJs']); - grunt.registerTask('docs', ['lint-docs-css', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs']); - grunt.registerTask('docs-github', ['jekyll:github']); - - grunt.registerTask('prep-release', ['dist', 'docs', 'docs-github', 'compress']); - - // Publish to GitHub - grunt.registerTask('publish', ['buildcontrol:pages']); -}; diff --git a/Gulpfile.js b/Gulpfile.js new file mode 100644 index 0000000000000000000000000000000000000000..3d972f08fa2be4d9af0de6d1b6b37a6ce1c538a2 --- /dev/null +++ b/Gulpfile.js @@ -0,0 +1,212 @@ +/*! + * Bootstrap's Gulpfile + * http://getbootstrap.com + * Copyright 2013-2016 The Bootstrap Authors + * Copyright 2013-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +var autoprefix = require('gulp-autoprefixer'), + babel = require('gulp-babel'), + build = require('build-control'), + clean = require('gulp-clean'), + cleancss = require('gulp-clean-css'), + concat = require('gulp-concat'), + debug = require('gulp-debug'), + eslint = require('gulp-eslint'), + exec = require('gulp-exec'), + flexbox = require('postcss-flexbox-fixes'), + gulp = require('gulp'), + htmlhint = require('gulp-html-hint'), + htmllint = require('gulp-html'), + isTravis = require('is-travis'), + jscs = require('gulp-jscs'), + jshint = require('gulp-jshint'), + postcss = require('gulp-postcss'), + rename = require('gulp-rename'), + sass = require('gulp-ruby-sass'), + scsslint = require('gulp-scss-lint'), + stamp = require('gulp-stamp'), + sourcemaps = require('gulp-sourcemaps'), + uglify = require('gulp-uglify'); + +// Equivalent to time-grunt +require("time-require"); + +// Project configuration. +var config = require('./gulp/config.js'); +config.autoprefixer = require('./gulp/postcss.js').autoprefixer; + +// Build SCSS +gulp.task('sass:core', () =>) { + var scss = gulp.src('scss/bootstrap.scss', { base: config.core.files.cwd }); + scss + .pipe(debug({ title: 'sassc:' })) + .pipe(sourcemaps.init()) + .pipe(sass().on('error', sass.logError)) + .pipe(autoprefix(config.autoprefixer.browsers)) + .pipe(postcss([flexbox])) + .pipe(sourcemaps.write()) + .pipe(debug({ title: 'copy:' })) + .pipe(gulp.dest('dist/css/')); + + scss + .pipe(debug({ title: 'sassc:' })) + .pipe(sourcemaps.init()) + .pipe(sass().on('error', sass.logError)) + .pipe(autoprefix(config.autoprefixer.browsers)) + .pipe(postcss([flexbox])) + .pipe(cleancss(config.cssmin.options)) + .pipe(sourcemaps.write()) + .pipe(debug({ title: 'copy:' })) + .pipe(gulp.dest('dist/css/')); +}); + +gulp.task('sass:docs', () => { + return gulp.src('docs/assets/scss/docs.scss'); + .pipe(debug({ title: 'sassc:' })) + .pipe(sass().on('error', sass.logError)) + .pipe(autoprefix(config.autoprefixer.browsers)) + .pipe(postcss([flexbox])) + .pipe(cleancss(config.cssmin.options)) + .pipe(debug({ title: 'copy:' })) + .pipe(gulp.dest('docs/assets/css/')); +}); + +gulp.task('exec:postcss-docs', () => { + return gulp.src('docs/examples/**/*.css') + .pipe(autoprefix(config.autoprefixer.browsers)) + .pipe(postcss([flexbox])); +}); + +gulp.task('clean:dist', () => { + return gulp.src('dist/**') + .pipe(clean()); +}); + +gulp.task('clean:docs', () => { + return gulp.src('docs/dist/**') + .pipe(clean()); +}); + +gulp.task('cssmin:docs', () => { + return gulp.src(config.cssmin.docs.src) + .pipe(cleancss(config.cssmin.options)) + .pipe(gulp.dest(config.cssmin.docs.dest)); +}); + +gulp.task('htmllint', () => { + return gulp.src(config.htmllint.src) + .pipe(htmllint()); +}); + +gulp.task('htmlhint', () => { + return gulp.src('_gh_pages/**/*.md') + .pipe(htmlhint('docs/.htmlhintrc')); +}); + +gulp.task('jekyll:docs', (cb) => { + exec('jekyll build --incremental', function(err, stdout, stderr) { + console.log(stdout); + console.log(stderr); + cb(err); + }); +}); + +gulp.task('babel:dev', () => { + return gulp.src('js/src/*.js') + .pipe(sourcemaps.init()) + .pipe(concat('bootstrap.js')) + .pipe(babel(config.babel.options)) + .pipe(sourcemaps.write()) + .pipe(gulp.dest('js/dist/')); +}); + +gulp.task('concat', () => { + gulp.src(config.concat.bootstrap.src) + .pipe(concat('bootstrap.js')) + .pipe(gulp.dest('dist/js/')); +}); + +gulp.task('babel:dist', () => { + return gulp.src(config.concat.bootstrap.dest) + .pipe(babel()) + .pipe(gulp.dest('dist/js/')); +}); + +gulp.task('stamp', () => { + return gulp.src(config.concat.bootstrap.dest) + .pipe(stamp(config.stamp.options)) + .pipe(gulp.dest('dist/js/')); +}); + +gulp.task('uglify:core', () => { + return gulp.src(config.concat.bootstrap.dest) + .pipe(uglify(config.uglfy.options)) + .pipe(rename('bootstrap.min.js')) + .pipe('dist/js/'); +}); + +gulp.task('watch', () => { + gulp.watch(config.watch.sass.files, config.watch.sass.tasks); + gulp.watch(config.watch.src.files, config.watch.src.tasks); + gulp.watch(config.watch.docs.files, config.watch.docs.tasks); +}); + +// Docs HTML validation task +gulp.task('validate-html', ['jekyll:docs', 'htmllint', 'htmlhint']); +// JS distribution task. +gulp.task('dist-js', ['babel:dev', 'concat', 'babel:dist', 'stamp', 'uglify:core']); + +gulp.task('test-scss', () => { + return gulp.src(config.scsslint.core.src) + .pipe(scsslint(config.scsslint.options)); +}); + +// CSS distribution task. +// gulp.task('sass-compile', ['sass:core', 'sass:extras', 'sass:docs']); +gulp.task('sass-compile', ['sass:core', 'sass:docs']); + +gulp.task('dist-css', ['sass-compile', 'cssmin:docs']); + +// Full distribution task. +gulp.task('dist', ['clean:dist', 'dist-css', 'dist-js']); + +// Default task. +gulp.task('default', ['clean:dist', 'test']); +gulp.task('test', ['eslint', 'jscs', ]); +gulp.task('eslint', () => { + var options = require('./js/.eslintrc.json'); + return gulp.src('js/src/*.js') + .pipe(eslint(options)) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); +gulp.task('jscs', () => { + var options = require('./js/.jscsrc'); + return gulp.src(['js/src/*', 'js/tests/unit', 'docs/assets/js/src/*', 'gulp/*', 'Gulpfile.js', 'docs/assets/js/ie-emulation-modes-warning.js', 'docs/assets/js/ie10-viewport-bug-workaround.js']) + .pipe(jscs(options)) + .pipe(jscs.reporter()); +}); +// Docs task. +gulp.task('docs-css', ['cssmin:docs', 'exec:postcss-docs']); +gulp.task('lint-docs-css', () => { + return gulp.src(config.scsslint.docs.src) + .pipe(scsslint(config.scsslint.options)); +}); +gulp.task('docs-js', ['uglify:docsJs']); +gulp.task('docs', ['lint-docs-css', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs']); +gulp.task('docs-github', (cb) => { + exec('jekyll build --incremental', (err, stdout, stderr) => { + console.log(stdout); + console.log(stderr); + cb(err); + }); +}); + +gulp.task('prep-release', ['dist', 'docs', 'docs-github', 'compress']); + +// Publish to GitHub +gulp.task('publish', () => { + build(config.buildcontrol.options); +}); diff --git a/grunt/bs-sass-compile/libsass.js b/gulp/bs-sass-compile/libsass.js similarity index 100% rename from grunt/bs-sass-compile/libsass.js rename to gulp/bs-sass-compile/libsass.js diff --git a/grunt/bs-sass-compile/sass.js b/gulp/bs-sass-compile/sass.js similarity index 100% rename from grunt/bs-sass-compile/sass.js rename to gulp/bs-sass-compile/sass.js diff --git a/grunt/change-version.js b/gulp/change-version.js similarity index 100% rename from grunt/change-version.js rename to gulp/change-version.js diff --git a/gulp/config.js b/gulp/config.js new file mode 100644 index 0000000000000000000000000000000000000000..bd63ea3f20698e28083377ece65011877d7e525d --- /dev/null +++ b/gulp/config.js @@ -0,0 +1,291 @@ +module.exports = { + + // Metadata. + pkg: require('../package.json'), + banner: '/*!\n' + + ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + + ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + + ' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' + + ' */\n', + jqueryCheck: 'if (typeof jQuery === \'undefined\') {\n' + + ' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\')\n' + + '}\n', + jqueryVersionCheck: '+function ($) {\n' + + ' var version = $.fn.jquery.split(\' \')[0].split(\'.\')\n' + + ' if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] >= 4)) {\n' + + ' throw new Error(\'Bootstrap\\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0\')\n' + + ' }\n' + + '}(jQuery);\n\n', + + // Task configuration. + clean: { + dist: 'dist', + docs: 'docs/dist' + }, + + // JS build configuration + babel: { + dev: { + options: { + sourceMap: true, + modules: 'ignore' + }, + files: { + 'js/dist/util.js' : 'js/src/util.js', + 'js/dist/alert.js' : 'js/src/alert.js', + 'js/dist/button.js' : 'js/src/button.js', + 'js/dist/carousel.js' : 'js/src/carousel.js', + 'js/dist/collapse.js' : 'js/src/collapse.js', + 'js/dist/dropdown.js' : 'js/src/dropdown.js', + 'js/dist/modal.js' : 'js/src/modal.js', + 'js/dist/scrollspy.js' : 'js/src/scrollspy.js', + 'js/dist/tab.js' : 'js/src/tab.js', + 'js/dist/tooltip.js' : 'js/src/tooltip.js', + 'js/dist/popover.js' : 'js/src/popover.js' + } + }, + dist: { + options: { + modules: 'ignore' + }, + files: { + '<%= concat.bootstrap.dest %>' : '<%= concat.bootstrap.dest %>' + } + } + }, + + stamp: { + options: { + banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>\n+function ($) {\n', + footer: '\n}(jQuery);' + }, + bootstrap: { + files: { + src: '<%= concat.bootstrap.dest %>' + } + } + }, + + concat: { + options: { + // Custom function to remove all export and import statements + process: function (src) { + return src.replace(/^(export|import).*/gm, ''); + }, + stripBanners: false + }, + bootstrap: { + src: [ + 'js/src/util.js', + 'js/src/alert.js', + 'js/src/button.js', + 'js/src/carousel.js', + 'js/src/collapse.js', + 'js/src/dropdown.js', + 'js/src/modal.js', + 'js/src/scrollspy.js', + 'js/src/tab.js', + 'js/src/tooltip.js', + 'js/src/popover.js' + ], + dest: 'dist/js/<%= pkg.name %>.js' + } + }, + + uglify: { + options: { + compress: { + warnings: false + }, + mangle: true, + preserveComments: /^!|@preserve|@license|@cc_on/i + }, + core: { + src: '<%= concat.bootstrap.dest %>', + dest: 'dist/js/<%= pkg.name %>.min.js' + }, + docsJs: { + src: configBridge.paths.docsJs, + dest: 'docs/assets/js/docs.min.js' + } + }, + + qunit: { + options: { + inject: 'js/tests/unit/phantom.js' + }, + files: 'js/tests/index.html' + }, + + // CSS build configuration + scsslint: { + options: { + bundleExec: true, + config: 'scss/.scss-lint.yml', + reporterOutput: null + }, + core: { + src: ['scss/*.scss', '!scss/_normalize.scss'] + }, + docs: { + src: ['docs/assets/scss/*.scss', '!docs/assets/scss/docs.scss'] + } + }, + + cssmin: { + options: { + // TODO: disable `zeroUnits` optimization once clean-css 3.2 is released + // and then simplify the fix for https://github.com/twbs/bootstrap/issues/14837 accordingly + compatibility: 'ie9', + keepSpecialComments: '*', + sourceMap: true, + advanced: false + }, + core: { + files: [ + { + expand: true, + cwd: 'dist/css', + src: ['*.css', '!*.min.css'], + dest: 'dist/css', + ext: '.min.css' + } + ] + }, + docs: { + src: 'docs/assets/css/docs.min.css', + dest: 'docs/assets/css/docs.min.css' + } + }, + + copy: { + docs: { + expand: true, + cwd: 'dist/', + src: [ + '**/*' + ], + dest: 'docs/dist/' + } + }, + + connect: { + server: { + options: { + port: 3000, + base: '.' + } + } + }, + + jekyll: { + options: { + bundleExec: true, + config: '_config.yml', + incremental: false + }, + docs: {}, + github: { + options: { + raw: 'github: true' + } + } + }, + + htmllint: { + options: { + ignore: [ + 'Attribute “autocomplete†is only allowed when the input type is “colorâ€, “dateâ€, “datetimeâ€, “datetime-localâ€, “emailâ€, “hiddenâ€, “monthâ€, “numberâ€, “passwordâ€, “rangeâ€, “searchâ€, “telâ€, “textâ€, “timeâ€, “urlâ€, or “weekâ€.', + 'Attribute “autocomplete†not allowed on element “button†at this point.', + 'Consider using the “h1†element as a top-level heading only (all “h1†elements are treated as top-level headings by many screen readers and other tools).', + 'Element “div†not allowed as child of element “progress†in this context. (Suppressing further errors from this subtree.)', + 'Element “img†is missing required attribute “srcâ€.', + 'The “color†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', + 'The “date†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', + 'The “datetime†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', + 'The “datetime-local†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', + 'The “month†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', + 'The “time†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', + 'The “week†input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.' + ] + }, + src: ['_gh_pages/**/*.html', 'js/tests/visual/*.html'] + }, + + watch: { + src: { + files: '<%= concat.bootstrap.src %>', + tasks: ['babel:dev'] + }, + sass: { + files: 'scss/**/*.scss', + tasks: ['dist-css', 'docs'] + }, + docs: { + files: 'docs/assets/scss/**/*.scss', + tasks: ['dist-css', 'docs'] + } + }, + + 'saucelabs-qunit': { + all: { + options: { + build: process.env.TRAVIS_JOB_ID, + concurrency: 10, + maxRetries: 3, + maxPollRetries: 4, + urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'], + browsers: grunt.file.readYAML('grunt/sauce_browsers.yml') + } + } + }, + + exec: { + postcss: { + command: 'npm run postcss' + }, + 'postcss-docs': { + command: 'npm run postcss-docs' + }, + htmlhint: { + command: 'npm run htmlhint' + }, + 'upload-preview': { + command: './grunt/upload-preview.sh' + } + }, + + buildcontrol: { + options: { + dir: '_gh_pages', + commit: true, + push: true, + message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%' + }, + pages: { + options: { + remote: 'git@github.com:twbs/derpstrap.git', + branch: 'gh-pages' + } + } + }, + + compress: { + main: { + options: { + archive: 'bootstrap-<%= pkg.version %>-dist.zip', + mode: 'zip', + level: 9, + pretty: true + }, + files: [ + { + expand: true, + cwd: 'dist/', + src: ['**'], + dest: 'bootstrap-<%= pkg.version %>-dist' + } + ] + } + } +}; diff --git a/grunt/configBridge.json b/gulp/configBridge.json similarity index 100% rename from grunt/configBridge.json rename to gulp/configBridge.json diff --git a/grunt/gcp-key.json.enc b/gulp/gcp-key.json.enc similarity index 100% rename from grunt/gcp-key.json.enc rename to gulp/gcp-key.json.enc diff --git a/grunt/npm-shrinkwrap.json b/gulp/npm-shrinkwrap.json similarity index 100% rename from grunt/npm-shrinkwrap.json rename to gulp/npm-shrinkwrap.json diff --git a/grunt/postcss.js b/gulp/postcss.js similarity index 100% rename from grunt/postcss.js rename to gulp/postcss.js diff --git a/grunt/sauce_browsers.yml b/gulp/sauce_browsers.yml similarity index 100% rename from grunt/sauce_browsers.yml rename to gulp/sauce_browsers.yml diff --git a/grunt/upload-preview.sh b/gulp/upload-preview.sh similarity index 100% rename from grunt/upload-preview.sh rename to gulp/upload-preview.sh diff --git a/package.json b/package.json index 2d6b598d2d454e12fbc47a1e92d4634a7317316c..26017ef209f3c4cc7dc7e63e914de4adcd1fe24a 100644 --- a/package.json +++ b/package.json @@ -17,14 +17,8 @@ "Twitter, Inc." ], "scripts": { - "change-version": "node grunt/change-version.js", - "eslint": "eslint --config js/.eslintrc.json js/src", - "jscs": "jscs --config=js/.jscsrc js/src js/tests/unit docs/assets/js/src grunt Gruntfile.js docs/assets/js/ie-emulation-modes-warning.js docs/assets/js/ie10-viewport-bug-workaround.js", - "htmlhint": "htmlhint --config docs/.htmlhintrc _gh_pages/", - "postcss": "postcss --config grunt/postcss.js --replace dist/css/*.css", - "postcss-docs": "postcss --config grunt/postcss.js --no-map --replace docs/assets/css/docs.min.css && postcss --config grunt/postcss.js --no-map --replace docs/examples/**/*.css", - "shrinkwrap": "npm shrinkwrap --dev && shx mv ./npm-shrinkwrap.json ./grunt/npm-shrinkwrap.json", - "test": "npm run eslint && npm run jscs && grunt test" + "change-version": "node gulp/change-version.js", + "shrinkwrap": "npm shrinkwrap --dev && shx mv ./npm-shrinkwrap.json ./gulp/npm-shrinkwrap.json" }, "style": "dist/css/bootstrap.css", "sass": "scss/bootstrap.scss", @@ -42,38 +36,38 @@ "tether": "^1.1.1" }, "devDependencies": { - "autoprefixer": "^6.0.3", "babel-eslint": "^6.0.4", + "build-control": "^0.3.8", "eslint": "^3.0.0", - "grunt": "^1.0.1", - "grunt-babel": "^5.0.3", - "grunt-build-control": "^0.7.0", - "grunt-contrib-clean": "^1.0.0", - "grunt-contrib-compress": "^1.1.0", - "grunt-contrib-concat": "^1.0.0", - "grunt-contrib-connect": "^1.0.0", - "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-cssmin": "^1.0.0", - "grunt-contrib-qunit": "^1.0.1", - "grunt-contrib-sass": "^1.0.0", - "grunt-contrib-uglify": "^1.0.0", - "grunt-contrib-watch": "^1.0.0", - "grunt-exec": "^1.0.0", - "grunt-html": "^8.0.1", - "grunt-jekyll": "^0.4.2", - "grunt-sass": "^1.0.0", - "grunt-saucelabs": "^9.0.0", - "grunt-scss-lint": "^0.3.8", - "grunt-stamp": "^0.3.0", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-clean": "^0.3.2", + "gulp-clean-css": "^2.0.11", + "gulp-concat": "^2.6.0", + "gulp-connect": "^4.1.0", + "gulp-debug": "^2.1.2", + "gulp-eslint": "^3.0.1", + "gulp-exec": "^2.1.2", + "gulp-html": "^0.4.4", + "gulp-htmlhint": "^0.3.1", + "gulp-jscs": "^4.0.0", + "gulp-jshint": "^2.0.1", + "gulp-postcss": "^6.1.1", + "gulp-qunit": "^1.4.0", + "gulp-rename": "^1.2.2", + "gulp-ruby-sass": "^2.0.6", + "gulp-scss-lint": "^0.4.0", + "gulp-sourcemaps": "^1.6.0", + "gulp-stamp": "0.0.9", + "gulp-uglify": "^1.5.4", "htmlhint": "^0.9.13", "is-travis": "^1.0.0", "jscs": "^3.0.4", - "load-grunt-tasks": "^3.4.0", - "postcss-cli": "^2.5.2", + "jshint": "^2.9.2", "postcss-flexbugs-fixes": "^2.0.0", "shelljs": "^0.7.0", "shx": "^0.1.2", - "time-grunt": "^1.2.1" + "time-require": "^0.1.2" }, "engines": { "node": ">=4"