Path: blob/master/emojionearea/tasks/build.js
1010 views
/**1* Special concat/build task to handle build requirements2* Concats AMD modules, removes their definitions,3* and includes/excludes specified modules4*/56module.exports = function( grunt ) {7"use strict";89var fs = require( "fs" ),10requirejs = require( "requirejs" ),11pkg = require( "../package.json" ),12srcFolder = __dirname + "/../src/",13rdefineEnd = /\n\}\s*?\);[^}\w]*$/,14read = function( fileName ) {15return grunt.file.read( srcFolder + fileName );16},17wrapper = read( "wrapper.js" ).split( /\/\/ \@CODE\n\/\/[^\n]+\n/ ),18config = {19baseUrl: "src",20name: pkg.name,2122paths: {23jquery : 'https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min'24},2526// We have multiple minify steps27optimize: "none",2829// Include dependencies loaded with require30findNestedDependencies: true,3132// Avoid inserting define() placeholder33skipModuleInsertion: true,3435// Avoid breaking semicolons inserted by r.js36skipSemiColonInsertion: true,37wrap: {38start: wrapper[ 0 ].replace( /\/\*jshint .* \*\/\n/, "" ),39end: wrapper[ 1 ]40},41rawText: {},42onBuildWrite: convert43};4445/**46* Strip all definitions generated by requirejs47* Convert "var" modules to var declarations48* "var module" means the module only contains a return49* statement that should be converted to a var declaration50* This is indicated by including the file in any "var" folder51* @param {String} name52* @param {String} path53* @param {String} contents The contents to be written (including their AMD wrappers)54*/55function convert( name, path, contents ) {56var amdName;5758// Convert var modules59if ( /.\/var\//.test( path.replace( process.cwd(), "" ) ) ) {60contents = contents61.replace( /define\([\w\W]*?return undefined\s*;/, " var " + ( /var\/([\w-]+)/.exec( name )[ 1 ] ) + ";" )62.replace( /define\([\w\W]*?return/, " var " + ( /var\/([\w-]+)/.exec( name )[ 1 ] ) + " =" )63.replace( rdefineEnd, "" );6465} else if ( /.\/function\//.test( path.replace( process.cwd(), "" ) ) ) {66contents = contents67.replace( /define\([\w\W]*?return function/, " function " + ( /function\/([\w-]+)/.exec( name )[ 1 ] ) + "")68.replace( rdefineEnd, "" );6970// Remove empty definitions71contents = contents72.replace( /define\(\[[^\]]*\]\)[\W\n]+$/, "" );7374} else {75contents = contents76.replace( /\s*return\s+[^\}]+(\}\s*?\);[^\w\}]*)$/, "$1" )7778// Multiple exports79.replace( /\s*exports\.\w+\s*=\s*\w+;/g, "" );8081// Remove define wrappers, closure ends, and empty declarations82contents = contents83.replace( /define\([^{]*?{/, "" )84.replace( rdefineEnd, "" );8586// Remove anything wrapped with87// /* ExcludeStart */ /* ExcludeEnd */88// or a single line directly after a // BuildExclude comment89contents = contents90.replace( /\/\*\s*ExcludeStart\s*\*\/[\w\W]*?\/\*\s*ExcludeEnd\s*\*\//ig, "" )91.replace( /\/\/\s*BuildExclude\n\r?[\w\W]*?\n\r?/ig, "" );9293// Remove empty definitions94contents = contents95.replace( /define\(\[[^\]]*\]\)[\W\n]+$/, "" );96}9798// AMD Name99if ( ( amdName = grunt.option( "amd" ) ) != null && /^exports\/amd$/.test( name ) ) {100101// Remove the comma for anonymous defines102contents = contents103.replace( new RegExp('/(\s*)"' + pkg.name + '"(\,\s*)/'),104amdName ? "$1\"" + amdName + "\"$2" : "" );105106}107return contents;108}109110grunt.registerMultiTask(111"build",112"Concatenate source, remove sub AMD definitions, " +113"(include/exclude modules with +/- flags), embed date/version",114function() {115var flag, index,116done = this.async(),117flags = this.flags,118name = grunt.option( "filename" ),119minimum = this.data.minimum,120removeWith = this.data.removeWith,121excluded = [],122included = [],123version = grunt.config( "pkg.version" ),124/**125* Recursively calls the excluder to remove on all modules in the list126* @param {Array} list127* @param {String} [prepend] Prepend this to the module name.128* Indicates we're walking a directory129*/130excludeList = function( list, prepend ) {131if ( list ) {132prepend = prepend ? prepend + "/" : "";133list.forEach( function( module ) {134135// Exclude var modules as well136if ( module === "var" ) {137excludeList(138fs.readdirSync( srcFolder + prepend + module ), prepend + module139);140return;141}142if ( prepend ) {143144// Skip if this is not a js file and we're walking files in a dir145if ( !( module = /([\w-\/]+)\.js$/.exec( module ) ) ) {146return;147}148149// Prepend folder name if passed150// Remove .js extension151module = prepend + module[ 1 ];152}153154// Avoid infinite recursion155if ( excluded.indexOf( module ) === -1 ) {156excluder( "-" + module );157}158} );159}160},161/**162* Adds the specified module to the excluded or included list, depending on the flag163* @param {String} flag A module path relative to164* the src directory starting with + or - to indicate165* whether it should included or excluded166*/167excluder = function( flag ) {168var m = /^(\+|\-|)([\w\/-]+)$/.exec( flag ),169exclude = m[ 1 ] === "-",170module = m[ 2 ];171172if ( exclude ) {173174// Can't exclude certain modules175if ( minimum.indexOf( module ) === -1 ) {176177// Add to excluded178if ( excluded.indexOf( module ) === -1 ) {179grunt.log.writeln( flag );180excluded.push( module );181182// Exclude all files in the folder of the same name183// These are the removable dependencies184// It's fine if the directory is not there185try {186excludeList( fs.readdirSync( srcFolder + module ), module );187} catch ( e ) {188grunt.verbose.writeln( e );189}190}191192// Check removeWith list193excludeList( removeWith[ module ] );194} else {195grunt.log.error( "Module \"" + module + "\" is a minimum requirement." );196if ( module === "selector" ) {197grunt.log.error(198"If you meant to replace Sizzle, use -sizzle instead."199);200}201}202} else {203grunt.log.writeln( flag );204included.push( module );205}206};207208// Filename can be passed to the command line using209// command line options210name = name ? ( "dist/" + name ) : this.data.dest;211212// append commit id to version213if ( process.env.COMMIT ) {214version += " " + process.env.COMMIT;215}216217// figure out which files to exclude based on these rules in this order:218// dependency explicit exclude219delete flags[ "*" ];220for ( flag in flags ) {221excluder( flag );222}223224grunt.verbose.writeflags( excluded, "Excluded" );225grunt.verbose.writeflags( included, "Included" );226227// append excluded modules to version228if ( excluded.length ) {229version += " -" + excluded.join( ",-" );230231// set pkg.version to version with excludes, so minified file picks it up232grunt.config.set( "pkg.version", version );233grunt.verbose.writeln( "Version changed to " + version );234235// Have to use shallow or core will get excluded since it is a dependency236config.excludeShallow = excluded;237}238config.include = included;239240/**241* Handle Final output from the optimizer242* @param {String} compiled243*/244config.out = function( compiled ) {245compiled = compiled246247// Embed Version248.replace( /@VERSION/g, version )249250// Embed Date251// yyyy-mm-ddThh:mmZ252.replace( /@DATE/g, ( new Date() ).toISOString().replace( /:\d+\.\d+Z$/, "Z" ) );253254// Write concatenated source to file255grunt.file.write( name, compiled );256};257258// Trace dependencies and concatenate files259requirejs.optimize( config, function( response ) {260grunt.verbose.writeln( response );261grunt.log.ok( "File '" + name + "' created." );262done();263}, function( err ) {264done( err );265} );266} );267};268269270