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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 | 2×
2×
2×
2×
2×
2×
2×
2×
2×
13×
1×
12×
2×
14×
14×
1×
14×
2×
2×
12×
12×
12×
6×
15×
2×
13×
13×
13×
3×
10×
9×
9×
9×
2×
6×
6×
6×
6×
12×
12×
11×
12×
6×
6×
2×
1483×
8×
12×
8×
7×
7×
6×
6×
6×
6×
6×
6×
6×
2×
6×
6×
6×
6×
2×
2×
6×
6×
6×
2×
8×
32×
| import requireHacker from 'require-hacker'
import { browserify, unbrowserify } from 'ethical-utility-browserifier'
import { requireModule, getAppPrefix, isRelativePackage } from 'ethical-utility-resolve-module-node'
import { absolute, relative } from 'ethical-utility-path'
import resolveCSSModule from './resolve-css.js'
import resolveJSModule from './resolve-js.js'
let moduleID = 0
const cache = {}
const resolveModule = (request, parent) => {
if (request.endsWith('.css')) {
return resolveCSSModule(request, parent)
}
return resolveJSModule(request, parent)
}
const resolveCache = (cached, modules, exclude) => {
const { id, key, alias, source, path } = cached
if (typeof require.cache[path + '.*'] === 'object') {
global
.__ethical_server_middleware_module_supplier__
[path] = require.cache[path + '.*'].exports
}
if (exclude[id]) {
const stubbedSource = `
module.exports = (
global.__ethical_server_middleware_module_supplier__['${path}']
)
`
return { source: stubbedSource, path }
}
modules.push(cached)
exclude[id] = 1
return { source, path }
}
const handler = (modules, exclude) => (request, { filename: parent }) => {
if (cache[request]) {
return resolveCache(cache[request], modules, exclude)
}
const resolvedModule = resolveModule(request, parent)
const { key, alias, path, source: getSource } = resolvedModule
if (cache[key]) {
return resolveCache(cache[key], modules, exclude)
}
const source = getSource(path)
const id = moduleID++
cache[key] = { id, key, alias, source, path }
return resolveCache(cache[key], modules, exclude)
}
const captureModules = (exclude) => {
const modules = []
const globalHook = requireHacker.global_hook('*', handler(modules, exclude))
return () => {
const cachedModules = modules.map(cached => {
const { id, key, alias, source, path } = cached
if (typeof require.cache[path + '.*'] === 'object') {
global
.__ethical_server_middleware_module_supplier__
[path] = require.cache[path + '.*'].exports
}
return { id, key, alias, source }
})
globalHook.unmount()
return cachedModules
}
}
const decacheNode = () => {
Object.keys(require.cache).forEach(key => { delete require.cache[key] })
global.__ethical_server_middleware_module_supplier__ = {}
}
const moduleCapturerMiddleware = async (ctx, next, config) => {
if (typeof ctx.response.body !== 'undefined') return await next()
const { main, path = 'module' } = config
if (ctx.request.path !== '/' + path) return await next()
const { request: { query: { entry = absolute(main), exclude = '' } } } = ctx
browserify()
const excluded = {}
exclude.split(',').forEach(id => excluded[id] = 1)
const releaseModules = captureModules(excluded)
try {
requireModule(entry)
} catch (e) {
console.error(e)
}
const modules = releaseModules()
unbrowserify()
const [ mainModule = {} ] = modules
if (main === relative(entry)) {
mainModule.alias = mainModule.key
mainModule.key = getAppPrefix()
}
ctx.response.body = JSON.stringify(modules)
ctx.response.set('Content-Type', 'application/json')
await next()
}
const moduleCapturerMiddlewareInit = (config = {}) => {
decacheNode()
return async (ctx, next) => (
await moduleCapturerMiddleware(ctx, next, config)
)
}
export default moduleCapturerMiddlewareInit
|