123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const asyncLib = require("async");
  7. class CachePlugin {
  8. constructor(cache) {
  9. this.cache = cache || {};
  10. this.FS_ACCURENCY = 2000;
  11. }
  12. apply(compiler) {
  13. if(Array.isArray(compiler.compilers)) {
  14. compiler.compilers.forEach((c, idx) => {
  15. c.apply(new CachePlugin(this.cache[idx] = this.cache[idx] || {}));
  16. });
  17. } else {
  18. const registerCacheToCompiler = (compiler, cache) => {
  19. compiler.plugin("this-compilation", compilation => {
  20. // TODO remove notCacheable for webpack 4
  21. if(!compilation.notCacheable) {
  22. compilation.cache = cache;
  23. compilation.plugin("child-compiler", (childCompiler, compilerName, compilerIndex) => {
  24. if(cache) {
  25. let childCache;
  26. if(!cache.children) cache.children = {};
  27. if(!cache.children[compilerName]) cache.children[compilerName] = [];
  28. if(cache.children[compilerName][compilerIndex])
  29. childCache = cache.children[compilerName][compilerIndex];
  30. else
  31. cache.children[compilerName].push(childCache = {});
  32. registerCacheToCompiler(childCompiler, childCache);
  33. }
  34. });
  35. } else if(this.watching) {
  36. compilation.warnings.push(
  37. new Error(`CachePlugin - Cache cannot be used because of: ${compilation.notCacheable}`)
  38. );
  39. }
  40. });
  41. };
  42. registerCacheToCompiler(compiler, this.cache);
  43. compiler.plugin("watch-run", (compiler, callback) => {
  44. this.watching = true;
  45. callback();
  46. });
  47. compiler.plugin("run", (compiler, callback) => {
  48. if(!compiler._lastCompilationFileDependencies) return callback();
  49. const fs = compiler.inputFileSystem;
  50. const fileTs = compiler.fileTimestamps = {};
  51. asyncLib.forEach(compiler._lastCompilationFileDependencies, (file, callback) => {
  52. fs.stat(file, (err, stat) => {
  53. if(err) {
  54. if(err.code === "ENOENT") return callback();
  55. return callback(err);
  56. }
  57. if(stat.mtime)
  58. this.applyMtime(+stat.mtime);
  59. fileTs[file] = +stat.mtime || Infinity;
  60. callback();
  61. });
  62. }, err => {
  63. if(err) return callback(err);
  64. Object.keys(fileTs).forEach(key => {
  65. fileTs[key] += this.FS_ACCURENCY;
  66. });
  67. callback();
  68. });
  69. });
  70. compiler.plugin("after-compile", function(compilation, callback) {
  71. compilation.compiler._lastCompilationFileDependencies = compilation.fileDependencies;
  72. compilation.compiler._lastCompilationContextDependencies = compilation.contextDependencies;
  73. callback();
  74. });
  75. }
  76. }
  77. /* istanbul ignore next */
  78. applyMtime(mtime) {
  79. if(this.FS_ACCURENCY > 1 && mtime % 2 !== 0)
  80. this.FS_ACCURENCY = 1;
  81. else if(this.FS_ACCURENCY > 10 && mtime % 20 !== 0)
  82. this.FS_ACCURENCY = 10;
  83. else if(this.FS_ACCURENCY > 100 && mtime % 200 !== 0)
  84. this.FS_ACCURENCY = 100;
  85. else if(this.FS_ACCURENCY > 1000 && mtime % 2000 !== 0)
  86. this.FS_ACCURENCY = 1000;
  87. }
  88. }
  89. module.exports = CachePlugin;