-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
112 lines (103 loc) · 3.7 KB
/
index.js
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
'use strict'
if (typeof Proxy !== 'function' && typeof Reflect !== 'object') {
console.error('Error: your current Node.js not support Proxy or Reflect!')
process.exit()
}
if (process.env.NODE_ENV === 'production') {
console.warn('Warning: proxy-hot-reload should not be used in production environment!')
}
const Module = require('module')
const _ = require('lodash')
const glob = require('glob')
const shimmer = require('shimmer')
const chokidar = require('chokidar')
const debug = require('debug')('proxy-hot-reload')
const debugDetail = require('debug')('proxy-hot-reload:detail')
const globOpt = {
nodir: true,
absolute: true
}
module.exports = function proxyHotReload (opts) {
opts = opts || {}
const includes = opts.includeFiles || glob.sync(process.env.PROXY_HOT_RELOAD_INCLUDES || opts.includes || '**/*.js', globOpt) || []
const excludes = opts.excludeFiles || glob.sync(process.env.PROXY_HOT_RELOAD_EXCLUDES || opts.excludes || '**/node_modules/**', globOpt) || []
const watchedFileChangedButNotReloadCache = opts.watchedFileChangedButNotReloadCache || function (filename) {
debug(`${filename} changed, but not reload cache!`)
}
const watchFiles = _.difference(includes, excludes)
const loadedFiles = Object.create(null)
chokidar
.watch(watchFiles, {
usePolling: true
})
.on('change', (path) => {
try {
if (require.cache[path]) {
const _exports = require.cache[path].exports
if (_.isPlainObject(_exports) && !_.isEmpty(_exports)) {
delete require.cache[path]
require(path)
if (path in loadedFiles) {
debug('Reload file: %s', path)
}
} else {
watchedFileChangedButNotReloadCache(path)
}
} else {
watchedFileChangedButNotReloadCache(path)
}
} catch (e) {
console.error('proxy-hot-reload reload `%s` error:', path)
console.error(e.stack)
}
})
.on('error', (error) => console.error(error))
shimmer.wrap(Module.prototype, '_compile', function (__compile) {
return function proxyHotReloadCompile (content, filename) {
if (!_.includes(watchFiles, filename)) {
try {
return __compile.call(this, content, filename)
} catch (e) {
console.error('proxy-hot-reload cannot compile file: %s', filename)
console.error(e.stack)
throw e
}
} else {
const result = __compile.call(this, content, filename)
this._exports = this.exports
// non-object return original compiled code
if (!_.isPlainObject(this._exports)) {
return result
}
if (!(filename in loadedFiles)) {
loadedFiles[filename] = true
debug('Watch file: %j', filename)
}
try {
// try to wrap with Proxy
this.exports = new Proxy(this._exports, {
get: function (target, key, receiver) {
try {
if (require.cache[filename]) {
debugDetail('Get `%s` from require.cache[%s]', key, filename)
return require.cache[filename]._exports[key]
} else {
debugDetail('Get `%s` from original %s', key, filename)
return Reflect.get(target, key, receiver)
}
} catch (e) {
console.error('proxy-hot-reload get `%s` from `%s` error:', key, filename)
console.error(e.stack)
throw e
}
}
})
} catch (e) {
console.error('proxy-hot-reload wrap `%s` with Proxy error:', filename)
console.error(e.stack)
}
return result
}
}
})
}