Skip to content

Instantly share code, notes, and snippets.

@drd
Created Sep 16, 2015
Embed
What would you like to do?
A caching babel compiler for require extensions, with optional preprocessor
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