From 4b4a4cd8d385989529ca35719d2e3317197f0e2a Mon Sep 17 00:00:00 2001 From: Ghislain Seguin Date: Thu, 10 Apr 2014 11:23:19 -0600 Subject: [PATCH] Decoupled buildCSSBundles to css.buildBundles --- lib/css.js | 194 ++++++++++++++++++++++++++++++++++++++++++++ lib/dependencies.js | 8 +- lib/filter.js | 13 +++ server.js | 194 ++------------------------------------------ 4 files changed, 216 insertions(+), 193 deletions(-) create mode 100644 lib/css.js create mode 100644 lib/filter.js diff --git a/lib/css.js b/lib/css.js new file mode 100644 index 0000000..195ebda --- /dev/null +++ b/lib/css.js @@ -0,0 +1,194 @@ +"use strict"; + +var _ = require( 'underscore' ), + applyFilter = require( './filter' ).apply, + async = require( "async" ), + cssConcat = require( 'css-concat' ), + dependencies = require( "./dependencies" ), + fs = require( "fs" ), + logger = require( 'simple-log' ).init( 'amd-builder:css' ), + path = require( 'path' ), + Promise = require( "node-promise" ).Promise, + requirejs = require( 'requirejs' ), + redefineRequireJSLogging = require( "./requirejs-utils" ).redefineRequireJSLogging; + + +function buildBundles( baseName, workspaceDir, relBaseUrl, compiledDir, files, filter, optimize ) { + // logger.log( "buildCSSBundle()" ); + var promise = new Promise(), + baseOut = path.join( compiledDir, baseName ); + + // get the dependency map for all modules + dependencies.buildMap( workspaceDir, relBaseUrl, compiledDir, files ).then( + function( modules ) { + var absBaseUrl = path.normalize( path.join( workspaceDir, relBaseUrl ) ); + var cssFiles = { + default: [] + }, + contents = { + default: "" + }, + outputFiles = []; + + async.waterfall([ + function( next ) { + var name, + processed = {}, + addCssDependencies = function( m ) { + processed[ m ] = true; + if ( !processed[ m ] && modules[ m ] && modules[ m ].deps ) { + modules[ m ].deps.forEach( addCssDependencies ); + } + if ( modules[ m ] && modules[ m ].css ) { + if ( typeof( modules[ m ].css ) === "string" ) { + // logger.log( "Adding: " + modules[ m ].css ); + cssFiles.default = _.union( cssFiles.default, modules[ m ].css.split( "," ) ); + } else { + for ( name in modules[ m ].css ) { + if ( modules[ m ].css.hasOwnProperty( name ) ) { + cssFiles[ name ] = cssFiles[ name ] || []; + // logger.log( "Adding css." + name + ": " + modules[ m ].css[ name ]); + cssFiles[ name ] = _.union( cssFiles[ name ], modules[ m ].css[ name ].split( "," ) ); + } + } + } + } + }; + + files.forEach( addCssDependencies ); + next(); + }, + function( next ) { + var keys = Object.keys( cssFiles ); + + keys.forEach( function( name ) { + if ( cssFiles.hasOwnProperty( name ) ) { + // resolve the file paths + cssFiles[ name ] = _.uniq( cssFiles[ name ]).map( function( s ) { + return path.resolve( absBaseUrl, s.trim() ); + }); + + contents[ name ] = ""; + cssFiles[ name ].forEach( function( file ) { + contents[ name ] += "\n"; + try { + contents[ name ] += cssConcat.concat( file, { comments: false }); + } catch ( e ) { + next( e.toString() ); + } + }); + contents[ name ] = contents[ name ].trim(); + if ( contents[ name ].length === 0 ) { + if ( optimize ) { + logger.log( name, "CSS file is empty, removing it from optimized bundle" ); + } else { + logger.log( name, "CSS file is empty, removing it from bundle" ); + } + delete contents[ name ]; + delete cssFiles[ name ]; + } + } + }); + next(); + }, + function( next ) { + async.forEach( + Object.keys( contents ), + function( key, callback ) { + var unoptimizedOut = baseOut + ( key === "default" ? "" : ( "." + key ) ) + ".css"; + + async.waterfall([ + function( step ) { + applyFilter( absBaseUrl, filter, contents[ key ], ".css", step ); + }, + function( content, step ) { + fs.writeFile( unoptimizedOut, content, 'utf8', step ); + }, + function( step ) { + if ( !optimize ) { + outputFiles.push( unoptimizedOut ); + } + step(); + } + ], callback ); + + }, + next + ); + }, + function( next ) { + async.forEach( + Object.keys( contents ), + function( key, callback ) { + var unoptimizedOut = baseOut + ( key === "default" ? "" : ( "." + key ) ) + ".css", + optimizedOut = baseOut + ( key === "default" ? "" : ( "." + key ) ) + ".min.css"; + + try { + process.chdir( workspaceDir ); + } + catch ( e1 ) { + next( e1.toString() ); + } + + redefineRequireJSLogging(); + + try { + requirejs.optimize( + { + cssIn: unoptimizedOut, + out: optimizedOut, + optimizeCss: "standard", + logLevel: 4 // SILENT + }, + function( response ) { + async.waterfall([ + function( step ) { + fs.readFile( optimizedOut, "utf-8", step ); + }, + function( content, step ) { + applyFilter( absBaseUrl, filter, content, ".min.css", step ); + }, + function( content, step ) { + fs.writeFile( optimizedOut, content, 'utf8', step ); + }, + function( step ) { + if ( optimize ) { + outputFiles.push( optimizedOut ); + } + step(); + } + ], callback ); + }, + function( err ) { + // We're expecting a string as the error. + next( err.message ); + } + ); + } catch ( e2 ) { + next( e2.toString() ); + } + }, + next + ); + } + ], function( err ) { + if ( err ) { + logger.error( err ); + promise.reject( err ); + } else { + if ( outputFiles.length === 0 || outputFiles.length > 1 ) { + promise.resolve( outputFiles ); + } else { + promise.resolve( outputFiles[ 0 ]); + } + } + }); + }, + function( err ) { + promise.reject( err ); + } + ); + return promise; +} + +exports.buildBundles = buildBundles; \ No newline at end of file diff --git a/lib/dependencies.js b/lib/dependencies.js index 4427bf5..904d001 100644 --- a/lib/dependencies.js +++ b/lib/dependencies.js @@ -25,7 +25,7 @@ function getFiles( dir, pattern, mapFn, callback ) { ], callback); }; -function buildMap( workspaceDir, compileDir, baseUrl, include ) { +function buildMap( workspaceDir, baseUrl, compiledDir, include ) { var id = bid++; // logger.log( "buildMap["+id+"]()" ); var promise = new Promise(), @@ -40,7 +40,7 @@ function buildMap( workspaceDir, compileDir, baseUrl, include ) { // logger.log( "buildMap["+id+"](): step 1" ); // If no name is provided, scan the baseUrl for js files and return the dep map for all JS objects in baseUrl if ( include && include.length > 0 ) { - next(); + next( null, null ); } else { getFiles( baseUrl, @@ -60,7 +60,7 @@ function buildMap( workspaceDir, compileDir, baseUrl, include ) { // Generate a sha on the sorted names var digest = shasum.update( include.join( "," ) ).digest( "hex" ); - filename += path.join( compileDir, "deps-" + digest + ".json" ); + filename += path.join( compiledDir, "deps-" + digest + ".json" ); fs.exists( filename, function( exists ) { next( null, digest, exists ) @@ -82,7 +82,7 @@ function buildMap( workspaceDir, compileDir, baseUrl, include ) { async.waterfall([ function( cb ) { // logger.log( "buildMap["+id+"](): step 3.1" ); - fs.mkdir( compileDir, function( err ) { + fs.mkdir( compiledDir, function( err ) { if ( err && err.code != "EEXIST" ) { cb( err ); } else { diff --git a/lib/filter.js b/lib/filter.js new file mode 100644 index 0000000..7217a01 --- /dev/null +++ b/lib/filter.js @@ -0,0 +1,13 @@ +"use strict"; + +var path = require( "path" ); + +function apply( baseUrl, filter, contents, ext, callback ) { + if ( filter ) { + require( path.join( baseUrl, filter ) )( contents, ext, callback ); + } else { + callback( null, contents ); + } +} + +exports.apply = apply; \ No newline at end of file diff --git a/server.js b/server.js index bcdb55d..f348fe0 100644 --- a/server.js +++ b/server.js @@ -3,9 +3,10 @@ var _ = require( 'underscore' ), express = require( 'express' ), app = express(), + applyFilter = require( './lib/filter' ).apply, async = require( 'async' ), crypto = require( 'crypto' ), - cssConcat = require( 'css-concat' ), + css = require( './lib/css' ), dependencies = require( "./lib/dependencies" ), fetch = require( './lib/project' ).fetch, fs = require( 'fs' ), @@ -14,11 +15,8 @@ var _ = require( 'underscore' ), path = require( 'path' ), promiseUtils = require( 'node-promise' ), Promise = require( 'node-promise' ).Promise, - when = require( 'node-promise' ).when, - regexp = require( './lib/regexp' ), requirejs = require( 'requirejs' ), semver = require( 'semver' ), - url = require( 'url' ), zip = require( "node-native-zip" ); var argv = require( 'optimist' ) @@ -201,8 +199,8 @@ function buildDependencyMap( project, baseUrl, include ) { } else { dependencies.buildMap( project.getWorkspaceDirSync(), - project.getCompiledDirSync(), baseUrl, + project.getCompiledDirSync(), include ).then( promise.resolve, @@ -213,190 +211,8 @@ function buildDependencyMap( project, baseUrl, include ) { return promise; } -function applyFilter( baseUrl, filter, contents, ext, callback ) { - if ( filter ) { - require( path.join( baseUrl, filter ) )( contents, ext, callback ); - } else { - callback( null, contents ); - } -} - -function buildCSSBundles( project, config, name, filter, optimize ) { - // logger.log( "buildCSSBundle()" ); - var promise = new Promise(), - baseUrl = path.normalize( path.join( project.getWorkspaceDirSync(), config.baseUrl ) ), - include = config.include, - baseOut = path.join( project.getCompiledDirSync(), name ); - - // get the dependency map for all modules - buildDependencyMap( project, config.baseUrl ).then( - function( modules ) { - var cssFiles = { - default: [] - }, - contents = { - default: "" - }, - outputFiles = []; - - async.waterfall([ - function( next ) { - var name, - processed = {}, - addCssDependencies = function( m ) { - processed[ m ] = true; - if ( !processed[ m ] && modules[ m ] && modules[ m ].deps ) { - modules[ m ].deps.forEach( addCssDependencies ); - } - if ( modules[ m ] && modules[ m ].css ) { - if ( typeof( modules[ m ].css ) === "string" ) { - // logger.log( "Adding: " + modules[ m ].css ); - cssFiles.default = _.union( cssFiles.default, modules[ m ].css.split( "," ) ); - } else { - for ( name in modules[ m ].css ) { - if ( modules[ m ].css.hasOwnProperty( name ) ) { - cssFiles[ name ] = cssFiles[ name ] || []; - // logger.log( "Adding css." + name + ": " + modules[ m ].css[ name ]); - cssFiles[ name ] = _.union( cssFiles[ name ], modules[ m ].css[ name ].split( "," ) ); - } - } - } - } - }; - - include.forEach( addCssDependencies ); - next(); - }, - function( next ) { - var keys = Object.keys( cssFiles ); - - keys.forEach( function( name ) { - if ( cssFiles.hasOwnProperty( name ) ) { - // resolve the file paths - cssFiles[ name ] = _.uniq( cssFiles[ name ]).map( function( s ) { - return path.resolve( baseUrl, s.trim() ); - }); - - contents[ name ] = ""; - cssFiles[ name ].forEach( function( file ) { - contents[ name ] += "\n"; - try { - contents[ name ] += cssConcat.concat( file, { comments: false }); - } catch ( e ) { - next( e.toString() ); - } - }); - contents[ name ] = contents[ name ].trim(); - if ( contents[ name ].length === 0 ) { - if ( optimize ) { - logger.log( name, "CSS file is empty, removing it from optimized bundle" ); - } else { - logger.log( name, "CSS file is empty, removing it from bundle" ); - } - delete contents[ name ]; - delete cssFiles[ name ]; - } - } - }); - next(); - }, - function( next ) { - async.forEach( - Object.keys( contents ), - function( key, callback ) { - var unoptimizedOut = baseOut + ( key === "default" ? "" : ( "." + key ) ) + ".css"; - - async.waterfall([ - function( step ) { - applyFilter( baseUrl, filter, contents[ key ], ".css", step ); - }, - function( content, step ) { - fs.writeFile( unoptimizedOut, content, 'utf8', step ); - }, - function( step ) { - if ( !optimize ) { - outputFiles.push( unoptimizedOut ); - } - step(); - } - ], callback ); - - }, - next - ); - }, - function( next ) { - async.forEach( - Object.keys( contents ), - function( key, callback ) { - var unoptimizedOut = baseOut + ( key === "default" ? "" : ( "." + key ) ) + ".css", - optimizedOut = baseOut + ( key === "default" ? "" : ( "." + key ) ) + ".min.css"; - - try { - process.chdir( project.getWorkspaceDirSync() ); - } - catch ( e1 ) { - next( e1.toString() ); - } - - redefineRequireJSLogging(); - - try { - requirejs.optimize( - { - cssIn: unoptimizedOut, - out: optimizedOut, - optimizeCss: "standard", - logLevel: 4 // SILENT - }, - function( response ) { - async.waterfall([ - function( step ) { - fs.readFile( optimizedOut, "utf-8", step ); - }, - function( content, step ) { - applyFilter( baseUrl, filter, content, ".min.css", step ); - }, - function( content, step ) { - fs.writeFile( optimizedOut, content, 'utf8', step ); - }, - function( step ) { - if ( optimize ) { - outputFiles.push( optimizedOut ); - } - step(); - } - ], callback ); - }, - function( err ) { - // We're expecting a string as the error. - next( err.message ); - } - ); - } catch ( e2 ) { - next( e2.toString() ); - } - }, - next - ); - } - ], function( err ) { - if ( err ) { - promise.reject( err ); - } else { - if ( outputFiles.length === 0 || outputFiles.length > 1 ) { - promise.resolve( outputFiles ); - } else { - promise.resolve( outputFiles[ 0 ]); - } - } - }); - }, - function( err ) { - promise.reject( err ); - } - ); - return promise; +function buildCSSBundles( project, config, baseName, filter, optimize ) { + return css.buildBundles( baseName, project.getWorkspaceDirSync(), config.baseUrl, project.getCompiledDirSync(), config.include, filter, optimize ); } var bjsid = 0;