UNPKG

5.8 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
6
7const fs = require('@parcel/fs');
8
9const path = require('path');
10
11const md5 = require('./utils/md5');
12
13const objectHash = require('./utils/objectHash');
14
15const pkg = require('../package.json');
16
17const logger = require('@parcel/logger');
18
19const _require = require('./utils/glob'),
20 isGlob = _require.isGlob,
21 glob = _require.glob; // These keys can affect the output, so if they differ, the cache should not match
22
23
24const OPTION_KEYS = ['publicURL', 'minify', 'hmr', 'target', 'scopeHoist', 'sourceMaps'];
25
26class FSCache {
27 constructor(options) {
28 this.dir = path.resolve(options.cacheDir || '.cache');
29 this.dirExists = false;
30 this.invalidated = new Set();
31 this.optionsHash = objectHash(OPTION_KEYS.reduce((p, k) => (p[k] = options[k], p), {
32 version: pkg.version
33 }));
34 }
35
36 ensureDirExists() {
37 var _this = this;
38
39 return (0, _asyncToGenerator2.default)(function* () {
40 if (_this.dirExists) {
41 return;
42 }
43
44 yield fs.mkdirp(_this.dir); // Create sub-directories for every possible hex value
45 // This speeds up large caches on many file systems since there are fewer files in a single directory.
46
47 for (let i = 0; i < 256; i++) {
48 yield fs.mkdirp(path.join(_this.dir, ('00' + i.toString(16)).slice(-2)));
49 }
50
51 _this.dirExists = true;
52 })();
53 }
54
55 getCacheFile(filename) {
56 let hash = md5(this.optionsHash + filename);
57 return path.join(this.dir, hash.slice(0, 2), hash.slice(2) + '.json');
58 }
59
60 getLastModified(filename) {
61 return (0, _asyncToGenerator2.default)(function* () {
62 if (isGlob(filename)) {
63 let files = yield glob(filename, {
64 onlyFiles: true
65 });
66 return (yield Promise.all(files.map(file => fs.stat(file).then(({
67 mtime
68 }) => mtime.getTime())))).reduce((a, b) => Math.max(a, b), 0);
69 }
70
71 return (yield fs.stat(filename)).mtime.getTime();
72 })();
73 }
74
75 writeDepMtimes(data) {
76 var _this2 = this;
77
78 return (0, _asyncToGenerator2.default)(function* () {
79 // Write mtimes for each dependent file that is already compiled into this asset
80 var _iteratorNormalCompletion = true;
81 var _didIteratorError = false;
82 var _iteratorError = undefined;
83
84 try {
85 for (var _iterator = data.dependencies[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
86 let dep = _step.value;
87
88 if (dep.includedInParent) {
89 dep.mtime = yield _this2.getLastModified(dep.name);
90 }
91 }
92 } catch (err) {
93 _didIteratorError = true;
94 _iteratorError = err;
95 } finally {
96 try {
97 if (!_iteratorNormalCompletion && _iterator.return != null) {
98 _iterator.return();
99 }
100 } finally {
101 if (_didIteratorError) {
102 throw _iteratorError;
103 }
104 }
105 }
106 })();
107 }
108
109 write(filename, data) {
110 var _this3 = this;
111
112 return (0, _asyncToGenerator2.default)(function* () {
113 try {
114 yield _this3.ensureDirExists();
115 yield _this3.writeDepMtimes(data);
116 yield fs.writeFile(_this3.getCacheFile(filename), JSON.stringify(data));
117
118 _this3.invalidated.delete(filename);
119 } catch (err) {
120 logger.error(`Error writing to cache: ${err.message}`);
121 }
122 })();
123 }
124
125 checkDepMtimes(data) {
126 var _this4 = this;
127
128 return (0, _asyncToGenerator2.default)(function* () {
129 // Check mtimes for files that are already compiled into this asset
130 // If any of them changed, invalidate.
131 var _iteratorNormalCompletion2 = true;
132 var _didIteratorError2 = false;
133 var _iteratorError2 = undefined;
134
135 try {
136 for (var _iterator2 = data.dependencies[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
137 let dep = _step2.value;
138
139 if (dep.includedInParent) {
140 if ((yield _this4.getLastModified(dep.name)) > dep.mtime) {
141 return false;
142 }
143 }
144 }
145 } catch (err) {
146 _didIteratorError2 = true;
147 _iteratorError2 = err;
148 } finally {
149 try {
150 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
151 _iterator2.return();
152 }
153 } finally {
154 if (_didIteratorError2) {
155 throw _iteratorError2;
156 }
157 }
158 }
159
160 return true;
161 })();
162 }
163
164 read(filename) {
165 var _this5 = this;
166
167 return (0, _asyncToGenerator2.default)(function* () {
168 if (_this5.invalidated.has(filename)) {
169 return null;
170 }
171
172 let cacheFile = _this5.getCacheFile(filename);
173
174 try {
175 let stats = yield fs.stat(filename);
176 let cacheStats = yield fs.stat(cacheFile);
177
178 if (stats.mtime > cacheStats.mtime) {
179 return null;
180 }
181
182 let json = yield fs.readFile(cacheFile);
183 let data = JSON.parse(json);
184
185 if (!(yield _this5.checkDepMtimes(data))) {
186 return null;
187 }
188
189 return data;
190 } catch (err) {
191 return null;
192 }
193 })();
194 }
195
196 invalidate(filename) {
197 this.invalidated.add(filename);
198 }
199
200 delete(filename) {
201 var _this6 = this;
202
203 return (0, _asyncToGenerator2.default)(function* () {
204 try {
205 yield fs.unlink(_this6.getCacheFile(filename));
206
207 _this6.invalidated.delete(filename);
208 } catch (err) {// Fail silently
209 }
210 })();
211 }
212
213}
214
215module.exports = FSCache;
\No newline at end of file