Skip to content

Commit 6faac31

Browse files
Support for an advanced “persistentCache” to be used for persisting outside of the current memory.
1 parent 3b240bb commit 6faac31

File tree

3 files changed

+150
-10
lines changed

3 files changed

+150
-10
lines changed

index.js

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ function Deps (opts) {
2727
if (!opts) opts = {};
2828

2929
this.basedir = opts.basedir || process.cwd();
30+
this.persistentCache = opts.persistentCache || function (file, id, pkg, fallback, cb) {
31+
setImmediate(function () {
32+
fallback(null, cb);
33+
});
34+
};
3035
this.cache = opts.cache;
3136
this.fileCache = opts.fileCache;
3237
this.pkgCache = opts.packageCache || {};
@@ -376,19 +381,41 @@ Deps.prototype.walk = function (id, parent, cb) {
376381
var c = self.cache && self.cache[file];
377382
if (c) return fromDeps(file, c.source, c.package, fakePath, Object.keys(c.deps));
378383

379-
self.readFile(file, id, pkg)
380-
.pipe(self.getTransforms(fakePath || file, pkg, {
381-
builtin: builtin,
382-
inNodeModules: parent.inNodeModules
383-
}))
384-
.pipe(concat(function (body) {
385-
fromSource(file, body.toString('utf8'), pkg, fakePath);
386-
}))
387-
;
384+
self.persistentCache(file, id, pkg, function fallback (stream, cb) {
385+
(stream || self.readFile(file, id, pkg))
386+
.pipe(self.getTransforms(fakePath || file, pkg, {
387+
builtin: builtin,
388+
inNodeModules: parent.inNodeModules
389+
}))
390+
.pipe(concat(function (body) {
391+
var src = body.toString('utf8');
392+
var deps = getDeps(file, src);
393+
if (deps) {
394+
cb(null, {
395+
source: src,
396+
package: pkg,
397+
deps: deps.reduce(function (deps, dep) {
398+
deps[dep] = true
399+
return deps
400+
}, {})
401+
});
402+
}
403+
}));
404+
}, function (err, c) {
405+
if (err) {
406+
self.emit('error', err);
407+
return;
408+
}
409+
fromDeps(file, c.source, c.package, fakePath, Object.keys(c.deps));
410+
});
388411
});
389412

413+
function getDeps (file, src) {
414+
return rec.noparse ? [] : self.parseDeps(file, src);
415+
}
416+
390417
function fromSource (file, src, pkg, fakePath) {
391-
var deps = rec.noparse ? [] : self.parseDeps(file, src);
418+
var deps = getDeps(file, src);
392419
if (deps) fromDeps(file, src, pkg, fakePath, deps);
393420
}
394421

readme.markdown

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,38 @@ contents for browser fields, main entries, and transforms
9494
* `opts.fileCache` - an object mapping filenames to raw source to avoid reading
9595
from disk.
9696

97+
* `opts.persistentCache` - a complex cache handler that allows async and persistent
98+
caching of data. A `persistentCache` needs to follow this interface:
99+
```
100+
function peristentCache (
101+
file, // the path to the file that is loaded
102+
id, // the id that is used to reference this file
103+
pkg, // the package that this file belongs to fallback
104+
cb // callback handler that receives the cache data
105+
) {
106+
if (hasError()) {
107+
return cb(error) // Pass any error to the callback
108+
}
109+
if (isInCache()) {
110+
return cb(null, {
111+
source: fs.readFileSync(file, 'utf8'), // String of the fully processed file
112+
package: pkg, // The package for housekeeping
113+
deps: {
114+
'id': // id that is used to reference a required file
115+
'file' // file path to the required file
116+
}
117+
})
118+
}
119+
// optional (can be null) stream that provides the data from
120+
// the hard disk, can be provided in case the file data is used
121+
// to evaluate the cache identifier
122+
stream = fs.createReadStream(file)
123+
124+
// fallback to the default reading
125+
fallback(stream, cb)
126+
}
127+
```
128+
97129
* `opts.paths` - array of global paths to search. Defaults to splitting on `':'`
98130
in `process.env.NODE_PATH`
99131

test/cache_persistent.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
var parser = require('../');
2+
var test = require('tap').test;
3+
var path = require('path');
4+
var fs = require('fs');
5+
6+
var files = {
7+
foo: path.join(__dirname, '/files/foo.js'),
8+
bar: path.join(__dirname, '/files/bar.js')
9+
};
10+
11+
test('uses persistent cache', function (t) {
12+
t.plan(1);
13+
var p = parser({
14+
persistentCache: function (file, id, pkg, fallback, cb) {
15+
if (file === files.bar) {
16+
return fallback(null, cb)
17+
}
18+
cb(null, {
19+
source: 'file at ' + file + '@' + id,
20+
package: pkg,
21+
deps: { './bar': files.bar }
22+
})
23+
}
24+
});
25+
p.end({ id: 'foo', file: files.foo, entry: false });
26+
27+
var rows = [];
28+
p.on('data', function (row) { rows.push(row) });
29+
p.on('end', function () {
30+
t.same(rows.sort(cmp), [
31+
{
32+
id: files.bar,
33+
file: files.bar,
34+
source: fs.readFileSync(files.bar, 'utf8'),
35+
deps: {}
36+
},
37+
{
38+
id: 'foo',
39+
file: files.foo,
40+
source: 'file at ' + files.foo + '@' + files.foo,
41+
deps: { './bar': files.bar }
42+
}
43+
].sort(cmp));
44+
});
45+
});
46+
47+
test('passes persistent cache error through', function (t) {
48+
t.plan(1);
49+
var p = parser({
50+
persistentCache: function (file, id, pkg, fallback, cb) {
51+
cb(new Error('foo'))
52+
}
53+
});
54+
p.end({ id: 'foo', file: files.foo, entry: false });
55+
p.on('error', function (err) { t.equals(err.message, 'foo') });
56+
});
57+
58+
test('allow passing of a different stream', function (t) {
59+
t.plan(1);
60+
var p = parser({
61+
persistentCache: function (file, id, pkg, fallback, cb) {
62+
fallback(fs.createReadStream(files.bar), cb)
63+
}
64+
});
65+
p.end({ id: 'foo', file: files.foo, entry: false });
66+
67+
var rows = [];
68+
p.on('data', function (row) { rows.push(row) });
69+
p.on('end', function () {
70+
t.same(rows.sort(cmp), [
71+
{
72+
id: 'foo',
73+
file: files.foo,
74+
source: fs.readFileSync(files.bar, 'utf8'),
75+
deps: {}
76+
}
77+
].sort(cmp));
78+
});
79+
});
80+
81+
function cmp (a, b) { return a.id < b.id ? -1 : 1 }

0 commit comments

Comments
 (0)