Skip to content

Commit 068be4b

Browse files
author
Shubham Kanodia
committed
Use LMDB cache instead of regular FS cache to speed up cache hits
1 parent 052c07a commit 068be4b

File tree

10 files changed

+3717
-3713
lines changed

10 files changed

+3717
-3713
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ jobs:
1111
- uses: actions/setup-node@v1
1212
with:
1313
node-version: "*"
14+
cache: 'yarn'
1415
- name: Install dependencies
1516
run: yarn
1617
- name: Lint
@@ -20,7 +21,7 @@ jobs:
2021
strategy:
2122
matrix:
2223
os: [ubuntu-latest, windows-latest]
23-
node-version: [10.x, 12.x, 14.x, 15.x]
24+
node-version: [12.x, 14.x, 16.x]
2425
webpack-version: [latest, '4']
2526
include:
2627
- node: 14.x
@@ -33,6 +34,7 @@ jobs:
3334
uses: actions/setup-node@v1
3435
with:
3536
node-version: ${{ matrix.node-version }}
37+
cache: 'yarn'
3638
- name: Install dependencies
3739
run: yarn
3840
- name: Install webpack ${{ matrix.webpack-version }}
@@ -48,29 +50,4 @@ jobs:
4850
if: ${{ matrix.coverage }}
4951
with:
5052
token: ${{ secrets.CODECOV_TOKEN }}
51-
test-legacy:
52-
name: Test - ubuntu-latest - Node v8.9, Webpack 4
53-
runs-on: ubuntu-latest
54-
env:
55-
YARN_NODE_LINKER: node-modules
56-
steps:
57-
- uses: actions/checkout@v2
58-
- name: Use Node.js 14.x
59-
uses: actions/setup-node@v1
60-
with:
61-
node-version: 14.x
62-
- name: Install dependencies
63-
run: yarn
64-
- name: Install webpack 4
65-
run: yarn add -D webpack@4
66-
- name: Build babel-loader
67-
run: yarn run build
68-
env:
69-
BABEL_ENV: test
70-
- name: Use Node.js 8.9
71-
uses: actions/setup-node@v1
72-
with:
73-
node-version: '8.9'
74-
- name: Run tests for webpack version 4
75-
run: node scripts/test-legacy
7653

.yarn/releases/yarn-2.3.3.cjs

Lines changed: 0 additions & 55 deletions
This file was deleted.

.yarn/releases/yarn-3.2.0.cjs

Lines changed: 785 additions & 0 deletions
Large diffs are not rendered by default.

.yarnrc.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
yarnPath: .yarn/releases/yarn-2.3.3.cjs
1+
yarnPath: .yarn/releases/yarn-3.2.0.cjs
2+
nodeLinker: node-modules

