| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 | "use strict";Object.defineProperty(exports, "__esModule", {  value: true});exports.default = loader;exports.pitch = pitch;/* eslint-disable  import/order*/const fs = require('fs');const path = require('path');const normalizePath = require('normalize-path');const async = require('neo-async');const crypto = require('crypto');const mkdirp = require('mkdirp');const {  getOptions} = require('loader-utils');const validateOptions = require('schema-utils');const pkg = require('../package.json');const env = process.env.NODE_ENV || 'development';const schema = require('./options.json');const defaults = {  cacheContext: '',  cacheDirectory: path.resolve('.cache-loader'),  cacheIdentifier: `cache-loader:${pkg.version} ${env}`,  cacheKey,  read,  write};function pathWithCacheContext(cacheContext, originalPath) {  if (!cacheContext) {    return originalPath;  }  if (originalPath.includes(cacheContext)) {    return originalPath.split('!').map(subPath => normalizePath(path.relative(cacheContext, subPath))).join('!');  }  return originalPath.split('!').map(subPath => normalizePath(path.resolve(cacheContext, subPath))).join('!');}function loader(...args) {  const options = Object.assign({}, defaults, getOptions(this));  validateOptions(schema, options, 'Cache Loader');  const {    write: writeFn  } = options;  const callback = this.async();  const {    data  } = this;  const dependencies = this.getDependencies().concat(this.loaders.map(l => l.path));  const contextDependencies = this.getContextDependencies(); // Should the file get cached?  let cache = true; // this.fs can be undefined  // e.g when using the thread-loader  // fallback to the fs module  const FS = this.fs || fs;  const toDepDetails = (dep, mapCallback) => {    FS.stat(dep, (err, stats) => {      if (err) {        mapCallback(err);        return;      }      const mtime = stats.mtime.getTime();      if (mtime / 1000 >= Math.floor(data.startTime / 1000)) {        // Don't trust mtime.        // File was changed while compiling        // or it could be an inaccurate filesystem.        cache = false;      }      mapCallback(null, {        path: pathWithCacheContext(options.cacheContext, dep),        mtime      });    });  };  async.parallel([cb => async.mapLimit(dependencies, 20, toDepDetails, cb), cb => async.mapLimit(contextDependencies, 20, toDepDetails, cb)], (err, taskResults) => {    if (err) {      callback(null, ...args);      return;    }    if (!cache) {      callback(null, ...args);      return;    }    const [deps, contextDeps] = taskResults;    writeFn(data.cacheKey, {      remainingRequest: data.remainingRequest,      dependencies: deps,      contextDependencies: contextDeps,      result: args    }, () => {      // ignore errors here      callback(null, ...args);    });  });}function pitch(remainingRequest, prevRequest, dataInput) {  const options = Object.assign({}, defaults, getOptions(this));  validateOptions(schema, options, 'Cache Loader (Pitch)');  const {    read: readFn,    cacheContext,    cacheKey: cacheKeyFn  } = options;  const callback = this.async();  const data = dataInput;  data.remainingRequest = pathWithCacheContext(cacheContext, remainingRequest);  data.cacheKey = cacheKeyFn(options, data.remainingRequest);  readFn(data.cacheKey, (readErr, cacheData) => {    if (readErr) {      callback();      return;    }    if (cacheData.remainingRequest !== data.remainingRequest) {      // in case of a hash conflict      callback();      return;    }    const FS = this.fs || fs;    async.each(cacheData.dependencies.concat(cacheData.contextDependencies), (dep, eachCallback) => {      FS.stat(dep.path, (statErr, stats) => {        if (statErr) {          eachCallback(statErr);          return;        }        if (stats.mtime.getTime() !== dep.mtime) {          eachCallback(true);          return;        }        eachCallback();      });    }, err => {      if (err) {        data.startTime = Date.now();        callback();        return;      }      cacheData.dependencies.forEach(dep => this.addDependency(pathWithCacheContext(cacheContext, dep.path)));      cacheData.contextDependencies.forEach(dep => this.addContextDependency(pathWithCacheContext(cacheContext, dep.path)));      callback(null, ...cacheData.result);    });  });}function digest(str) {  return crypto.createHash('md5').update(str).digest('hex');}const directories = new Set();function write(key, data, callback) {  const dirname = path.dirname(key);  const content = JSON.stringify(data);  if (directories.has(dirname)) {    // for performance skip creating directory    fs.writeFile(key, content, 'utf-8', callback);  } else {    mkdirp(dirname, mkdirErr => {      if (mkdirErr) {        callback(mkdirErr);        return;      }      directories.add(dirname);      fs.writeFile(key, content, 'utf-8', callback);    });  }}function read(key, callback) {  fs.readFile(key, 'utf-8', (err, content) => {    if (err) {      callback(err);      return;    }    try {      const data = JSON.parse(content);      callback(null, data);    } catch (e) {      callback(e);    }  });}function cacheKey(options, request) {  const {    cacheIdentifier,    cacheDirectory  } = options;  const hash = digest(`${cacheIdentifier}\n${request}`);  return path.join(cacheDirectory, `${hash}.json`);}
 |