source: imaps-frontend/node_modules/babel-loader/lib/cache.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/**
2 * Filesystem Cache
3 *
4 * Given a file and a transform function, cache the result into files
5 * or retrieve the previously cached files if the given file is already known.
6 *
7 * @see https://github.com/babel/babel-loader/issues/34
8 * @see https://github.com/babel/babel-loader/pull/41
9 */
10const os = require("os");
11const path = require("path");
12const zlib = require("zlib");
13const crypto = require("crypto");
14const {
15 promisify
16} = require("util");
17const {
18 readFile,
19 writeFile,
20 mkdir
21} = require("fs/promises");
22const findCacheDirP = import("find-cache-dir");
23const transform = require("./transform");
24// Lazily instantiated when needed
25let defaultCacheDirectory = null;
26let hashType = "sha256";
27// use md5 hashing if sha256 is not available
28try {
29 crypto.createHash(hashType);
30} catch {
31 hashType = "md5";
32}
33const gunzip = promisify(zlib.gunzip);
34const gzip = promisify(zlib.gzip);
35
36/**
37 * Read the contents from the compressed file.
38 *
39 * @async
40 * @params {String} filename
41 * @params {Boolean} compress
42 */
43const read = async function (filename, compress) {
44 const data = await readFile(filename + (compress ? ".gz" : ""));
45 const content = compress ? await gunzip(data) : data;
46 return JSON.parse(content.toString());
47};
48
49/**
50 * Write contents into a compressed file.
51 *
52 * @async
53 * @params {String} filename
54 * @params {Boolean} compress
55 * @params {String} result
56 */
57const write = async function (filename, compress, result) {
58 const content = JSON.stringify(result);
59 const data = compress ? await gzip(content) : content;
60 return await writeFile(filename + (compress ? ".gz" : ""), data);
61};
62
63/**
64 * Build the filename for the cached file
65 *
66 * @params {String} source File source code
67 * @params {Object} options Options used
68 *
69 * @return {String}
70 */
71const filename = function (source, identifier, options) {
72 const hash = crypto.createHash(hashType);
73 const contents = JSON.stringify({
74 source,
75 options,
76 identifier
77 });
78 hash.update(contents);
79 return hash.digest("hex") + ".json";
80};
81
82/**
83 * Handle the cache
84 *
85 * @params {String} directory
86 * @params {Object} params
87 */
88const handleCache = async function (directory, params) {
89 const {
90 source,
91 options = {},
92 cacheIdentifier,
93 cacheDirectory,
94 cacheCompression,
95 logger
96 } = params;
97 const file = path.join(directory, filename(source, cacheIdentifier, options));
98 try {
99 // No errors mean that the file was previously cached
100 // we just need to return it
101 logger.debug(`reading cache file '${file}'`);
102 return await read(file, cacheCompression);
103 } catch {
104 // conitnue if cache can't be read
105 logger.debug(`discarded cache as it can not be read`);
106 }
107 const fallback = typeof cacheDirectory !== "string" && directory !== os.tmpdir();
108
109 // Make sure the directory exists.
110 try {
111 // overwrite directory if exists
112 logger.debug(`creating cache folder '${directory}'`);
113 await mkdir(directory, {
114 recursive: true
115 });
116 } catch (err) {
117 if (fallback) {
118 return handleCache(os.tmpdir(), params);
119 }
120 throw err;
121 }
122
123 // Otherwise just transform the file
124 // return it to the user asap and write it in cache
125 logger.debug(`applying Babel transform`);
126 const result = await transform(source, options);
127
128 // Do not cache if there are external dependencies,
129 // since they might change and we cannot control it.
130 if (!result.externalDependencies.length) {
131 try {
132 logger.debug(`writing result to cache file '${file}'`);
133 await write(file, cacheCompression, result);
134 } catch (err) {
135 if (fallback) {
136 // Fallback to tmpdir if node_modules folder not writable
137 return handleCache(os.tmpdir(), params);
138 }
139 throw err;
140 }
141 }
142 return result;
143};
144
145/**
146 * Retrieve file from cache, or create a new one for future reads
147 *
148 * @async
149 * @param {Object} params
150 * @param {String} params.cacheDirectory Directory to store cached files
151 * @param {String} params.cacheIdentifier Unique identifier to bust cache
152 * @param {Boolean} params.cacheCompression Whether compressing cached files
153 * @param {String} params.source Original contents of the file to be cached
154 * @param {Object} params.options Options to be given to the transform fn
155 *
156 * @example
157 *
158 * const result = await cache({
159 * cacheDirectory: '.tmp/cache',
160 * cacheIdentifier: 'babel-loader-cachefile',
161 * cacheCompression: false,
162 * source: *source code from file*,
163 * options: {
164 * experimental: true,
165 * runtime: true
166 * },
167 * });
168 */
169
170module.exports = async function (params) {
171 let directory;
172 if (typeof params.cacheDirectory === "string") {
173 directory = params.cacheDirectory;
174 } else {
175 if (defaultCacheDirectory === null) {
176 const {
177 default: findCacheDir
178 } = await findCacheDirP;
179 defaultCacheDirectory = findCacheDir({
180 name: "babel-loader"
181 }) || os.tmpdir();
182 }
183 directory = defaultCacheDirectory;
184 }
185 return await handleCache(directory, params);
186};
Note: See TracBrowser for help on using the repository browser.