node-ff-assets ========= A Node.js library providing automatic site assets aggregation and content modifiers. ## Installation npm install node-ff-assets --save ## Target/Source locations The asset target file location is a derived value. Its created by mapping the buildConfig.linkTarget in the buildConfig.linkMapping keys to get a prefix for the local file system location. The same is also true for the buildConfig.linkSources list which are url paths which need to be mapped to the file system files by the buildConfig.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'], Gives; 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 render static/js/ffa/assets.js else static/js/site.js static/js/ffa/jquery-2.1.3/jquery.js ## Usage // Create config object var buildConfig = { downloadStartDelay: null, downloadForce: false, downloadOptions: { timeout: 10000, maxResponseLength: 10000000, agent: 'node-ff-assets asset fetcher' }, linkTargetSingleResult: true, linkTarget: '/static-uri/js/assets.js', linkSources: [ '/static/js/lib/jquery-2.1.3/jquery.js@http://code.jquery.com/jquery-2.1.3.js', '/static/js/lib/foobar/dyna.js@@http://localhost/force-download-on-every-build-for-this-file.js', '/static/js/site.js' ], linkMapping: ['/static-uri/':'www_static/',], assetHeader: '\n/* node-ff-assets: begin */\n\n', assetFooter: '\n/* node-ff-assets: end */\n\n', assetSeperator: '\n/* node-ff-assets: next */\n', } // Development override, targets still gets build but result is full list of assets. buildConfig.linkTargetSingleResult = false; // Push local js/css files as uri sources into config NodeFFAssets.pushLinkSourcesSync(buildConfig, '/static-uri/js/', 'www_public/js/'); NodeFFAssets.pushLinkSourcesSync(buildConfig, '/static-uri/js/model/', 'www_public/js/model/'); NodeFFAssets.pushLinkSourcesSync(buildConfig, '/static-uri/js/model/meta', 'www_public/js/model/meta'); // Require library var NodeFFAssets = require('node-ff-assets'); // Create simpel builder var assetBuilderA = new NodeFFAssets.ResourceBuilder(buildConfig); // Same as default, plain inclusion of content. var assetBuilderB = new NodeFFAssets.ResourceBuilder(buildConfig,NodeFFAssets.FunctionFactory.Constructor.readFile()); // Minify content, with optional Minify config options. var assetBuilderC = new NodeFFAssets.ResourceBuilder(buildConfig,NodeFFAssets.FunctionFactory.Constructor.readFileMinify()); var assetBuilderD = new NodeFFAssets.ResourceBuilder(buildConfig,NodeFFAssets.FunctionFactory.Constructor.readFileMinify(minifyOptions)); // Third party content modifiers, with readFile function var assetBuilderE = new NodeFFAssets.ResourceBuilder(buildConfig,function(file,callback) { // should return file data to callback(err,data); ); // Hook events assetBuilderA.on('begin', function() { }); assetBuilderA.on('end', function() { }); assetBuilderA.on('log', function(logLevel, logMessage) { }); assetBuilderA.on('error', function(err) { }); assetBuilderA.on('result', function(resultValue) { }); assetBuilderA.on('file-download-pre', function(remoteUrl) { }); assetBuilderA.on('file-download-post', function(localFile) { }); assetBuilderA.on('file-read-pre', function(localFile) { }); assetBuilderA.on('file-read-post', function(localFile) { }); assetBuilderA.on('file-write-pre', function(targetFile) { }); assetBuilderA.on('file-write-post', function(targetFile) { }); // Use build in event functions assetBuilderB.on('log', NodeFFAssets.FunctionFactory.Event.log.console('css')); assetBuilderB.on('result', NodeFFAssets.FunctionFactory.Event.result.objectSet(server,'includeCssFiles')); // Run builder assetBuilderC.run(function(err) { //done }); // Run all builders NodeFFAssets.runAll([ assetBuilderA, assetBuilderB, assetBuilderC, ], function(err) { // all done }); // Render result function renderIndex(app) { return function (req, res, next) { res.render('index', { includeCssFiles: app.get('includeCssFiles'), includeJsFiles: app.get('includeJsFiles'), }); } }; app.get('/',renderIndex(app)); // Template index.jade doctype html html(lang='en',ng-app='ffUI') head base(href='/ui') title=title 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 mapping node_modules Some js libraries can be directly served from node_packages and thus also be included the node-ff-assets output, but these required there own reverse mapping; '/static/module/bootstrap/': 'node_modules/bootstrap/dist/', This will let the parse find the /static/module/bootstrap/css/bootstrap.css resource and maps it the local file; node_modules/bootstrap/dist/css/bootstrap.css // note1: www_static/[js/css]/lib is versioned ingored. // note2: server routes; // app.use('/static',express.static(path.join(__dirname,'www_static'))); // app.use('/static/module/bootstrap',express.static(path.join(__dirname,'node_modules/bootstrap/dist'))); var NodeFFAssets = require('node-ff-assets'); var buildCss = new NodeFFAssets.ResourceBuilder({ linkMapping: { '/static/module/bootstrap/': 'node_modules/bootstrap/dist/', '/static/': 'www_static/', }, linkTarget: '/static/css/lib/assets.css', linkSources: [ '/static/module/bootstrap/css/bootstrap.css', '/static/css/site.css', ], }); buildCss.on('log', NodeFFAssets.FunctionFactory.Event.log.console('css')); buildCss.on('result', NodeFFAssets.FunctionFactory.Event.result.objectSet(server,'includeCssFiles')); buildCss.run(function(err) { // done }) // Render result as in usage example. ## Example complex var LogWinston = require('winston'); var Log = LogWinston.loggers.get('main'); var Mongoose = require('mongoose'); var NodeFFAssets = require('node-ff-assets'); function createBuildConfig(type) { var singleResult = 'false' != process.env.DEV_ASSETS_SINGLE_RESULT; var linkMapping = { '/static/module/bootstrap/': 'node_modules/bootstrap/dist/', '/static/module/flot/': 'node_modules/flot/', '/static/': 'www_static/', } if (type == 'css') { return { linkMapping: linkMapping, linkTargetSingleResult: singleResult, linkTarget: '/static/css/lib/assets.css', linkSources: [ '/static/module/bootstrap/css/bootstrap.css', ], }; } else { return { downloadStartDelay: 200, linkTargetSingleResult: singleResult, linkMapping: linkMapping, linkTarget: '/static/js/lib/assets.js', linkSources: [ '/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', ], }; } } function createBuildLogger(logType) { return function(logLevel, logMessage) { Log.log(logLevel, 'node-ff-assets-'+logType+' '+logMessage); } }; function buildAssets(server,callback) { // Create asset config var buildJsConfig = createBuildConfig('js'); var buildCssConfig = createBuildConfig('css'); // Extends js/css lists with local folders NodeFFAssets.pushLinkSourcesSync(buildJsConfig, '/static/js/', 'www_static/js/'); NodeFFAssets.pushLinkSourcesSync(buildJsConfig, '/static/js/controller/', 'www_static/js/controller/'); NodeFFAssets.pushLinkSourcesSync(buildCssConfig, '/static/css/', 'www_static/css/'); // Extend js list with crud entries var localPort = server.get('server config').options.http.port; var modelNames = Mongoose.connection.modelNames(); for (i = 0; i < modelNames.length; i++) { var modelName = modelNames[i]; var assetLink = '/static/js/lib/xcrud/'+modelName+'.js@@http://localhost:'+localPort+'/ui/include/js/controller/'+modelName; buildJsConfig.linkSources.push(assetLink); } // Create builders var buildJs = new NodeFFAssets.ResourceBuilder(buildJsConfig); // note: Minify fails here on some js. var buildCss = new NodeFFAssets.ResourceBuilder(buildCssConfig,NodeFFAssets.FunctionFactory.Constructor.readFileMinify()); // Config build events buildJs.on ('log', createBuildLogger('js')); buildCss.on('log', createBuildLogger('css')); buildJs.on ('result', NodeFFAssets.FunctionFactory.Event.result.objectSet(server,'includeJsFiles')); buildCss.on('result', NodeFFAssets.FunctionFactory.Event.result.objectSet(server,'includeCssFiles')); // Run builders NodeFFAssets.runAll([buildCss,buildJs],callback); } exports.build = function(server) { buildAssets(server,function() { Log.info('Server init done.'); }); } // 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 (TODO) ## 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.1.2 added objectAdd * 0.1.1 Doc updates * 0.1.0 Initial release