444 lines
17 KiB
Markdown
444 lines
17 KiB
Markdown
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
|