/** * Adapted from: https://github.com/elastic/require-in-the-middle */ import Module from 'module' import plugins from './plugins' let bundledModules = { ...plugins, 'tailwindcss/colors': require('tailwindcss/colors'), 'tailwindcss/defaultConfig': require('tailwindcss/defaultConfig'), 'tailwindcss/defaultTheme': require('tailwindcss/defaultTheme'), 'tailwindcss/resolveConfig': require('tailwindcss/resolveConfig'), 'tailwindcss/plugin': require('tailwindcss/plugin'), } export default class Hook { cache = {} deps: string[] = [] private _unhooked: boolean = false private _origRequire = Module.prototype.require private _require: (req: string) => any constructor(find: string, callback: (x) => {}) { // @ts-ignore if (typeof Module._resolveFilename !== 'function') { throw new Error( // @ts-ignore `Error: Expected Module._resolveFilename to be a function (was: ${typeof Module._resolveFilename}) - aborting!` ) } let self = this let patching = {} // @ts-ignore this._require = Module.prototype.require = function (request) { if (self._unhooked) { // if the patched require function could not be removed because // someone else patched it after it was patched here, we just // abort and pass the request onwards to the original require return self._origRequire.apply(this, arguments) } let filename if (bundledModules.hasOwnProperty(request)) { try { // @ts-ignore filename = Module._resolveFilename(request, this) } catch (_) { // if (plugins.hasOwnProperty(request)) { // console.log(`Using bundled version of \`${request}\`: v${plugins[request].version}`) // } return bundledModules[request].module || bundledModules[request] } } else { // @ts-ignore filename = Module._resolveFilename(request, this) } // return known patched modules immediately if (self.cache.hasOwnProperty(filename)) { return self.cache[filename] } // Check if this module has a patcher in-progress already. // Otherwise, mark this module as patching in-progress. let patched = patching[filename] if (!patched) { patching[filename] = true } let exports = self._origRequire.apply(this, arguments) if (filename !== find) { return exports } // If it's already patched, just return it as-is. if (patched) return exports // The module has already been loaded, // so the patching mark can be cleaned up. delete patching[filename] // only call onrequire the first time a module is loaded if (!self.cache.hasOwnProperty(filename)) { // ensure that the cache entry is assigned a value before calling // onrequire, in case calling onrequire requires the same module. self.cache[filename] = exports self.cache[filename] = callback(exports) } return self.cache[filename] } } unhook() { this._unhooked = true if (this._require === Module.prototype.require) { Module.prototype.require = this._origRequire } } }