babel.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
["@babel/preset-env", {
44
"loose": true,
55
"targets": {
6-
"node": "6.9"
6+
"node": "12.0.0"
77
}
88
}]
99
],

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
},
1212
"dependencies": {
1313
"find-cache-dir": "^3.3.1",
14+
"lmdb": "^2.2.4",
1415
"loader-utils": "^1.4.0",
15-
"make-dir": "^3.1.0",
1616
"schema-utils": "^2.6.5"
1717
},
1818
"peerDependencies": {
@@ -36,6 +36,7 @@
3636
"eslint-plugin-prettier": "^3.0.0",
3737
"husky": "^4.3.0",
3838
"lint-staged": "^10.5.1",
39+
"node-preload": "^0.2.1",
3940
"nyc": "^15.1.0",
4041
"pnp-webpack-plugin": "^1.6.4",
4142
"prettier": "^2.1.2",

src/cache.js

Lines changed: 34 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,48 @@
77
* @see https://github.com/babel/babel-loader/issues/34
88
* @see https://github.com/babel/babel-loader/pull/41
99
*/
10-
const fs = require("fs");
1110
const os = require("os");
12-
const path = require("path");
13-
const zlib = require("zlib");
1411
const crypto = require("crypto");
1512
const findCacheDir = require("find-cache-dir");
16-
const { promisify } = require("util");
13+
const { open } = require("lmdb");
1714

1815
const transform = require("./transform");
1916
// Lazily instantiated when needed
2017
let defaultCacheDirectory = null;
21-
22-
const readFile = promisify(fs.readFile);
23-
const writeFile = promisify(fs.writeFile);
24-
const gunzip = promisify(zlib.gunzip);
25-
const gzip = promisify(zlib.gzip);
26-
const makeDir = require("make-dir");
18+
let cacheDB = null;
2719

2820
/**
29-
* Read the contents from the compressed file.
30-
*
31-
* @async
32-
* @params {String} filename
33-
* @params {Boolean} compress
21+
* Initialize cache
3422
*/
35-
const read = async function (filename, compress) {
36-
const data = await readFile(filename + (compress ? ".gz" : ""));
37-
const content = compress ? await gunzip(data) : data;
3823

39-
return JSON.parse(content.toString());
40-
};
24+
async function initCacheDB(cacheDir, cacheCompression) {
25+
if (cacheDB) return cacheDB;
26+
const fallback = cacheDir !== os.tmpdir();
4127

42-
/**
43-
* Write contents into a compressed file.
44-
*
45-
* @async
46-
* @params {String} filename
47-
* @params {Boolean} compress
48-
* @params {String} result
49-
*/
50-
const write = async function (filename, compress, result) {
51-
const content = JSON.stringify(result);
28+
try {
29+
cacheDB = open({
30+
path: cacheDir,
31+
compression: cacheCompression,
32+
sharedStructuresKey: Symbol.for(`structures`),
33+
});
34+
} catch (err) {
35+
if (fallback) {
36+
cacheDB = initCacheDB(os.tmpdir(), cacheCompression);
37+
}
5238

53-
const data = compress ? await gzip(content) : content;
54-
return await writeFile(filename + (compress ? ".gz" : ""), data);
55-
};
39+
throw err;
40+
}
41+
}
5642

5743
/**
58-
* Build the filename for the cached file
44+
* Build the cache key for the cached file
5945
*
6046
* @params {String} source File source code
6147
* @params {Object} options Options used
6248
*
6349
* @return {String}
6450
*/
65-
const filename = function (source, identifier, options) {
51+
const fileCacheKey = function (source, identifier, options) {
6652
// md4 hashing is not supported starting with node v17.0.0
6753
const majorNodeVersion = parseInt(process.versions.node.split(".")[0], 10);
6854
let hashType = "md4";
@@ -76,7 +62,7 @@ const filename = function (source, identifier, options) {
7662

7763
hash.update(contents);
7864

79-
return hash.digest("hex") + ".json";
65+
return hash.digest("hex");
8066
};
8167

8268
/**
@@ -85,51 +71,21 @@ const filename = function (source, identifier, options) {
8571
* @params {String} directory
8672
* @params {Object} params
8773
*/
88-
const handleCache = async function (directory, params) {
89-
const {
90-
source,
91-
options = {},
92-
cacheIdentifier,
93-
cacheDirectory,
94-
cacheCompression,
95-
} = params;
74+
const handleCache = async function (params) {
75+
const { source, options = {}, cacheIdentifier } = params;
9676

97-
const file = path.join(directory, filename(source, cacheIdentifier, options));
98-
99-
try {
100-
// No errors mean that the file was previously cached
101-
// we just need to return it
102-
return await read(file, cacheCompression);
103-
} catch (err) {}
77+
const cacheKey = fileCacheKey(source, cacheIdentifier, options);
10478

105-
const fallback =
106-
typeof cacheDirectory !== "string" && directory !== os.tmpdir();
107-
108-
// Make sure the directory exists.
109-
try {
110-
await makeDir(directory);
111-
} catch (err) {
112-
if (fallback) {
113-
return handleCache(os.tmpdir(), params);
114-
}
115-
116-
throw err;
79+
// Fetch cached result if it exists
80+
const cached = await cacheDB.get(cacheKey);
81+
if (typeof cached !== "undefined") {
82+
return cached;
11783
}
11884

119-
// Otherwise just transform the file
85+
// Otherwise, just transform the cacheKey
12086
// return it to the user asap and write it in cache
12187
const result = await transform(source, options);
122-
123-
try {
124-
await write(file, cacheCompression, result);
125-
} catch (err) {
126-
if (fallback) {
127-
// Fallback to tmpdir if node_modules folder not writable
128-
return handleCache(os.tmpdir(), params);
129-
}
130-
131-
throw err;
132-
}
88+
cacheDB.put(cacheKey, result);
13389

13490
return result;
13591
};
@@ -173,5 +129,7 @@ module.exports = async function (params) {
173129
directory = defaultCacheDirectory;
174130
}
175131

176-
return await handleCache(directory, params);
132+
await initCacheDB(directory, params.cacheCompression);
133+
134+
return await handleCache(params);
177135
};

0 commit comments

Comments
 (0)