├── .gitignore ├── Readme.md ├── index.js ├── lib └── asereje.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | .aMMMb .dMMMb dMMMMMP dMMMMb dMMMMMP dMMMMMP dMMMMMP 2 | dMP"dMP dMP" VP dMP dMP.dMP dMP dMP dMP 3 | dMMMMMP VMMMb dMMMP dMMMMK" dMMMP dMP dMMMP 4 | dMP dMP dP .dMP dMP dMP"AMF dMP dK .dMP dMP 5 | dMP dMP VMMMP" dMMMMMP dMP dMP dMMMMMP VMMMP" dMMMMMP 6 | 7 | 8 | "Aserejé ja de jé de jebe, tu de jebere sebiunouba, majabi an de bugui an de buididipí" 9 | 10 | ## Description 11 | 12 | Asereje is a library that builds your assets on demand. 13 | 14 | ## Installation 15 | 16 | ``` bash 17 | npm install asereje 18 | ``` 19 | 20 | ## Usage 21 | 22 | First you have to configure asereje: 23 | 24 | ``` javascript 25 | var asereje = require('asereje'); 26 | 27 | asereje.config({ 28 | active: process.env.NODE_ENV === 'production' // enable it just for production 29 | , js_globals: ['lib/jquery', 'global', 'underscore'] // js files that will be present always 30 | , css_globals: ['reset', 'global'] // css files that will be present always 31 | , js_path: __dirname + '/public/javascripts' // javascript folder path 32 | , css_path: __dirname + '/public/css' // css folder path 33 | }); 34 | ``` 35 | 36 | Then you can use `css` or `js` function to get the file names. 37 | 38 | ``` javascript 39 | res.render('users/index', { 40 | css: asereje.css(['users', users/index]) // => ['reset', 'global', 'users', 'users/index'] 41 | }); 42 | 43 | // ... it builds the files and the next requests will return: 44 | 45 | res.render('users/index', { 46 | css: asereje.css(['users', users/index]) // => ['dist/f330099956c144c090b06f6d4bae8770', 'dist/caa6925553b03e049eeda6f70da9dc1a'] 47 | }); 48 | ``` 49 | 50 | ``` jade 51 | html 52 | head 53 | -each file in css 54 | link(rel= 'stylesheet', href= '/css/' + file + '.css' ) 55 | ... 56 | ``` 57 | 58 | ## Explanation 59 | 60 | Asereje does 3 things: 61 | 62 | * Bundles your files together and build 2 files. The first is for the files that are common to all the pages, such a reset.css or jquery.js. 63 | This files will be cached once and not requested anymore. The second file is specific to each page. 64 | * Applies minification. `Ugilify-js` for javascripts and `sqwish` for css. 65 | * Renames the files with the md5 of the content. This way we can set the expires header to max. 66 | 67 | ## Configure your webserver to take advantage 68 | 69 | Built files are stored under `js_path|css_path/dist`. Add expires headers to all this files so the users will have them cached forever. 70 | 71 | ``` 72 | // nginx conf 73 | location ~* ^/(css|javascripts)/dist/.+\.(css|js)$ { 74 | expires max; 75 | } 76 | ``` 77 | 78 | ## Asereje? What does it mean?? 79 | 80 | [The true meaning of life](http://www.youtube.com/watch?v=drw-M-t4OTo) 81 | 82 | ## License 83 | 84 | (The MIT License) 85 | 86 | Copyright (c) 2011 Pau Ramon Revilla <masylum@gmail.com> 87 | 88 | Permission is hereby granted, free of charge, to any person obtaining 89 | a copy of this software and associated documentation files (the 90 | 'Software'), to deal in the Software without restriction, including 91 | without limitation the rights to use, copy, modify, merge, publish, 92 | distribute, sublicense, and/or sell copies of the Software, and to 93 | permit persons to whom the Software is furnished to do so, subject to 94 | the following conditions: 95 | 96 | The above copyright notice and this permission notice shall be 97 | included in all copies or substantial portions of the Software. 98 | 99 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 100 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 101 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 102 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 103 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 104 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 105 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 106 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/asereje'); 2 | -------------------------------------------------------------------------------- /lib/asereje.js: -------------------------------------------------------------------------------- 1 | var _cache = {} 2 | , ASEREJE = {} 3 | , _settings = { active: true 4 | , js_globals: [] 5 | , css_globals: [] 6 | , sqwish_strict: true 7 | } 8 | , uglify = require('uglify-js') 9 | , sqwish = require('sqwish') 10 | , _ = require('underscore') 11 | , crypto = require('crypto') 12 | , fs = require('fs'); 13 | 14 | function md5(str) { 15 | return crypto 16 | .createHash('md5') 17 | .update(str) 18 | .digest('hex'); 19 | } 20 | 21 | function _get(type, global_files, files) { 22 | if (!_settings[type + '_path']) throw (Error('You must configure asereje paths first!')); 23 | 24 | function getCache(files) { 25 | return _cache[files.join(';')]; 26 | } 27 | 28 | function setAndCache(files) { 29 | var funk = require('funk')('parallel') 30 | , path = _settings[type + '_path'] + '/'; 31 | 32 | files.forEach(function (el) { 33 | fs.readFile(path + el + '.' + type, 'utf8', funk.result(el)); 34 | }); 35 | 36 | funk.run(function () { 37 | var self = this, minified, bundled = ''; 38 | 39 | files.forEach(function (el) { 40 | if (type === 'css') { 41 | bundled += self[el]; 42 | } else { 43 | bundled += self[el] + ';'; 44 | } 45 | }); 46 | 47 | if (type === 'css') { 48 | minified = sqwish.minify(bundled, _settings.sqwish_strict); 49 | } else if (type === 'js') { 50 | (function () { 51 | var jsp = uglify.parser 52 | , pro = uglify.uglify 53 | , ast = jsp.parse(bundled); 54 | 55 | ast = pro.ast_mangle(ast); 56 | ast = pro.ast_squeeze(ast); 57 | minified = pro.gen_code(ast); 58 | }()); 59 | } 60 | 61 | _cache[files.join(';')] = ['dist/' + md5(minified), minified]; 62 | fs.writeFile(path + getCache(files)[0] + '.' + type, getCache(files)[1]); 63 | }); 64 | } 65 | 66 | function run(files) { 67 | var cached = getCache(files); 68 | 69 | if (cached) { 70 | return [cached[0]]; 71 | } else { 72 | if (files.length) { 73 | setAndCache(files); 74 | } 75 | return files; 76 | } 77 | } 78 | 79 | return run(global_files).concat(run(files)); 80 | } 81 | 82 | /** 83 | * Sets a config value 84 | * 85 | * @param {Object} values 86 | * 87 | * @return itself 88 | */ 89 | ASEREJE.config = function (values) { 90 | _settings = _.extend(_settings, values); 91 | return ASEREJE; 92 | }; 93 | 94 | /** 95 | * Returns an array of file names. 96 | * Creates and caches the new css assets. 97 | * 98 | * @param {Array} files 99 | * 100 | * @return {Array} 101 | */ 102 | ASEREJE.css = function (files) { 103 | if (!_settings.css_globals) throw (Error('You must configure asereje `css_globals` first!')); 104 | 105 | files = files || []; 106 | 107 | if (_settings.active) { 108 | return _get('css', _settings.css_globals, files); 109 | } else { 110 | return _settings.css_globals.concat(files); 111 | } 112 | }; 113 | 114 | /** 115 | * Returns an array of file names. 116 | * Creates and caches the new javascript assets. 117 | * 118 | * @param {Array} global_files 119 | * @param {Array} files 120 | * 121 | * @return {Array} 122 | */ 123 | ASEREJE.js = function (files) { 124 | if (!_settings.js_globals) throw (Error('You must configure asereje `js_globals` first!')); 125 | 126 | files = files || []; 127 | 128 | if (_settings.active) { 129 | return _get('js', _settings.js_globals, files); 130 | } else { 131 | return _settings.js_globals.concat(files); 132 | } 133 | }; 134 | 135 | module.exports = ASEREJE; 136 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asereje", 3 | "description": "Asereje is a library that builds your assets on demand", 4 | "version": "0.1.0", 5 | "author": "Pau Ramon ", 6 | "keywords": ["build", "assets", "css", "javascript"], 7 | "main": "./index", 8 | "dependencies": { 9 | "uglify-js": "1.0.6", 10 | "funk": "1.5.0", 11 | "sqwish": "0.2.0", 12 | "underscore": "1.1.6" 13 | }, 14 | "repository" : {"type": "git" , "url": "http://github.com/masylum/asereje.git" }, 15 | "engines": { "node": ">= 0.4.0" } 16 | } 17 | --------------------------------------------------------------------------------