From 213eaad880b4f11b65394f4f9b6c44da92954670 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 16 Aug 2013 09:48:00 -0400 Subject: [PATCH] Move jQuery specific tasks to independent files. Close gh-1334. Also: * Confirm build task to the style guide * Use grunt API to load jQuery specific tasks * Add "use strict"; statements Conflicts: Gruntfile.js build/tasks/build.js --- Gruntfile.js | 201 ++----------------------------------- build/{ => tasks}/build.js | 14 +-- build/tasks/dist.js | 90 +++++++++++++++++ build/tasks/testswarm.js | 50 +++++++++ build/tasks/uglify.js | 54 ++++++++++ 5 files changed, 213 insertions(+), 196 deletions(-) rename build/{ => tasks}/build.js (96%) create mode 100644 build/tasks/dist.js create mode 100644 build/tasks/testswarm.js create mode 100644 build/tasks/uglify.js diff --git a/Gruntfile.js b/Gruntfile.js index 538f6fb80..5cad93f65 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,15 +2,7 @@ module.exports = function( grunt ) { "use strict"; - // Integrate build task - require( "./build/build" )( grunt ); - - var distpaths = [ - "dist/jquery.js", - "dist/jquery.min.map", - "dist/jquery.min.js" - ], - gzip = require("gzip-js"), + var gzip = require( "gzip-js" ), readOptionalJSON = function( filepath ) { var data = {}; try { @@ -18,7 +10,6 @@ module.exports = function( grunt ) { } catch(e) {} return data; }, - fs = require( "fs" ), srcHintOptions = readOptionalJSON( "src/.jshintrc" ); // The concatenated file won't pass onevar @@ -66,7 +57,7 @@ module.exports = function( grunt ) { options: srcHintOptions }, grunt: { - src: [ "Gruntfile.js", "build/build.js" ], + src: [ "Gruntfile.js", "build/tasks/*" ], options: { jshintrc: ".jshintrc" } @@ -136,186 +127,16 @@ module.exports = function( grunt ) { } }); - grunt.registerTask( "testswarm", function( commit, configFile ) { - var jobName, - testswarm = require( "testswarm" ), - runs = {}, - done = this.async(), - pull = /PR-(\d+)/.exec( commit ), - config = grunt.file.readJSON( configFile ).jquery, - tests = grunt.config([ this.name, "tests" ]); - - if ( pull ) { - jobName = "jQuery pull #" + pull[ 1 ] + ""; - } else { - jobName = "jQuery commit #" + commit.substr( 0, 10 ) + ""; - } - - tests.forEach(function( test ) { - runs[test] = config.testUrl + commit + "/test/index.html?module=" + test; - }); - - testswarm.createClient( { - url: config.swarmUrl, - pollInterval: 10000, - timeout: 1000 * 60 * 30 - } ) - .addReporter( testswarm.reporters.cli ) - .auth( { - id: config.authUsername, - token: config.authToken - }) - .addjob( - { - name: jobName, - runs: runs, - runMax: config.runMax, - browserSets: config.browserSets - }, function( err, passed ) { - if ( err ) { - grunt.log.error( err ); - } - done( passed ); - } - ); - }); - - // Process files for distribution - grunt.registerTask( "dist", function() { - var stored, flags, paths, nonascii; - - // Check for stored destination paths - // ( set in dist/.destination.json ) - stored = Object.keys( grunt.config( "dst" ) ); - - // Allow command line input as well - flags = Object.keys( this.flags ); - - // Combine all output target paths - paths = [].concat( stored, flags ).filter(function( path ) { - return path !== "*"; - }); - - // Ensure the dist files are pure ASCII - nonascii = false; - - distpaths.forEach(function( filename ) { - var i, c, - text = fs.readFileSync( filename, "utf8" ); - - // Ensure files use only \n for line endings, not \r\n - if ( /\x0d\x0a/.test( text ) ) { - grunt.log.writeln( filename + ": Incorrect line endings (\\r\\n)" ); - nonascii = true; - } - - // Ensure only ASCII chars so script tags don't need a charset attribute - if ( text.length !== Buffer.byteLength( text, "utf8" ) ) { - grunt.log.writeln( filename + ": Non-ASCII characters detected:" ); - for ( i = 0; i < text.length; i++ ) { - c = text.charCodeAt( i ); - if ( c > 127 ) { - grunt.log.writeln( "- position " + i + ": " + c ); - grunt.log.writeln( "-- " + text.substring( i - 20, i + 20 ) ); - break; - } - } - nonascii = true; - } - - // Modify map/min so that it points to files in the same folder; - // see https://github.com/mishoo/UglifyJS2/issues/47 - if ( /\.map$/.test( filename ) ) { - text = text.replace( /"dist\//g, "\"" ); - fs.writeFileSync( filename, text, "utf-8" ); - - // Use our hard-coded sourceMap directive instead of the autogenerated one (#13274; #13776) - } else if ( /\.min\.js$/.test( filename ) ) { - i = 0; - text = text.replace( /(?:\/\*|)\n?\/\/@\s*sourceMappingURL=.*(\n\*\/|)/g, - function( match ) { - if ( i++ ) { - return ""; - } - return match; - }); - fs.writeFileSync( filename, text, "utf-8" ); - } - - // Optionally copy dist files to other locations - paths.forEach(function( path ) { - var created; - - if ( !/\/$/.test( path ) ) { - path += "/"; - } - - created = path + filename.replace( "dist/", "" ); - grunt.file.write( created, text ); - grunt.log.writeln( "File '" + created + "' created." ); - }); - }); - - return !nonascii; - }); - - // Work around grunt-contrib-uglify sourceMap issues (jQuery #13776) - grunt.registerMultiTask( "pre-uglify", function() { - var banner = this.options().banner; - - this.files.forEach(function( mapping ) { - // Join src - var input = mapping.src.map(function( file ) { - var contents = grunt.file.read( file ); - - // Strip banners - return contents - // Remove the main jQuery banner, it'll be replaced by the new banner anyway. - .replace( /^\/\*![\W\w]*?\*\/\n?/g, "" ) - // Strip other banners preserving line count. - .replace( /^\/\*!(?:.|\n)*?\*\/\n?/gm, function ( match ) { - return match.replace( /[^\n]/gm, "" ); - }); - }).join("\n"); - - // Write temp file (with optional banner) - grunt.file.write( mapping.dest, ( banner || "" ) + input ); - }); - }); - - // Change the map file to point back to jquery.js instead of jquery.pre-min.js. - // The problem is caused by the pre-uglify task. - // Also, remove temporary files. - grunt.registerMultiTask( "post-uglify", function() { - this.files.forEach(function( mapping ) { - var mapFileName = mapping.src[ 0 ]; - - // Rename the file to a temporary name. - fs.renameSync( mapFileName, mapping.dest); - grunt.file.write( mapFileName, grunt.file.read( mapping.dest ) - // The uglify task erroneously prepends dist/ to file names. - .replace( /"dist\//g, "\"" ) - // Refer to the source jquery.js, not the temporary jquery.pre-min.js. - .replace( /\.pre-min\./g, "." ) - // There's already a pragma at the beginning of the file, remove the one at the end. - .replace( /\/\/@ sourceMappingURL=jquery\.min\.map$/g, "" )); - }); - - // Remove temporary files. - this.options().tempFiles.forEach(function( fileName ) { - fs.unlink( fileName ); - }); - }); - // Load grunt tasks from NPM packages - grunt.loadNpmTasks("grunt-compare-size"); - grunt.loadNpmTasks("grunt-git-authors"); - grunt.loadNpmTasks("grunt-contrib-watch"); - grunt.loadNpmTasks("grunt-contrib-jshint"); - grunt.loadNpmTasks("grunt-contrib-uglify"); - grunt.loadNpmTasks("grunt-jsonlint"); + grunt.loadNpmTasks( "grunt-compare-size" ); + grunt.loadNpmTasks( "grunt-git-authors" ); + grunt.loadNpmTasks( "grunt-contrib-watch" ); + grunt.loadNpmTasks( "grunt-contrib-jshint" ); + grunt.loadNpmTasks( "grunt-contrib-uglify" ); + grunt.loadNpmTasks( "grunt-jsonlint" ); + + // Integrate jQuery specific tasks + grunt.loadTasks( "build/tasks" ); // Short list as a high frequency watch task grunt.registerTask( "dev", [ "build:*:*", "jshint" ] ); diff --git a/build/build.js b/build/tasks/build.js similarity index 96% rename from build/build.js rename to build/tasks/build.js index eb68f685c..ab580fdc5 100644 --- a/build/build.js +++ b/build/tasks/build.js @@ -5,11 +5,13 @@ module.exports = function( grunt ) { - var fs = require("fs"), + "use strict"; + + var fs = require( "fs" ), srcFolder = __dirname + "/../src/", rdefineEnd = /\}\);[^}\w]*$/, // This is temporary until the skipSemiColonInsertion option makes it to NPM - requirejs = require("./r"), + requirejs = require( "../r" ), config = { baseUrl: "src", name: "jquery", @@ -114,8 +116,8 @@ module.exports = function( grunt ) { */ excluder = function( flag ) { var m = /^(\+|\-|)([\w\/-]+)$/.exec( flag ), - exclude = m[1] === "-", - module = m[2]; + exclude = m[ 1 ] === "-", + module = m[ 2 ]; if ( exclude ) { // Can't exclude certain modules @@ -216,8 +218,8 @@ module.exports = function( grunt ) { // // grunt build:*:*:+ajax:-dimensions:-effects:-offset grunt.registerTask( "custom", function() { - var args = [].slice.call(arguments), - modules = args.length ? args[0].replace(/,/g, ":") : ""; + var args = [].slice.call( arguments ), + modules = args.length ? args[ 0 ].replace( /,/g, ":" ) : ""; grunt.log.writeln( "Creating custom build...\n" ); diff --git a/build/tasks/dist.js b/build/tasks/dist.js new file mode 100644 index 000000000..591078cde --- /dev/null +++ b/build/tasks/dist.js @@ -0,0 +1,90 @@ +module.exports = function( grunt ) { + + "use strict"; + + var fs = require( "fs" ), + distpaths = [ + "dist/jquery.js", + "dist/jquery.min.map", + "dist/jquery.min.js" + ]; + + // Process files for distribution + grunt.registerTask( "dist", function() { + var stored, flags, paths, nonascii; + + // Check for stored destination paths + // ( set in dist/.destination.json ) + stored = Object.keys( grunt.config( "dst" ) ); + + // Allow command line input as well + flags = Object.keys( this.flags ); + + // Combine all output target paths + paths = [].concat( stored, flags ).filter(function( path ) { + return path !== "*"; + }); + + // Ensure the dist files are pure ASCII + nonascii = false; + + distpaths.forEach(function( filename ) { + var i, c, + text = fs.readFileSync( filename, "utf8" ); + + // Ensure files use only \n for line endings, not \r\n + if ( /\x0d\x0a/.test( text ) ) { + grunt.log.writeln( filename + ": Incorrect line endings (\\r\\n)" ); + nonascii = true; + } + + // Ensure only ASCII chars so script tags don't need a charset attribute + if ( text.length !== Buffer.byteLength( text, "utf8" ) ) { + grunt.log.writeln( filename + ": Non-ASCII characters detected:" ); + for ( i = 0; i < text.length; i++ ) { + c = text.charCodeAt( i ); + if ( c > 127 ) { + grunt.log.writeln( "- position " + i + ": " + c ); + grunt.log.writeln( "-- " + text.substring( i - 20, i + 20 ) ); + break; + } + } + nonascii = true; + } + + // Modify map/min so that it points to files in the same folder; + // see https://github.com/mishoo/UglifyJS2/issues/47 + if ( /\.map$/.test( filename ) ) { + text = text.replace( /"dist\//g, "\"" ); + fs.writeFileSync( filename, text, "utf-8" ); + + // Use our hard-coded sourceMap directive instead of the autogenerated one (#13274; #13776) + } else if ( /\.min\.js$/.test( filename ) ) { + i = 0; + text = text.replace( /(?:\/\*|)\n?\/\/@\s*sourceMappingURL=.*(\n\*\/|)/g, + function( match ) { + if ( i++ ) { + return ""; + } + return match; + }); + fs.writeFileSync( filename, text, "utf-8" ); + } + + // Optionally copy dist files to other locations + paths.forEach(function( path ) { + var created; + + if ( !/\/$/.test( path ) ) { + path += "/"; + } + + created = path + filename.replace( "dist/", "" ); + grunt.file.write( created, text ); + grunt.log.writeln( "File '" + created + "' created." ); + }); + }); + + return !nonascii; + }); +}; diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js new file mode 100644 index 000000000..92b696e27 --- /dev/null +++ b/build/tasks/testswarm.js @@ -0,0 +1,50 @@ +module.exports = function( grunt ) { + + "use strict"; + + grunt.registerTask( "testswarm", function( commit, configFile ) { + var jobName, + testswarm = require( "testswarm" ), + runs = {}, + done = this.async(), + pull = /PR-(\d+)/.exec( commit ), + config = grunt.file.readJSON( configFile ).jquery, + tests = grunt.config([ this.name, "tests" ]); + + if ( pull ) { + jobName = "jQuery pull #" + pull[ 1 ] + ""; + } else { + jobName = "jQuery commit #" + commit.substr( 0, 10 ) + ""; + } + + tests.forEach(function( test ) { + runs[ test ] = config.testUrl + commit + "/test/index.html?module=" + test; + }); + + testswarm.createClient( { + url: config.swarmUrl, + pollInterval: 10000, + timeout: 1000 * 60 * 30 + } ) + .addReporter( testswarm.reporters.cli ) + .auth( { + id: config.authUsername, + token: config.authToken + }) + .addjob( + { + name: jobName, + runs: runs, + runMax: config.runMax, + browserSets: config.browserSets + }, function( err, passed ) { + if ( err ) { + grunt.log.error( err ); + } + done( passed ); + } + ); + }); +}; diff --git a/build/tasks/uglify.js b/build/tasks/uglify.js new file mode 100644 index 000000000..7c1a01bec --- /dev/null +++ b/build/tasks/uglify.js @@ -0,0 +1,54 @@ +module.exports = function( grunt ) { + + "use strict"; + + var fs = require( "fs" ); + + // Work around grunt-contrib-uglify sourceMap issues (jQuery #13776) + grunt.registerMultiTask( "pre-uglify", function() { + var banner = this.options().banner; + + this.files.forEach(function( mapping ) { + // Join src + var input = mapping.src.map(function( file ) { + var contents = grunt.file.read( file ); + + // Strip banners + return contents + // Remove the main jQuery banner, it'll be replaced by the new banner anyway. + .replace( /^\/\*![\W\w]*?\*\/\n?/g, "" ) + // Strip other banners preserving line count. + .replace( /^\/\*!(?:.|\n)*?\*\/\n?/gm, function ( match ) { + return match.replace( /[^\n]/gm, "" ); + }); + }).join("\n"); + + // Write temp file (with optional banner) + grunt.file.write( mapping.dest, ( banner || "" ) + input ); + }); + }); + + // Change the map file to point back to jquery.js instead of jquery.pre-min.js. + // The problem is caused by the pre-uglify task. + // Also, remove temporary files. + grunt.registerMultiTask( "post-uglify", function() { + this.files.forEach(function( mapping ) { + var mapFileName = mapping.src[ 0 ]; + + // Rename the file to a temporary name. + fs.renameSync( mapFileName, mapping.dest); + grunt.file.write( mapFileName, grunt.file.read( mapping.dest ) + // The uglify task erroneously prepends dist/ to file names. + .replace( /"dist\//g, "\"" ) + // Refer to the source jquery.js, not the temporary jquery.pre-min.js. + .replace( /\.pre-min\./g, "." ) + // There's already a pragma at the beginning of the file, remove the one at the end. + .replace( /\/\/@ sourceMappingURL=jquery\.min\.map$/g, "" )); + }); + + // Remove temporary files. + this.options().tempFiles.forEach(function( fileName ) { + fs.unlink( fileName ); + }); + }); +}; -- 2.39.5