From f50b474605bace509ab939c80650b204cc42672b Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Thu, 9 May 2019 18:44:31 +0100 Subject: [PATCH 1/4] perf: add cached version of `isDir` --- src/index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/index.js b/src/index.js index 47437d1..f137c45 100644 --- a/src/index.js +++ b/src/index.js @@ -37,6 +37,22 @@ function cachedIsFile (file, cb) { isFileCache[file].then(contents => cb(null, contents), cb); } +let isDirCache = {}; +function cachedIsDir (dir, cb) { + if (dir in isDirCache === false) { + isDirCache[dir] = statAsync(dir) + .then( + stat => stat.isDirectory(), + err => { + if (err.code === 'ENOENT') return false; + delete isDirCache[dir]; + throw err; + }); + } + isDirCache[dir].then(contents => cb(null, contents), cb); +} + + function getMainFields (options) { let mainFields; if (options.mainFields) { @@ -182,6 +198,7 @@ export default function nodeResolve ( options = {} ) { }, readFile: cachedReadFile, isFile: cachedIsFile, + isDir: cachedIsDir, extensions: extensions }; From 774c954152db937db04dc8c55253edded7a5de35 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Fri, 10 May 2019 11:36:24 +0100 Subject: [PATCH 2/4] refactor: DRY up cache functions --- src/index.js | 73 +++++++++++++++++++--------------------------------- 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/src/index.js b/src/index.js index f137c45..0f2a4ac 100644 --- a/src/index.js +++ b/src/index.js @@ -9,49 +9,29 @@ const ES6_BROWSER_EMPTY = resolve( __dirname, '../src/empty.js' ); // which deploy both ESM .mjs and CommonJS .js files as ESM. const DEFAULT_EXTS = [ '.mjs', '.js', '.json', '.node' ]; -let readFileCache = {}; const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, (err, contents) => err ? reject(err) : fulfil(contents))); const statAsync = file => new Promise((fulfil, reject) => fs.stat(file, (err, contents) => err ? reject(err) : fulfil(contents))); -function cachedReadFile (file, cb) { - if (file in readFileCache === false) { - readFileCache[file] = readFileAsync(file).catch(err => { - delete readFileCache[file]; - throw err; - }); - } - readFileCache[file].then(contents => cb(null, contents), cb); -} - -let isFileCache = {}; -function cachedIsFile (file, cb) { - if (file in isFileCache === false) { - isFileCache[file] = statAsync(file) - .then( - stat => stat.isFile(), - err => { - if (err.code === 'ENOENT') return false; - delete isFileCache[file]; - throw err; - }); - } - isFileCache[file].then(contents => cb(null, contents), cb); -} - -let isDirCache = {}; -function cachedIsDir (dir, cb) { - if (dir in isDirCache === false) { - isDirCache[dir] = statAsync(dir) - .then( - stat => stat.isDirectory(), - err => { - if (err.code === 'ENOENT') return false; - delete isDirCache[dir]; - throw err; - }); - } - isDirCache[dir].then(contents => cb(null, contents), cb); -} - +const cache = fn => { + let cache = Object.create(null); + const wrapped = (s, cb = false) => { + if (s in cache === false) { + cache[s] = fn(s).catch(err => { + delete cache[s]; + throw err; + }); + } + return cb ? cache[s].then(v => cb(null, v), cb) : cache[s]; + }; + wrapped.clear = () => { cache = {}; }; + return wrapped; +}; +const ignoreENOENT = err => { + if (err.code === 'ENOENT') return false; + throw err; +}; +const readFileCached = cache(readFileAsync); +const isDirCached = cache(file => statAsync(file).then(stat => stat.isDirectory(), ignoreENOENT)); +const isFileCached = cache(file => statAsync(file).then(stat => stat.isFile(), ignoreENOENT)); function getMainFields (options) { let mainFields; @@ -115,8 +95,9 @@ export default function nodeResolve ( options = {} ) { }, generateBundle () { - isFileCache = {}; - readFileCache = {}; + readFileCached.clear(); + isFileCached.clear(); + isDirCached.clear(); }, resolveId ( importee, importer ) { @@ -196,9 +177,9 @@ export default function nodeResolve ( options = {} ) { } return pkg; }, - readFile: cachedReadFile, - isFile: cachedIsFile, - isDir: cachedIsDir, + readFile: readFileCached, + isFile: isFileCached, + isDirectory: isDirCached, extensions: extensions }; From d786f8d136ab9f2687fc7cd4d9a5f784a26db826 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Fri, 10 May 2019 11:41:40 +0100 Subject: [PATCH 3/4] refactor: use Map for cache over Object --- src/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 0f2a4ac..424159f 100644 --- a/src/index.js +++ b/src/index.js @@ -12,17 +12,17 @@ const DEFAULT_EXTS = [ '.mjs', '.js', '.json', '.node' ]; const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, (err, contents) => err ? reject(err) : fulfil(contents))); const statAsync = file => new Promise((fulfil, reject) => fs.stat(file, (err, contents) => err ? reject(err) : fulfil(contents))); const cache = fn => { - let cache = Object.create(null); - const wrapped = (s, cb = false) => { - if (s in cache === false) { - cache[s] = fn(s).catch(err => { - delete cache[s]; + const cache = new Map(); + const wrapped = (fileName, cb) => { + if (cache.has(fileName) === false) { + cache.set(fileName, fn(fileName).catch(err => { + cache.delete(fileName); throw err; - }); + })); } - return cb ? cache[s].then(v => cb(null, v), cb) : cache[s]; + return cache.get(fileName).then(v => cb(null, v), cb); }; - wrapped.clear = () => { cache = {}; }; + wrapped.clear = () => cache.clear(); return wrapped; }; const ignoreENOENT = err => { From 46a2581ab74076f149c7e58a2add20c3db5d1f58 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Fri, 10 May 2019 18:28:31 +0100 Subject: [PATCH 4/4] refactor: rename variables for clarity --- src/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 424159f..b5b6c61 100644 --- a/src/index.js +++ b/src/index.js @@ -13,14 +13,14 @@ const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, const statAsync = file => new Promise((fulfil, reject) => fs.stat(file, (err, contents) => err ? reject(err) : fulfil(contents))); const cache = fn => { const cache = new Map(); - const wrapped = (fileName, cb) => { - if (cache.has(fileName) === false) { - cache.set(fileName, fn(fileName).catch(err => { - cache.delete(fileName); + const wrapped = (param, done) => { + if (cache.has(param) === false) { + cache.set(param, fn(param).catch(err => { + cache.delete(param); throw err; })); } - return cache.get(fileName).then(v => cb(null, v), cb); + return cache.get(param).then(result => done(null, result), done); }; wrapped.clear = () => cache.clear(); return wrapped;