Last active
December 10, 2015 22:38
-
-
Save piranha/4504099 to your computer and use it in GitHub Desktop.
Custom RequireJS packer/optimizer & md5 map generator.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// (c) 2012-2013 Instant Communication Bhd, under terms of ISC License. | |
// | |
// Process index.html to add md5ized path mapping for RequireJS. | |
// | |
// Needs empty CacheBust variable to be defined (see replacement logic), which | |
// afterwards should be used in `require.config({paths: CacheBust});` call. | |
var fs = require('fs'); | |
var exec = require('child_process').exec; | |
var crypto = require('crypto'); | |
var path = require('path'); | |
function write(index, md5map) { | |
index = fs.readFileSync(index).toString(); | |
md5map = JSON.stringify(md5map); | |
index = index | |
.replace('CacheBust = {}', | |
'CacheBust = ' + md5map); | |
console.log(index); | |
} | |
function md5(fn) { | |
var hasher = crypto.createHash('md5'); | |
hasher.update(fs.readFileSync(fn)); | |
return hasher.digest('hex'); | |
} | |
function findFiles(name) { | |
var stat = fs.statSync(name); | |
if (stat.isDirectory()) { | |
var files = fs.readdirSync(name); | |
return files | |
.map(function(fn) { | |
return findFiles(path.join(name, fn)); | |
}) | |
.filter(function(x) { return x; }) | |
.reduce(function(vals, x) { | |
return Array.isArray(x) ? vals.concat(x) : vals.push(x) && vals; | |
}, []); | |
} | |
var ext = name.slice(name.lastIndexOf('.') + 1); | |
if (ext == 'js' || ext == 'json' || ext == 'css') { | |
return {name: name, value: name + '?' + md5(name)}; | |
} | |
} | |
function stripname(dir, path) { | |
if (dir.length) { | |
path = path.slice(dir.length + 1); | |
} | |
var ext = path.slice(path.lastIndexOf('.') + 1); | |
if (ext == 'js') { | |
path = path.slice(0, path.length - 3); | |
} | |
return path; | |
} | |
function run() { | |
if (process.argv.length < 4) { | |
console.log('Usage: ' + process.argv[1] + | |
' path/to/index.html paths/to prod/dirs\n'); | |
process.exit(0); | |
} | |
var index = process.argv[2]; | |
var dirs = process.argv.slice(3); | |
var dir, i, files, map = {}; | |
for (i = 0; i < dirs.length; i++) { | |
dir = dirs[i]; | |
findFiles(dir).forEach(function(x) { | |
map[stripname(dir, x.name)] = stripname(dir, x.value); | |
}); | |
} | |
write(index, map); | |
} | |
run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// (c) 2012-2013 Instant Communication Bhd, under terms of ISC License. | |
var fs = require('fs'); | |
var path = require('path'); | |
var getopt = require('node-getopt'); | |
var uglify = require('uglify-js'); | |
var jsp = uglify.parser; | |
var pro = uglify.uglify; | |
var parsed = require('node-getopt').create([ | |
['b', 'base=BASE', 'Base path'], | |
['o', 'output=OUTPUT', 'Output path'] | |
]) | |
.bindHelp() | |
.parseSystem(); | |
var args = parsed.argv, opts = parsed.options; | |
var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; | |
var cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g; | |
function moduleFromPath(path) { | |
if (path.slice(path.length - 3) === '.js') { | |
path = path.slice(0, path.length - 3); | |
} | |
if (path.slice(0, opts.base.length) == opts.base) { | |
path = path.slice(opts.base.length); | |
} | |
return path; | |
} | |
function getpath(module) { | |
return path.join(opts.base, module + '.js'); | |
} | |
function relativeModule(parent, module) { | |
return path.join(path.dirname(parent), module); | |
} | |
function parseModule(found, module) { | |
if (found[module]) { | |
return; | |
} | |
console.log(' ...processing ' + module); | |
var content = fs.readFileSync(getpath(module), 'utf8').toString(); | |
var deps = ['require', 'exports', 'module']; | |
content | |
.replace(commentRegExp, '') | |
.replace(cjsRequireRegExp, function(match, dep) { | |
deps.push(dep); | |
if (dep[0] === '.') { | |
parseModule(found, relativeModule(module, dep)); | |
} | |
}); | |
var def = 'define("' + module + '", '; | |
if (content.match(/define\( *function/)) { | |
def = def + '["' + deps.join('", "') + '"], '; | |
} else { | |
def = def + '[], '; | |
} | |
found[module] = content.replace(/define\(/, def); | |
return found; | |
} | |
function compress(code) { | |
var ast; | |
ast = jsp.parse(code); | |
ast = pro.ast_mangle(ast, { | |
mangle: true, | |
mangle_toplevel: false, | |
defines: {}, | |
except: null, | |
no_functions: false | |
}); | |
ast = pro.ast_squeeze(ast, { | |
make_seqs: false, | |
dead_code: true, | |
keep_comps: true, | |
unsafe: false | |
}); | |
return pro.gen_code(ast, { | |
ascii_only: false, | |
beautify: false, | |
indent_level: 4, | |
indent_start: 0, | |
quote_keys: false, | |
space_colon: false, | |
inline_script: false | |
}); | |
} | |
function main() { | |
if (!args.length) { | |
console.log('Run ' + process.argv[1] + ' --help to see usage\n'); | |
process.exit(0); | |
} | |
var modules = {}; | |
args.forEach(function(module) { | |
module = moduleFromPath(module); | |
console.log('Traversing from ' + module + '...'); | |
parseModule(modules, module); | |
}); | |
var content = ''; | |
for (var module in modules) { | |
content += modules[module]; | |
} | |
var compressed = compress(content); | |
if (opts.output) { | |
fs.writeFileSync(opts.output, compressed, 'utf8'); | |
console.log('Packed to ' + opts.output); | |
} else { | |
console.log(compressed); | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment