node-ff-assets ========= A Node.js library providing automatic site assets aggregation. ## Installation npm install node-ff-assets --save ## Example Application There is a fully working bootstrap with angularjs example in the example folder. ## Usage // note1: www_static/[js/css]/lib is version ignored. // note2: server routes; // app.use('/static', express.static(path.join(__dirname,'www_static'))); // app.use('/static/module/flot', express.static(path.join(__dirname,'node_modules/flot/dist'))); // app.use('/static/module/bootstrap', express.static(path.join(__dirname,'node_modules/bootstrap/dist'))); var assets = require('node-ff-assets'); var assetsConfig = { // Map from uri paths to file systems paths. linkMapping : { '/static/module/bootstrap/': 'node_modules/bootstrap/dist/', '/static/module/flot/': 'node_modules/flot/', '/static/': 'www_static/', }, // Site sources in html page. linkSourcesCss : [ '/static/module/bootstrap/css/bootstrap.css', ], linkSourcesJs : [ '/static/js/lib/jquery-2.1.3/jquery.js@http://code.jquery.com/jquery-2.1.3.js', '/static/module/bootstrap/js/bootstrap.js', '/static/module/flot/jquery.flot.js', '/static/module/flot/jquery.flot.resize.js', '/static/module/flot/jquery.flot.pie.js', '/static/js/lib/angularjs-1.4.0-b4/angular.js@https://code.angularjs.org/1.4.0-beta.4/angular.js', '/static/js/lib/angularjs-1.4.0-b4/angular-route.js@https://code.angularjs.org/1.4.0-beta.4/angular-route.js', '/static/js/lib/angularjs-1.4.0-b4/angular-resource.js@https://code.angularjs.org/1.4.0-beta.4/angular-resource.js', '/static/js/lib/angularjs-1.4.0-b4/angular-touch.js@https://code.angularjs.org/1.4.0-beta.4/angular-touch.js', ], }; // callback helper to return an assembler config per asset type function createBuildConfig(type) { return function(callback) { // Override rendered result from command line var singleResult = 'false' != process.env.DEV_ASSETS_SINGLE_RESULT; if (type == 'css') { callback(null,{ linkMapping: assetsConfig.linkMapping, linkTargetSingleResult: singleResult, linkTarget: '/static/css/lib/assets.css', linkSources: assetsConfig.linkSourcesCss, assetType: type, }); } else { callback(null, { linkTargetSingleResult: singleResult, linkMapping: assetsConfig.linkMapping, linkTarget: '/static/js/lib/assets.js', linkSources: assetsConfig.linkSourcesJs, assetType: type, }); } } } function buildAssets(server,callbackDone) { assets.build({ assets: { js: { configCreate: createBuildConfig('js'), configFill: function (config, callback) { async.series([ assets.factory.lib.async.pushLinkSources(config, '/static/js/', 'www_static/js/'), assets.factory.lib.async.pushLinkSources(config, '/static/js/controller/', 'www_static/js/controller/'), ],callback); }, }, css: { configCreate: createBuildConfig('css'), configFill: function (config, callback) { async.series([ assets.factory.lib.async.pushLinkSources(config, '/static/css/', 'www_static/css/'), ],callback); }, assemblerCreate: function (assemblerConfig, callback) { callback(null,new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileMinify())); }, }, }, assemblerFill: function (assembler, callback) { var serverResultKey = 'ff_assets_'+assembler.config.assetType; assembler.on ('log', assets.factory.assembler.event.log.console(assembler.config.assetType)); assembler.on ('result', assets.factory.assembler.event.result.objectSet(server,serverResultKey)); callback(); }, },callbackDone); } exports.build = function(server) { buildAssets(server,function(err) { if (err) { throw err; } console.log('Server init done.'); // init other stuff... }); } ## Config options The config option of the objects are filled from config templates with defaults. ### Builder Config Only configCreate if required to set in root and/or in asset. var template = { buildOrder: ['css','js'], configCreate: null, configFill: factory.builder.configCreate.nop(), assemblerCreate: factory.builder.assemblerCreate.readFile(), assemblerFill: factory.builder.configCreate.nop(), assets: { js: { configCreate: null, configFill: null, assemblerCreate: null, assemblerFill: null, }, css: { configCreate: null, configFill: null, assemblerCreate: null, assemblerFill: null, }, }, }; ### Assembler Config required: assetType,linkTarget,linkSources and linkMapping. var name = 'node-ff-assets'; var downloadTimeout = (1000*10) * 6; // 1min var downloadMaxSize = (1024*1024) * 10; // 10mb var template = { downloadStartDelay: null, downloadForce: false, downloadOptions: { timeout: downloadTimeout, maxResponseLength: downloadMaxSize, agent: name+' remote fetcher', }, linkTargetSingleResult: true, linkTarget: null, linkSources: [], linkMapping: [], assetType: null, assetHeader: '\n/* '+name+': begin */\n\n', assetFooter: '\n/* '+name+': end */\n\n', assetSeperator: '\n/* '+name+': next */\n', }; ### Assembler Download Force Sometimes its needed for have forces downloads of a resource. This can be done by adding an extra @ sign. linkSources: ['/static/js/lib/dynamic-generated.js@@http://localhost:8080/example-ui/include-js/generateModels']; note: if using localhost to download use the downloadStartDelay option so server is really up. The downloadForce option will redownload all resources of asset group. ## Target/Source locations The asset target file location is a derived value. Its created by mapping the assemblerConfig.linkTarget in the assemblerConfig.linkMapping keys to get a prefix for the local file system location. The same is also true for the assemblerConfig.linkSources list which are url paths which need to be mapped to the file system files by the assemblerConfig.linkMapping data. linkTarget: '/static/js/ffa/assets.js', linkMapping: ['/static/':'www_static/',], linkSources: ['/static/js/site.js','/static/js/ffa/jquery-2.1.3/jquery.js@http://code.jquery.com/jquery-2.1.3.js'], Result; public js file: http://localhost:8080/static/js/site.js public js file: http://localhost:8080/static/js/ffa/assets.js public js file: http://localhost:8080/static/js/ffa/jquery-2.1.3/jquery.js filesystem file: www_static/js/site.js filesystem file: www_static/js/ffa/assets.js filesystem file: www_static/js/ffa/jquery-2.1.3/jquery.js .gitignore line: www_static/js/ffa if buildConfig.linkTargetSingleResult = true then result static/js/ffa/assets.js else static/js/site.js static/js/ffa/jquery-2.1.3/jquery.js ## Objects For some use cases the assets.build(config,callback) is flexable enough. Then there are two objects which may provide the needed options. ### Object AssetsBuilder var assets = require('node-ff-assets'); var builderConfig = {...}; // Create builder var assetsBuilderA = new assets.AssetsBuilder(builderConfig); // Run all assetsBuilderB.runAll(function(err) { //done }); // Run singles async.series([ assetsBuilderC.runAsset('css'), assetsBuilderD.runAsset('js'), ],function(err) { //done }); ### Object AssetAssembler var assets = require('node-ff-assets'); var assemblerConfig = {...}; // Create default assembler. var assetAssemblerA = new assets.AssetAssembler(assemblerConfig); // Same as default, plain inclusion of content. var assetAssemblerB = new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFile()); // Minify content, with optional Minify config options. var assetAssemblerC = new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileMinify()); var assetAssemblerD = new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileMinify(minifyOptions)); // Third party content modifiers, with readFile function var assetAssemblerE = new assets.AssetAssembler(buildConfig,function(file,callback) { // should return file data to callback(err,data); ); // Registrate events (note: may change a bit) assetAssemblerA.on('begin', function() { }); assetAssemblerA.on('end', function() { }); assetAssemblerA.on('log', function(logLevel, logMessage) { }); assetAssemblerA.on('error', function(err) { }); assetAssemblerA.on('result', function(resultValue) { }); assetAssemblerA.on('file-download-pre', function(remoteUrl) { }); assetAssemblerA.on('file-download-post', function(localFile) { }); assetAssemblerA.on('file-read-pre', function(localFile) { }); assetAssemblerA.on('file-read-post', function(localFile) { }); assetAssemblerA.on('file-write-pre', function(targetFile) { }); assetAssemblerA.on('file-write-post', function(targetFile) { }); // Use build in event functions assetAssemblerB.on('log', assets.factory.assembler.event.log.console('css')); assetAssemblerB.on('result', assets.factory.assembler.event.result.objectSet(server,'includeCssFiles')); // Run builder assetAssemblerC.run(function(err) { //done }); ## Rendering In these examples I use the server (app/express) object to store the results in for displaying. Which the index page renderer will get and inject in page context. function renderIndex(app) { return function (req, res, next) { res.render('index', { includeCssFiles: server.get('ff_assets_css'), includeJsFiles: server.get('ff_assets_js'), }); } }; app.get('/',renderIndex(app)); // Template index.jade doctype html html(lang='en',ng-app='ffUI') head base(href='/ui') title='Index' meta(charset='UTF-8') meta(http-equiv='X-UA-Compatible' content='IE=edge') meta(name='viewport' content='width=device-width, initial-scale=1') meta(name='keywords' content='keywords') each cssFile in includeCssFiles link(rel='stylesheet' href='#{cssFile}') body div(id='wrapper') div(ng-include='\'/ui/include/html/layout/header\'') div(id='page-wrapper') div(id='container-fluid') div(ng-view) div(ng-include='\'/ui/include/html/layout/footer\'') each jsFile in includeJsFiles script(src='#{jsFile}') ## Example log output // Result First run info: node-ff-assets-css build begin for: /static/css/lib/assets.css debug: node-ff-assets-css readFile: node_modules/bootstrap/dist/css/bootstrap.css size: 285496 debug: node-ff-assets-css readFile: www_static/css/boot.css size: 1606 debug: node-ff-assets-css readFile: www_static/css/flot.css size: 82 debug: node-ff-assets-css readFile: www_static/css/panel.css size: 545 debug: node-ff-assets-css readFile: www_static/css/style.css size: 10419 debug: node-ff-assets-css target size: 298318 info: node-ff-assets-css build result size: 1 from: 5 info: node-ff-assets-css build done in: 33 ms. info: node-ff-assets-js build begin for: /static/js/lib/assets.js debug: node-ff-assets-js downloadFile: http://code.jquery.com/jquery-2.1.3.js debug: node-ff-assets-js downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular.js debug: node-ff-assets-js downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular-route.js debug: node-ff-assets-js downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular-resource.js debug: node-ff-assets-js downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular-touch.js debug: node-ff-assets-js downloadFile: http://localhost:8008/ui/include/js/controller/test1 GET /ui/include/js/controller/test1 200 7.931 ms - - debug: node-ff-assets-js downloadFile: http://localhost:8008/ui/include/js/controller/test2 GET /ui/include/js/controller/test2 200 5.215 ms - - debug: node-ff-assets-js downloadFile: http://localhost:8008/ui/include/js/controller/test3 GET /ui/include/js/controller/test3 200 1.583 ms - - debug: node-ff-assets-js readFile: www_static/js/lib/jquery-2.1.3/jquery.js size: 247387 debug: node-ff-assets-js readFile: node_modules/bootstrap/dist/js/bootstrap.js size: 66732 debug: node-ff-assets-js readFile: node_modules/flot/jquery.flot.js size: 110008 debug: node-ff-assets-js readFile: node_modules/flot/jquery.flot.resize.js size: 2504 debug: node-ff-assets-js readFile: node_modules/flot/jquery.flot.pie.js size: 23405 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular.js size: 988198 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-route.js size: 35796 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-resource.js size: 26780 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-touch.js size: 22887 debug: node-ff-assets-js readFile: www_static/js/app-directives.js size: 185 debug: node-ff-assets-js readFile: www_static/js/app-filters.js size: 202 debug: node-ff-assets-js readFile: www_static/js/app-services.js size: 80 debug: node-ff-assets-js readFile: www_static/js/app.js size: 766 debug: node-ff-assets-js readFile: www_static/js/controller/page-about.js size: 364 debug: node-ff-assets-js readFile: www_static/js/controller/page-foobar.js size: 361 debug: node-ff-assets-js readFile: www_static/js/controller/page-index.js size: 351 debug: node-ff-assets-js readFile: www_static/js/controller/page-help.js size: 376 debug: node-ff-assets-js readFile: www_static/js/lib/xcrud/test1.js size: 2010 debug: node-ff-assets-js readFile: www_static/js/lib/xcrud/test2.js size: 2138 debug: node-ff-assets-js readFile: www_static/js/lib/xcrud/test3.js size: 2218 debug: node-ff-assets-js target size: 1540945 info: node-ff-assets-js build result size: 1 from: 24 info: node-ff-assets-js build done in: 3497 ms. info: Server init done. // Result Next runs info: node-ff-assets-css build begin for: /static/css/lib/assets.css debug: node-ff-assets-css readFile: node_modules/bootstrap/dist/css/bootstrap.css size: 285496 debug: node-ff-assets-css readFile: www_static/css/boot.css size: 1606 debug: node-ff-assets-css readFile: www_static/css/flot.css size: 82 debug: node-ff-assets-css readFile: www_static/css/panel.css size: 545 debug: node-ff-assets-css readFile: www_static/css/style.css size: 10419 debug: node-ff-assets-css target size: 298318 info: node-ff-assets-css build result size: 1 from: 5 info: node-ff-assets-css build done in: 36 ms. info: node-ff-assets-js build begin for: /static/js/lib/assets.js debug: node-ff-assets-js downloadFile: http://localhost:8008/ui/include/js/controller/test1 GET /ui/include/js/controller/test1 200 7.931 ms - - debug: node-ff-assets-js downloadFile: http://localhost:8008/ui/include/js/controller/test2 GET /ui/include/js/controller/test2 200 5.215 ms - - debug: node-ff-assets-js downloadFile: http://localhost:8008/ui/include/js/controller/test3 GET /ui/include/js/controller/test3 200 1.583 ms - - debug: node-ff-assets-js readFile: www_static/js/lib/jquery-2.1.3/jquery.js size: 247387 debug: node-ff-assets-js readFile: node_modules/bootstrap/dist/js/bootstrap.js size: 66732 debug: node-ff-assets-js readFile: node_modules/flot/jquery.flot.js size: 110008 debug: node-ff-assets-js readFile: node_modules/flot/jquery.flot.resize.js size: 2504 debug: node-ff-assets-js readFile: node_modules/flot/jquery.flot.pie.js size: 23405 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular.js size: 988198 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-route.js size: 35796 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-resource.js size: 26780 debug: node-ff-assets-js readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-touch.js size: 22887 debug: node-ff-assets-js readFile: www_static/js/app-directives.js size: 185 debug: node-ff-assets-js readFile: www_static/js/app-filters.js size: 202 debug: node-ff-assets-js readFile: www_static/js/app-services.js size: 80 debug: node-ff-assets-js readFile: www_static/js/app.js size: 766 debug: node-ff-assets-js readFile: www_static/js/controller/page-about.js size: 364 debug: node-ff-assets-js readFile: www_static/js/controller/page-foobar.js size: 361 debug: node-ff-assets-js readFile: www_static/js/controller/page-index.js size: 351 debug: node-ff-assets-js readFile: www_static/js/controller/page-help.js size: 376 debug: node-ff-assets-js readFile: www_static/js/lib/xcrud/test1.js size: 2010 debug: node-ff-assets-js readFile: www_static/js/lib/xcrud/test2.js size: 2138 debug: node-ff-assets-js readFile: www_static/js/lib/xcrud/test3.js size: 2218 debug: node-ff-assets-js target size: 1540945 info: node-ff-assets-js build result size: 1 from: 24 info: node-ff-assets-js build done in: 105 ms. info: Server init done. ## Tests npm test ## Contributing In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code. ## Release History ### 0.2.1 * Added example application * Fixed buid callback * Fixed buildOrder default * Updated doc ### 0.2.0 * Redone objs * Added tests * Made jslint pass ### 0.1.x * Added objectAdd * Doc updates * Initial release