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 express example application in the example folder. This contains bootstrap and angularjs and ejs templates and results in single html/js/css file. ## Usage note: www_static/[js/css]/lib are scm version ignored. ### example-assets.json { "linkMapping" : { "/static/module/bootstrap/": "node_modules/bootstrap/dist/", "/static/module/flot/": "node_modules/flot/", "/static/": "www_static/" }, "css": { "linkTarget": "/static/css/lib/assets.css", "linkSources": [ "/static/module/bootstrap/css/bootstrap.css" ] }, "js": { "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" ] } } ### example.js var express = require('express'); var async = require('async'); var path = require('path'); var assets = require('node-ff-assets'); function buildAssets(server,callbackDone) { var singleResult = 'false' !== process.env.DEV_ASSETS_SINGLE_RESULT; var assetsConfig = require('./example-assets.json'); assets.build({ assets: { js: { configCreate: assets.factory.builder.configCreate.fromJSON(assetsConfig,'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: assets.factory.builder.configCreate.fromJSON(assetsConfig,'css'), configFill: function (config, callback) { async.series([ assets.factory.lib.async.pushLinkSources(config, '/static/css/', 'www_static/css/'), ],callback); }, }, }, assemblerCreate: assets.factory.builder.assemblerCreate.readFileRegex(), 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)); assembler.config.linkTargetSingleResult = singleResult; callback(); }, },callbackDone); } function renderPage(server) { return function (req, res) { res.render('index', { pageTitle: 'node-ff-assets example', pageKeywords: 'node,ff,assets,example,ui', pageCssFiles: server.get('ff_assets_css'), pageJsFiles: server.get('ff_assets_js'), }); }; } var server = express(); buildAssets(server,function(err) { if (err) { throw err; } console.info('Server assets done.'); server.get('/example-ui',renderPage(server)); ...snip.. config rest of server }); ### index.ejs <%= pageTitle %> <% if (pageCssFiles.length) { %><% pageCssFiles.forEach(function (cssFile) { %><% }) %><% } %>
<% if (pageJsFiles.length) { %><% pageJsFiles.forEach(function (jsFile) { %><% }) %><% } %> ## 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: '/* '+name+': Auto generated. */\n', assetFooter: '/* '+name+': end */\n', assetSeperator: '\n/* '+name+': <%= file %> */\n\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 and start server before building. 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()); // Filter content based on regexes var assetAssemblerF = new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileRegex()); var assetAssemblerH = new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileRegex(regexData)); // 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(logMessage) { }); 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 }); ## Example log output First run with downloads and with DEBUG="*" ff:assets:assets-builder runAll started. +0ms ff:assets:assets-builder runAsset started for: css +1ms ff:assets:assets-builder runAsset started for: js +0ms ff:assets:assets-builder assemblerCreate from default +2ms ff:assets:assets-builder assemblerFill from default +0ms ff:assets:assets-builder runAssembler type: css +0ms node-ff-assets:css build begin for: /static/css/lib/assets.css ff:assets:asset-assembler downloadList size: 0 +4ms ff:assets:asset-assembler readFileList size: 5 +1ms ff:assets:asset-assembler readFile: node_modules/bootstrap/dist/css/bootstrap.css size: 129940 +4ms ff:assets:asset-assembler readFile: www_static/css/boot.css size: 1824 +1ms ff:assets:asset-assembler readFile: www_static/css/flot.css size: 94 +0ms ff:assets:asset-assembler readFile: www_static/css/panel.css size: 605 +1ms ff:assets:asset-assembler readFile: www_static/css/style.css size: 448 +0ms ff:assets:asset-assembler target file: www_static/css/lib/assets.css +0ms ff:assets:asset-assembler target size: 133244 +0ms node-ff-assets:css build result size: 1 from: 5 node-ff-assets:css build done in: 10 ms. ff:assets:assets-builder assemblerCreate from default +1ms ff:assets:assets-builder assemblerFill from default +0ms ff:assets:assets-builder runAssembler type: js +0ms node-ff-assets:js build begin for: /static/js/lib/assets.js ff:assets:asset-assembler downloadList size: 5 +1ms ff:assets:asset-assembler readFileList size: 13 +0ms ff:assets:asset-assembler downloadFile: http://code.jquery.com/jquery-2.1.3.js +0ms ff:assets:asset-assembler downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular.js +90ms ff:assets:asset-assembler downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular-route.js +2s ff:assets:asset-assembler downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular-resource.js +579ms ff:assets:asset-assembler downloadFile: https://code.angularjs.org/1.4.0-beta.4/angular-touch.js +567ms ff:assets:asset-assembler readFile: www_static/js/lib/jquery-2.1.3/jquery.js size: 151917 +593ms ff:assets:asset-assembler readFile: node_modules/bootstrap/dist/js/bootstrap.js size: 49199 +4ms ff:assets:asset-assembler readFile: node_modules/flot/jquery.flot.js size: 54509 +7ms ff:assets:asset-assembler readFile: node_modules/flot/jquery.flot.resize.js size: 1439 +1ms ff:assets:asset-assembler readFile: node_modules/flot/jquery.flot.pie.js size: 13451 +2ms ff:assets:asset-assembler readFile: www_static/js/lib/angularjs-1.4.0-b4/angular.js size: 297085 +61ms ff:assets:asset-assembler readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-route.js size: 8360 +5ms ff:assets:asset-assembler readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-resource.js size: 6847 +1ms ff:assets:asset-assembler readFile: www_static/js/lib/angularjs-1.4.0-b4/angular-touch.js size: 7568 +2ms ff:assets:asset-assembler readFile: www_static/js/example-app.js size: 401 +0ms ff:assets:asset-assembler readFile: www_static/js/controller/page-bar.js size: 205 +0ms ff:assets:asset-assembler readFile: www_static/js/controller/page-foo.js size: 205 +0ms ff:assets:asset-assembler readFile: www_static/js/controller/page-index.js size: 207 +1ms ff:assets:asset-assembler target file: www_static/js/lib/assets.js +0ms ff:assets:asset-assembler target size: 592332 +0ms node-ff-assets:js build result size: 1 from: 13 node-ff-assets:js build done in: 3502 ms. Server assets done. Server config done. Server started on port 8080 ## 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.5 * Switched debug logging to debug library. * Removed events from AssetsBuilder. * Removed logLevel from log event in AssetAssembler. ### 0.2.4 * Added json config reader. * Added readFileRegex data filter. * Added filename template to seperator. * Converted example to ejs. ### 0.2.2 * Fixed error to callback * Fixed 404 error * Removed error event * Added log event to builder * Added builder tests * Made example jslint pass ### 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