mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
763ade6dda
Summary of the changes:
* expand `node_smoke_tests` to test the full & slim builds
* run `compare_size` on all built minified files; don't run it anymore on
unminified files where they don't provide lots of value
The main goal of this change is to make it easier to compare sizes of both the
full & slim builds between the `3.x-stable` & `main` branches.
Closes gh-5291
Ref gh-5255
(partially cherry-picked from commit 8be4c0e4f8
)
369 lines
10 KiB
JavaScript
369 lines
10 KiB
JavaScript
/**
|
|
* Special concat/build task to handle various jQuery build requirements
|
|
* Concats AMD modules, removes their definitions,
|
|
* and includes/excludes specified modules
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
module.exports = function( grunt ) {
|
|
var fs = require( "fs" ),
|
|
requirejs = require( "requirejs" ),
|
|
slimBuildFlags = require( "./lib/slim-build-flags" ),
|
|
srcFolder = __dirname + "/../../src/",
|
|
rdefineEnd = /\}\s*?\);[^}\w]*$/,
|
|
read = function( fileName ) {
|
|
return grunt.file.read( srcFolder + fileName );
|
|
},
|
|
|
|
// Catch `// @CODE` and subsequent comment lines event if they don't start
|
|
// in the first column.
|
|
wrapper = read( "wrapper.js" ).split( /[\x20\t]*\/\/ @CODE\n(?:[\x20\t]*\/\/[^\n]+\n)*/ ),
|
|
|
|
config = {
|
|
baseUrl: "src",
|
|
name: "jquery",
|
|
|
|
// Allow strict mode
|
|
useStrict: true,
|
|
|
|
// We have multiple minify steps
|
|
optimize: "none",
|
|
|
|
// Include dependencies loaded with require
|
|
findNestedDependencies: true,
|
|
|
|
// Avoid inserting define() placeholder
|
|
skipModuleInsertion: true,
|
|
|
|
// Avoid breaking semicolons inserted by r.js
|
|
skipSemiColonInsertion: true,
|
|
wrap: {
|
|
start: wrapper[ 0 ].replace( /\/\*\s*eslint(?: |-).*\s*\*\/\n/, "" ),
|
|
end: wrapper[ 1 ]
|
|
},
|
|
rawText: {},
|
|
onBuildWrite: convert
|
|
};
|
|
|
|
/**
|
|
* Strip all definitions generated by requirejs
|
|
* Convert "var" modules to var declarations
|
|
* "var module" means the module only contains a return
|
|
* statement that should be converted to a var declaration
|
|
* This is indicated by including the file in any "var" folder
|
|
* @param {String} name
|
|
* @param {String} path
|
|
* @param {String} contents The contents to be written (including their AMD wrappers)
|
|
*/
|
|
function convert( name, path, contents ) {
|
|
var amdName;
|
|
|
|
// Convert var modules
|
|
if ( /.\/var\//.test( path.replace( process.cwd(), "" ) ) ) {
|
|
contents = contents
|
|
.replace(
|
|
/define\(\s*(["'])[\w\W]*?\1[\w\W]*?return/,
|
|
"var " +
|
|
( /var\/([\w-]+)/.exec( name )[ 1 ] ) +
|
|
" ="
|
|
)
|
|
.replace( rdefineEnd, "" );
|
|
|
|
} else {
|
|
|
|
contents = contents
|
|
.replace( /\s*return\s+[^\}]+(\}\s*?\);[^\w\}]*)$/, "$1" )
|
|
|
|
// Multiple exports
|
|
.replace( /\s*exports\.\w+\s*=\s*\w+;/g, "" );
|
|
|
|
// Remove define wrappers, closure ends, and empty declarations
|
|
contents = contents
|
|
.replace( /define\([^{]*?{\s*(?:("|')use strict\1(?:;|))?/, "" )
|
|
.replace( rdefineEnd, "" );
|
|
|
|
// Remove anything wrapped with
|
|
// /* ExcludeStart */ /* ExcludeEnd */
|
|
// or a single line directly after a // BuildExclude comment
|
|
contents = contents
|
|
.replace( /\/\*\s*ExcludeStart\s*\*\/[\w\W]*?\/\*\s*ExcludeEnd\s*\*\//ig, "" )
|
|
.replace( /\/\/\s*BuildExclude\n\r?[\w\W]*?\n\r?/ig, "" );
|
|
|
|
// Remove empty definitions
|
|
contents = contents
|
|
.replace( /define\(\s*\[[^\]]*\]\s*\)[\W\n]+$/, "" );
|
|
}
|
|
|
|
// AMD Name
|
|
if ( ( amdName = grunt.option( "amd" ) ) != null && /^exports\/amd$/.test( name ) ) {
|
|
if ( amdName ) {
|
|
grunt.log.writeln( "Naming jQuery with AMD name: " + amdName );
|
|
} else {
|
|
grunt.log.writeln( "AMD name now anonymous" );
|
|
}
|
|
|
|
// Remove the comma for anonymous defines
|
|
contents = contents
|
|
.replace( /(\s*)"jquery"(\,\s*)/, amdName ? "$1\"" + amdName + "\"$2" : "" );
|
|
|
|
}
|
|
return contents;
|
|
}
|
|
|
|
grunt.registerMultiTask(
|
|
"build",
|
|
"Concatenate source, remove sub AMD definitions, " +
|
|
"(include/exclude modules with +/- flags), embed date/version",
|
|
function() {
|
|
var flag, index,
|
|
done = this.async(),
|
|
flags = this.flags,
|
|
optIn = flags[ "*" ],
|
|
name = grunt.option( "filename" ),
|
|
minimum = this.data.minimum,
|
|
removeWith = this.data.removeWith,
|
|
excluded = [],
|
|
included = [],
|
|
version = grunt.config( "pkg.version" ),
|
|
|
|
/**
|
|
* Recursively calls the excluder to remove on all modules in the list
|
|
* @param {Array} list
|
|
* @param {String} [prepend] Prepend this to the module name.
|
|
* Indicates we're walking a directory
|
|
*/
|
|
excludeList = function( list, prepend ) {
|
|
if ( list ) {
|
|
prepend = prepend ? prepend + "/" : "";
|
|
list.forEach( function( module ) {
|
|
|
|
// Exclude var modules as well
|
|
if ( module === "var" ) {
|
|
excludeList(
|
|
fs.readdirSync( srcFolder + prepend + module ), prepend + module
|
|
);
|
|
return;
|
|
}
|
|
if ( prepend ) {
|
|
|
|
// Skip if this is not a js file and we're walking files in a dir
|
|
if ( !( module = /([\w-\/]+)\.js$/.exec( module ) ) ) {
|
|
return;
|
|
}
|
|
|
|
// Prepend folder name if passed
|
|
// Remove .js extension
|
|
module = prepend + module[ 1 ];
|
|
}
|
|
|
|
// Avoid infinite recursion
|
|
if ( excluded.indexOf( module ) === -1 ) {
|
|
excluder( "-" + module );
|
|
}
|
|
} );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Adds the specified module to the excluded or included list, depending on the flag
|
|
* @param {String} flag A module path relative to
|
|
* the src directory starting with + or - to indicate
|
|
* whether it should be included or excluded
|
|
*/
|
|
excluder = function( flag ) {
|
|
var additional,
|
|
m = /^(\+|-|)([\w\/-]+)$/.exec( flag ),
|
|
exclude = m[ 1 ] === "-",
|
|
module = m[ 2 ];
|
|
|
|
// Recognize the legacy `sizzle` alias
|
|
if ( module === "sizzle" ) {
|
|
module = "selector";
|
|
}
|
|
|
|
if ( exclude ) {
|
|
|
|
// Can't exclude certain modules
|
|
if ( minimum.indexOf( module ) === -1 ) {
|
|
|
|
// Add to excluded
|
|
if ( excluded.indexOf( module ) === -1 ) {
|
|
grunt.log.writeln( flag );
|
|
excluded.push( module );
|
|
|
|
// Exclude all files in the folder of the same name
|
|
// These are the removable dependencies
|
|
// It's fine if the directory is not there
|
|
try {
|
|
|
|
// `selector` is a special case as we don't just remove
|
|
// the module, but we replace it with `selector-native`
|
|
// which re-uses parts of the `src/selector` folder.
|
|
if ( module !== "selector" ) {
|
|
excludeList(
|
|
fs.readdirSync( `${ srcFolder }/${ module }` ),
|
|
module
|
|
);
|
|
}
|
|
} catch ( e ) {
|
|
grunt.verbose.writeln( e );
|
|
}
|
|
}
|
|
|
|
additional = removeWith[ module ];
|
|
|
|
// Check removeWith list
|
|
if ( additional ) {
|
|
excludeList( additional.remove || additional );
|
|
if ( additional.include ) {
|
|
included = included.concat( additional.include );
|
|
grunt.log.writeln( "+" + additional.include );
|
|
}
|
|
}
|
|
} else {
|
|
grunt.log.error( "Module \"" + module + "\" is a minimum requirement." );
|
|
}
|
|
} else {
|
|
grunt.log.writeln( flag );
|
|
included.push( module );
|
|
}
|
|
};
|
|
|
|
// Filename can be passed to the command line using
|
|
// command line options
|
|
// e.g. grunt build --filename=jquery-custom.js
|
|
name = name ? ( "dist/" + name ) : this.data.dest;
|
|
|
|
// append commit id to version
|
|
if ( process.env.COMMIT ) {
|
|
version += " " + process.env.COMMIT;
|
|
}
|
|
|
|
// figure out which files to exclude based on these rules in this order:
|
|
// dependency explicit exclude
|
|
// > explicit exclude
|
|
// > explicit include
|
|
// > dependency implicit exclude
|
|
// > implicit exclude
|
|
// examples:
|
|
// * none (implicit exclude)
|
|
// *:* all (implicit include)
|
|
// *:*:-css all except css and dependents (explicit > implicit)
|
|
// *:*:-css:+effects same (excludes effects because explicit include is
|
|
// trumped by explicit exclude of dependency)
|
|
// *:+effects none except effects and its dependencies
|
|
// (explicit include trumps implicit exclude of dependency)
|
|
delete flags[ "*" ];
|
|
for ( flag in flags ) {
|
|
excluder( flag );
|
|
}
|
|
|
|
// Handle full selector module exclusion.
|
|
// Replace with selector-native.
|
|
if ( excluded.indexOf( "selector" ) > -1 ) {
|
|
config.rawText.selector = "define([ \"./selector-native\" ]);";
|
|
}
|
|
|
|
// Replace exports/global with a noop noConflict
|
|
if ( ( index = excluded.indexOf( "exports/global" ) ) > -1 ) {
|
|
config.rawText[ "exports/global" ] = "define( [\n\t\"../core\"\n], " +
|
|
"function( jQuery ) {\n\tjQuery.noConflict = function() {};\n} );";
|
|
excluded.splice( index, 1 );
|
|
}
|
|
|
|
grunt.verbose.writeflags( excluded, "Excluded" );
|
|
grunt.verbose.writeflags( included, "Included" );
|
|
|
|
// append excluded modules to version
|
|
if ( excluded.length ) {
|
|
version += " -" + excluded.join( ",-" );
|
|
|
|
// set pkg.version to version with excludes, so minified file picks it up
|
|
grunt.config.set( "pkg.version", version );
|
|
grunt.verbose.writeln( "Version changed to " + version );
|
|
|
|
// Have to use shallow or core will get excluded since it is a dependency
|
|
config.excludeShallow = excluded;
|
|
}
|
|
config.include = included;
|
|
|
|
/**
|
|
* Handle Final output from the optimizer
|
|
* @param {String} compiled
|
|
*/
|
|
config.out = function( compiled ) {
|
|
compiled = compiled
|
|
|
|
// Embed Version
|
|
.replace( /@VERSION/g, version )
|
|
|
|
// Embed Date
|
|
// yyyy-mm-ddThh:mmZ
|
|
.replace( /@DATE/g, ( new Date() ).toISOString().replace( /:\d+\.\d+Z$/, "Z" ) );
|
|
|
|
// Write concatenated source to file
|
|
grunt.file.write( name, compiled );
|
|
};
|
|
|
|
// Turn off opt-in if necessary
|
|
if ( !optIn ) {
|
|
|
|
// Overwrite the default inclusions with the explicit ones provided
|
|
config.rawText.jquery = "define( [\n" +
|
|
( included.length ?
|
|
included.map( module => "\t\"./" + module + "\"" ).join( ",\n" ) :
|
|
"" ) +
|
|
"\n] );";
|
|
}
|
|
|
|
// Trace dependencies and concatenate files
|
|
requirejs.optimize( config, function( response ) {
|
|
grunt.verbose.writeln( response );
|
|
grunt.log.ok( "File '" + name + "' created." );
|
|
done();
|
|
}, function( err ) {
|
|
done( err );
|
|
} );
|
|
} );
|
|
|
|
// Special "alias" task to make custom build creation less grawlix-y
|
|
// Translation example
|
|
//
|
|
// grunt custom:+ajax,-dimensions,-effects,-offset
|
|
//
|
|
// Becomes:
|
|
//
|
|
// grunt build:*:*:+ajax:-dimensions:-effects:-offset
|
|
//
|
|
// There's also a special "slim" alias that resolves to the jQuery Slim build
|
|
// configuration:
|
|
//
|
|
// grunt custom:slim
|
|
grunt.registerTask( "custom", function() {
|
|
var args = this.args,
|
|
modules = args.length ?
|
|
args[ 0 ]
|
|
.split( "," )
|
|
|
|
// Replace "slim" with respective exclusions meant for
|
|
// the official slim build
|
|
.reduce( ( acc, elem ) => acc.concat(
|
|
elem === "slim" ?
|
|
slimBuildFlags :
|
|
[ elem ]
|
|
), [] )
|
|
|
|
.join( ":" ) :
|
|
"";
|
|
|
|
grunt.log.writeln( "Creating custom build...\n" );
|
|
grunt.task.run( [
|
|
"build:*:*" + ( modules ? ":" + modules : "" ),
|
|
"uglify",
|
|
"remove_map_comment",
|
|
"dist"
|
|
] );
|
|
} );
|
|
};
|