Created
September 16, 2015 18:34
-
-
Save drd/d5a2e225065f525e57d9 to your computer and use it in GitHub Desktop.
A caching babel compiler for require extensions, with optional preprocessor
This file contains hidden or 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
var babel = require('babel'); | |
var extend = require('underscore').extend; | |
var path = require("path"); | |
var os = require("os"); | |
var fs = require("fs-ext"); | |
var merge = require('lodash').merge; | |
var cache = {}; | |
var jsons = {}; | |
function exists(filename) { | |
if (!fs.existsSync) return false; | |
var cached = cache[filename]; | |
if (cached != null) return cached; | |
return cache[filename] = fs.existsSync(filename); | |
} | |
function resolveRc(loc, opts) { | |
opts = opts || {}; | |
var rel = ".babelrc"; | |
function find(start, rel) { | |
var file = path.join(start, rel); | |
if (exists(file)) { | |
var content = fs.readFileSync(file, "utf8"); | |
var json; | |
try { | |
json = jsons[content]; | |
if (!json) { | |
json = jsons[content] = JSON.parse(content); | |
} | |
} catch (err) { | |
err.message = [file, err.message].join(': '); | |
throw err; | |
} | |
if (json.breakConfig) return; | |
merge(opts, json, function(a, b) { | |
if (Array.isArray(a)) { | |
return a.concat(b); | |
} | |
}); | |
} | |
var up = path.dirname(start); | |
if (up !== start) { // root | |
find(up, rel); | |
} | |
} | |
if (opts.breakConfig !== true) { | |
find(loc, rel); | |
} | |
return opts; | |
}; | |
const FILENAME = path.join(os.tmpdir(), ".babel.json"); | |
var cache = {}; | |
function save() { | |
if (!fs.existsSync(FILENAME)) { | |
fs.writeFileSync(FILENAME, '{}'); | |
} | |
var fd = fs.openSync(FILENAME, 'r'); | |
try { | |
fs.flockSync(fd, 'ex'); | |
var canonical = JSON.parse(fs.readFileSync(FILENAME)); | |
Object.keys(cache).forEach(function(key) { | |
var persisted = canonical[key]; | |
var local = cache[key]; | |
if (!persisted) { | |
canonical[key] = local; | |
} | |
else if (persisted && persisted.mtime) { | |
if (persisted.mtime < local.mtime) { | |
canonical[key] = local; | |
} | |
} | |
}); | |
fs.writeFileSync(FILENAME, JSON.stringify(canonical, null, " ")); | |
} catch(e) { | |
console.error(e); | |
} finally { | |
fs.flockSync(fd, 'un'); | |
} | |
} | |
function load() { | |
if (process.env.BABEL_DISABLE_CACHE) return; | |
if (!fs.existsSync(FILENAME)) return; | |
try { | |
cache = JSON.parse(fs.readFileSync(FILENAME)); | |
} catch (err) { | |
return; | |
} | |
} | |
load(); | |
// | |
var transformOpts = { stage: 1 }; | |
var ignoreRegex = /node_modules/; | |
var onlyRegex; | |
var oldHandlers = {}; | |
var maps = {}; | |
var total = 0; | |
var mtime = function (filename) { | |
return +fs.statSync(filename).mtime; | |
}; | |
var compile = function (filename, src, preprocess) { | |
var result; | |
var opts = extend({}, transformOpts); | |
// this will be done when the file is transformed anyway but we need all | |
// the options so we can generate the cache key | |
resolveRc(filename, opts); | |
var cacheKey = [filename, JSON.stringify(opts), (preprocess || '').toString().substr(10, 20), babel.version].join(':'); | |
if (cache) { | |
var cached = cache[cacheKey]; | |
if (cached && cached.mtime === mtime(filename)) { | |
result = cached; | |
} | |
} | |
if (!result) { | |
console.error("Missed cache for", filename); | |
var start = Date.now(); | |
if (preprocess) { | |
try { | |
src = preprocess(src); | |
} catch (e) { | |
console.error("Error preprocessing " + filename + ":"); | |
console.error(e.toString()); | |
process.exit(1); | |
} | |
} | |
result = babel.transform(src, extend(opts, { | |
sourceMap: "both", | |
ast: false | |
})); | |
total += Date.now() - start; | |
console.error('Cumulative', process.pid, total/1000); | |
if (cache) { | |
result.mtime = mtime(filename); | |
cache[cacheKey] = result; | |
save(); | |
} | |
} | |
maps[filename] = result.map; | |
return result.code; | |
}; | |
module.exports = {canCompile: babel.canCompile, compile: compile}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment