1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/**
* 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) => {} = (x) => 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
}
}
}
|