You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.7 KiB
169 lines
4.7 KiB
const defaults = require('./defaults'); |
|
const md5 = require('./md5'); |
|
const safeGet = require('./safeGet'); |
|
const FileStore = require('./FileStore'); |
|
const FileBlobStore = require('./FileBlobStore'); |
|
const mkdir = require('./mkdir'); |
|
|
|
let isEnabled = false; |
|
|
|
exports = function(options = {}) { |
|
if (isEnabled) { |
|
return; |
|
} |
|
isEnabled = true; |
|
defaults(options, defOptions); |
|
|
|
const Module = require('module'); |
|
const fs = require('fs'); |
|
const path = require('path'); |
|
const vm = require('vm'); |
|
|
|
const cacheDir = options.dir || getCacheDir(); |
|
if (!fs.existsSync(cacheDir)) { |
|
mkdir.sync(cacheDir); |
|
} |
|
|
|
if (options.requirePath) { |
|
const _resolveFilename = Module._resolveFilename; |
|
const requirePathMapStore = new FileStore( |
|
path.resolve(cacheDir, 'require-path.json') |
|
); |
|
|
|
Module._resolveFilename = function(request, parent, isMain, options) { |
|
let currentModuleCache = requirePathMapStore.get(parent.filename); |
|
if (!currentModuleCache) { |
|
currentModuleCache = {}; |
|
requirePathMapStore.set(parent.filename, currentModuleCache); |
|
} |
|
if (currentModuleCache[request]) { |
|
return currentModuleCache[request]; |
|
} |
|
|
|
const pathToLoad = _resolveFilename( |
|
request, |
|
parent, |
|
isMain, |
|
options |
|
); |
|
currentModuleCache[request] = pathToLoad; |
|
|
|
return pathToLoad; |
|
}; |
|
} |
|
|
|
if (options.code) { |
|
const fileMapStore = new FileStore( |
|
path.resolve(cacheDir, 'require-file.json') |
|
); |
|
|
|
Module._extensions['.js'] = function(module, filename) { |
|
let content; |
|
if (fileMapStore.get(filename)) { |
|
content = fileMapStore.get(filename); |
|
} else { |
|
content = fs.readFileSync(filename, 'utf8'); |
|
fileMapStore.set(filename, content); |
|
} |
|
return module._compile(content, filename); |
|
}; |
|
} |
|
|
|
if (options.compileCache) { |
|
const compileCacheBlobStore = new FileBlobStore( |
|
path.resolve(cacheDir, 'compile-cache') |
|
); |
|
process.once('exit', () => compileCacheBlobStore.save()); |
|
Module.prototype._compile = function(content, filename) { |
|
const mod = this; |
|
|
|
function require(id) { |
|
return mod.require(id); |
|
} |
|
|
|
function resolve(request, options) { |
|
return Module._resolveFilename(request, mod, false, options); |
|
} |
|
require.resolve = resolve; |
|
|
|
resolve.paths = function paths(request) { |
|
return Module._resolveLookupPaths(request, mod, true); |
|
}; |
|
|
|
require.main = process.mainModule; |
|
|
|
require.extensions = Module._extensions; |
|
require.cache = Module._cache; |
|
|
|
const dirname = path.dirname(filename); |
|
|
|
const compiledWrapper = moduleCompile(filename, content); |
|
|
|
const args = [ |
|
mod.exports, |
|
require, |
|
mod, |
|
filename, |
|
dirname, |
|
process, |
|
global, |
|
Buffer |
|
]; |
|
return compiledWrapper.apply(mod.exports, args); |
|
}; |
|
|
|
function moduleCompile(filename, content) { |
|
const wrapper = Module.wrap(content); |
|
|
|
const buffer = compileCacheBlobStore.get(filename); |
|
|
|
const script = new vm.Script(wrapper, { |
|
filename, |
|
lineOffset: 0, |
|
displayErrors: true, |
|
cachedData: buffer, |
|
produceCachedData: true |
|
}); |
|
|
|
if (script.cachedDataProduced) { |
|
compileCacheBlobStore.set(filename, script.cachedData); |
|
} else if (script.cachedDataRejected) { |
|
compileCacheBlobStore.delete(filename); |
|
} |
|
|
|
const compiledWrapper = script.runInThisContext({ |
|
filename, |
|
lineOffset: 0, |
|
columnOffset: 0, |
|
displayErrors: true |
|
}); |
|
|
|
return compiledWrapper; |
|
} |
|
} |
|
}; |
|
|
|
const defOptions = { |
|
requirePath: true, |
|
code: false, |
|
compileCache: true |
|
}; |
|
|
|
function getCacheDir() { |
|
const os = require('os'); |
|
|
|
return ( |
|
os.tmpdir() + |
|
'/' + |
|
md5( |
|
`${get(process, 'versions.v8')}${get(require, 'main.filename') || |
|
get(module, 'parent.filename')}` |
|
) |
|
); |
|
} |
|
|
|
function get(obj, path) { |
|
return safeGet(obj, path) || ''; |
|
} |
|
|
|
module.exports = exports;
|
|
|