UNPKG

4.06 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.cache = void 0;
4/**
5 * Filesystem Cache
6 *
7 * Given a file and a transform function, cache the result into files
8 * or retrieve the previously cached files if the given file is already known.
9 *
10 * @see https://github.com/babel/babel-loader/
11 */
12const fs = require("fs");
13const os = require("os");
14const path = require("path");
15const zlib = require("zlib");
16const crypto = require("crypto");
17const findCacheDir = require("find-cache-dir");
18const makeDir = require("make-dir");
19const util_1 = require("util");
20const _1 = require(".");
21// Lazily instantiated when needed
22let defaultCacheDirectory = null;
23const readFile = (0, util_1.promisify)(fs.readFile);
24const writeFile = (0, util_1.promisify)(fs.writeFile);
25const gunzip = (0, util_1.promisify)(zlib.gunzip);
26const gzip = (0, util_1.promisify)(zlib.gzip);
27/**
28 * Read the contents from the compressed file.
29 *
30 * @async
31 * @params {String} filename
32 * @params {Boolean} compress
33 */
34const read = async function (filename, compress) {
35 const data = await readFile(filename + (compress ? ".gz" : ""));
36 const content = compress ? await gunzip(data) : data;
37 return JSON.parse(content.toString());
38};
39/**
40 * Write contents into a compressed file.
41 *
42 * @async
43 * @params {String} filename
44 * @params {Boolean} compress
45 * @params {String} result
46 */
47const write = async function (filename, compress, result) {
48 const content = JSON.stringify(result);
49 const data = compress ? await gzip(content) : content;
50 return await writeFile(filename + (compress ? ".gz" : ""), data);
51};
52/**
53 * Build the filename for the cached file
54 *
55 * @params {String} source File source code
56 * @params {Object} options Options used
57 *
58 * @return {String}
59 */
60const filename = function (source, identifier) {
61 const hash = crypto.createHash("md4");
62 const contents = JSON.stringify({ source, identifier });
63 hash.update(contents);
64 return hash.digest("hex") + ".json";
65};
66/**
67 * Handle the cache
68 *
69 * @params {String} directory
70 * @params {Object} params
71 */
72const handleCache = async function (directory, cacheOptions, params) {
73 const { cacheIdentifier, cacheDirectory, cacheCompression } = cacheOptions;
74 const file = path.join(directory, filename(params.resourcePath, cacheIdentifier));
75 try {
76 // No errors mean that the file was previously cached
77 // we just need to return it
78 return await read(file, cacheCompression);
79 }
80 catch (err) {
81 // continue regardless of error
82 }
83 const fallback = typeof cacheDirectory !== "string" && directory !== os.tmpdir();
84 // Make sure the directory exists.
85 try {
86 await makeDir(directory);
87 }
88 catch (err) {
89 if (fallback) {
90 return handleCache(os.tmpdir(), cacheOptions, params);
91 }
92 throw err;
93 }
94 // Otherwise just transform the file
95 // return it to the user asap and write it in cache
96 const result = await (0, _1.transform)(params);
97 try {
98 await write(file, cacheCompression, result);
99 }
100 catch (err) {
101 if (fallback) {
102 // Fallback to tmpdir if node_modules folder not writable
103 return handleCache(os.tmpdir(), cacheOptions, params);
104 }
105 throw err;
106 }
107 return result;
108};
109/**
110 * Retrieve file from cache, or create a new one for future reads
111 *
112 * @async
113 * @param {CacheOptions} cacheOptions
114 * @param {TransformParams} transformParams Options to be given to the transform fn
115 *
116 */
117async function cache(cacheOptions, transformParams) {
118 let directory;
119 if (typeof cacheOptions.cacheDirectory === "string") {
120 directory = cacheOptions.cacheDirectory;
121 }
122 else {
123 if (defaultCacheDirectory === null) {
124 defaultCacheDirectory = findCacheDir({ name: "responsive-loader" }) || os.tmpdir();
125 }
126 directory = defaultCacheDirectory;
127 }
128 return await handleCache(directory, cacheOptions, transformParams);
129}
130exports.cache = cache;