index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. const path_1 = __importDefault(require("path"));
  6. const virtual_stats_1 = require("./virtual-stats");
  7. let inode = 45000000;
  8. function checkActivation(instance) {
  9. if (!instance._compiler) {
  10. throw new Error('You must use this plugin only after creating webpack instance!');
  11. }
  12. }
  13. function getModulePath(filePath, compiler) {
  14. return path_1.default.isAbsolute(filePath) ? filePath : path_1.default.join(compiler.context, filePath);
  15. }
  16. function createWebpackData(result) {
  17. return (backendOrStorage) => {
  18. if (backendOrStorage._data) {
  19. const curLevelIdx = backendOrStorage._currentLevel;
  20. const curLevel = backendOrStorage._levels[curLevelIdx];
  21. return {
  22. result,
  23. level: curLevel,
  24. };
  25. }
  26. return [null, result];
  27. };
  28. }
  29. function getData(storage, key) {
  30. if (storage._data instanceof Map) {
  31. return storage._data.get(key);
  32. }
  33. else if (storage._data) {
  34. return storage.data[key];
  35. }
  36. else if (storage.data instanceof Map) {
  37. return storage.data.get(key);
  38. }
  39. else {
  40. return storage.data[key];
  41. }
  42. }
  43. function setData(backendOrStorage, key, valueFactory) {
  44. const value = valueFactory(backendOrStorage);
  45. if (backendOrStorage._data instanceof Map) {
  46. backendOrStorage._data.set(key, value);
  47. }
  48. else if (backendOrStorage._data) {
  49. backendOrStorage.data[key] = value;
  50. }
  51. else if (backendOrStorage.data instanceof Map) {
  52. backendOrStorage.data.set(key, value);
  53. }
  54. else {
  55. backendOrStorage.data[key] = value;
  56. }
  57. }
  58. function getStatStorage(fileSystem) {
  59. if (fileSystem._statStorage) {
  60. return fileSystem._statStorage;
  61. }
  62. else if (fileSystem._statBackend) {
  63. return fileSystem._statBackend;
  64. }
  65. else {
  66. throw new Error("Couldn't find a stat storage");
  67. }
  68. }
  69. function getFileStorage(fileSystem) {
  70. if (fileSystem._readFileStorage) {
  71. return fileSystem._readFileStorage;
  72. }
  73. else if (fileSystem._readFileBackend) {
  74. return fileSystem._readFileBackend;
  75. }
  76. else {
  77. throw new Error("Couldn't find a readFileStorage");
  78. }
  79. }
  80. function getReadDirBackend(fileSystem) {
  81. if (fileSystem._readdirBackend) {
  82. return fileSystem._readdirBackend;
  83. }
  84. else if (fileSystem._readdirStorage) {
  85. return fileSystem._readdirStorage;
  86. }
  87. else {
  88. throw new Error("Couldn't find a readDirStorage from Webpack Internals");
  89. }
  90. }
  91. class VirtualModulesPlugin {
  92. constructor(modules) {
  93. this._compiler = null;
  94. this._watcher = null;
  95. this._staticModules = modules || null;
  96. }
  97. writeModule(filePath, contents) {
  98. if (!this._compiler) {
  99. throw new Error(`Plugin has not been initialized`);
  100. }
  101. checkActivation(this);
  102. const len = contents ? contents.length : 0;
  103. const time = Date.now();
  104. const date = new Date(time);
  105. const stats = new virtual_stats_1.VirtualStats({
  106. dev: 8675309,
  107. nlink: 0,
  108. uid: 1000,
  109. gid: 1000,
  110. rdev: 0,
  111. blksize: 4096,
  112. ino: inode++,
  113. mode: 33188,
  114. size: len,
  115. blocks: Math.floor(len / 4096),
  116. atime: date,
  117. mtime: date,
  118. ctime: date,
  119. birthtime: date,
  120. });
  121. const modulePath = getModulePath(filePath, this._compiler);
  122. if (process.env.WVM_DEBUG)
  123. console.log(this._compiler.name, 'Write virtual module:', modulePath, contents);
  124. let finalWatchFileSystem = this._watcher && this._watcher.watchFileSystem;
  125. while (finalWatchFileSystem && finalWatchFileSystem.wfs) {
  126. finalWatchFileSystem = finalWatchFileSystem.wfs;
  127. }
  128. let finalInputFileSystem = this._compiler.inputFileSystem;
  129. while (finalInputFileSystem && finalInputFileSystem._inputFileSystem) {
  130. finalInputFileSystem = finalInputFileSystem._inputFileSystem;
  131. }
  132. finalInputFileSystem._writeVirtualFile(modulePath, stats, contents);
  133. if (finalWatchFileSystem &&
  134. (finalWatchFileSystem.watcher.fileWatchers.size || finalWatchFileSystem.watcher.fileWatchers.length)) {
  135. const fileWatchers = finalWatchFileSystem.watcher.fileWatchers instanceof Map
  136. ? Array.from(finalWatchFileSystem.watcher.fileWatchers.values())
  137. : finalWatchFileSystem.watcher.fileWatchers;
  138. for (let fileWatcher of fileWatchers) {
  139. if ('watcher' in fileWatcher) {
  140. fileWatcher = fileWatcher.watcher;
  141. }
  142. if (fileWatcher.path === modulePath) {
  143. if (process.env.DEBUG)
  144. console.log(this._compiler.name, 'Emit file change:', modulePath, time);
  145. delete fileWatcher.directoryWatcher._cachedTimeInfoEntries;
  146. fileWatcher.emit('change', time, null);
  147. }
  148. }
  149. }
  150. }
  151. apply(compiler) {
  152. this._compiler = compiler;
  153. const afterEnvironmentHook = () => {
  154. let finalInputFileSystem = compiler.inputFileSystem;
  155. while (finalInputFileSystem && finalInputFileSystem._inputFileSystem) {
  156. finalInputFileSystem = finalInputFileSystem._inputFileSystem;
  157. }
  158. if (!finalInputFileSystem._writeVirtualFile) {
  159. const originalPurge = finalInputFileSystem.purge;
  160. finalInputFileSystem.purge = () => {
  161. originalPurge.apply(finalInputFileSystem, []);
  162. if (finalInputFileSystem._virtualFiles) {
  163. Object.keys(finalInputFileSystem._virtualFiles).forEach((file) => {
  164. const data = finalInputFileSystem._virtualFiles[file];
  165. finalInputFileSystem._writeVirtualFile(file, data.stats, data.contents);
  166. });
  167. }
  168. };
  169. finalInputFileSystem._writeVirtualFile = (file, stats, contents) => {
  170. const statStorage = getStatStorage(finalInputFileSystem);
  171. const fileStorage = getFileStorage(finalInputFileSystem);
  172. const readDirStorage = getReadDirBackend(finalInputFileSystem);
  173. finalInputFileSystem._virtualFiles = finalInputFileSystem._virtualFiles || {};
  174. finalInputFileSystem._virtualFiles[file] = { stats: stats, contents: contents };
  175. setData(statStorage, file, createWebpackData(stats));
  176. setData(fileStorage, file, createWebpackData(contents));
  177. const segments = file.split(/[\\/]/);
  178. let count = segments.length - 1;
  179. const minCount = segments[0] ? 1 : 0;
  180. while (count > minCount) {
  181. const dir = segments.slice(0, count).join(path_1.default.sep) || path_1.default.sep;
  182. try {
  183. finalInputFileSystem.readdirSync(dir);
  184. }
  185. catch (e) {
  186. const time = Date.now();
  187. const dirStats = new virtual_stats_1.VirtualStats({
  188. dev: 8675309,
  189. nlink: 0,
  190. uid: 1000,
  191. gid: 1000,
  192. rdev: 0,
  193. blksize: 4096,
  194. ino: inode++,
  195. mode: 16877,
  196. size: stats.size,
  197. blocks: Math.floor(stats.size / 4096),
  198. atime: time,
  199. mtime: time,
  200. ctime: time,
  201. birthtime: time,
  202. });
  203. setData(readDirStorage, dir, createWebpackData([]));
  204. setData(statStorage, dir, createWebpackData(dirStats));
  205. }
  206. let dirData = getData(getReadDirBackend(finalInputFileSystem), dir);
  207. dirData = dirData[1] || dirData.result;
  208. const filename = segments[count];
  209. if (dirData.indexOf(filename) < 0) {
  210. const files = dirData.concat([filename]).sort();
  211. setData(getReadDirBackend(finalInputFileSystem), dir, createWebpackData(files));
  212. }
  213. else {
  214. break;
  215. }
  216. count--;
  217. }
  218. };
  219. }
  220. };
  221. const afterResolversHook = () => {
  222. if (this._staticModules) {
  223. for (const [filePath, contents] of Object.entries(this._staticModules)) {
  224. this.writeModule(filePath, contents);
  225. }
  226. this._staticModules = null;
  227. }
  228. };
  229. const version = typeof compiler.webpack === 'undefined' ? 4 : 5;
  230. const watchRunHook = (watcher, callback) => {
  231. this._watcher = watcher.compiler || watcher;
  232. const virtualFiles = compiler.inputFileSystem._virtualFiles;
  233. const fts = compiler.fileTimestamps;
  234. if (virtualFiles && fts && typeof fts.set === 'function') {
  235. Object.keys(virtualFiles).forEach((file) => {
  236. const mtime = +virtualFiles[file].stats.mtime;
  237. fts.set(file, version === 4
  238. ? mtime
  239. : {
  240. safeTime: mtime,
  241. timestamp: mtime,
  242. });
  243. });
  244. }
  245. callback();
  246. };
  247. if (compiler.hooks) {
  248. compiler.hooks.afterEnvironment.tap('VirtualModulesPlugin', afterEnvironmentHook);
  249. compiler.hooks.afterResolvers.tap('VirtualModulesPlugin', afterResolversHook);
  250. compiler.hooks.watchRun.tapAsync('VirtualModulesPlugin', watchRunHook);
  251. }
  252. else {
  253. compiler.plugin('after-environment', afterEnvironmentHook);
  254. compiler.plugin('after-resolvers', afterResolversHook);
  255. compiler.plugin('watch-run', watchRunHook);
  256. }
  257. }
  258. }
  259. module.exports = VirtualModulesPlugin;
  260. //# sourceMappingURL=index.js.map