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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
'use strict';
const ParserHelpers = require('webpack/lib/ParserHelpers');
const stringify = require('json-stringify-safe');
const strip = require('strip-ansi');
const uuid = require('uuid/v4');
const webpack = require('webpack');
function addEntry(entry, compilerName) {
const clientEntry = [`webpack-hot-client/client?${compilerName || uuid()}`];
let newEntry = {};
if (!Array.isArray(entry) && typeof entry === 'object') {
const [first] = Object.keys(entry);
newEntry[first] = clientEntry.concat(entry[first]);
} else {
newEntry = clientEntry.concat(entry);
}
return newEntry;
}
function hotEntry(compiler) {
if (compiler.options.target !== process.env.WHC_TARGET) {
return;
}
const { entry } = compiler.options;
const { name } = compiler;
let newEntry;
if (typeof entry === 'function') {
newEntry = function enter(...args) {
// the entry result from the original entry function in the config
let result = entry(...args);
validateEntry(result);
result = addEntry(result, name);
return result;
};
} else {
newEntry = addEntry(entry, name);
}
compiler.hooks.entryOption.call(compiler.options.context, newEntry);
}
function hotPlugin(compiler) {
const hmrPlugin = new webpack.HotModuleReplacementPlugin();
/* istanbul ignore next */
compiler.hooks.compilation.tap('HotModuleReplacementPlugin', (compilation, {
normalModuleFactory
}) => {
const handler = (parser) => {
parser.hooks.evaluateIdentifier.for('module.hot').tap({
name: 'HotModuleReplacementPlugin',
before: 'NodeStuffPlugin'
}, expr => ParserHelpers.evaluateToIdentifier('module.hot', !!parser.state.compilation.hotUpdateChunkTemplate)(expr));
};
normalModuleFactory.hooks.parser.for('javascript/auto').tap('HotModuleReplacementPlugin', handler);
normalModuleFactory.hooks.parser.for('javascript/dynamic').tap('HotModuleReplacementPlugin', handler);
});
hmrPlugin.apply(compiler);
}
function validateEntry(entry) {
const type = typeof entry;
const isArray = Array.isArray(entry);
if (type !== 'function') {
if (!isArray && type !== 'object') {
throw new TypeError('webpack-hot-client: The value of `entry` must be an Array, Object, or Function. Please check your webpack config.');
}
if (!isArray && type === 'object') {
for (const key of Object.keys(entry)) {
const value = entry[key];
if (!Array.isArray(value)) {
throw new TypeError('webpack-hot-client: `entry` Object values must be an Array or Function. Please check your webpack config.');
}
}
}
}
}
module.exports = {
modifyCompiler(compiler, options) {
// this is how we pass the options at runtime to the client script
const definePlugin = new webpack.DefinePlugin({
__hotClientOptions__: stringify(options)
});
for (const comp of [].concat(compiler.compilers || compiler)) {
hotEntry(comp);
options.log.debug('Applying DefinePlugin:__hotClientOptions__');
definePlugin.apply(comp);
hotPlugin(comp);
}
},
payload(type, data) {
return stringify({ type, data });
},
sendData(broadcast, stats, options) {
const send = (type, data) => {
broadcast(module.exports.payload(type, data));
};
if (stats.errors && stats.errors.length > 0) {
if (options.send.errors) {
const errors = [].concat(stats.errors).map(error => strip(error));
send('errors', { errors });
}
return;
}
/* istanbul ignore if */
if (stats.assets && stats.assets.every(asset => !asset.emitted)) {
send('no-change');
return;
}
const { hash, warnings } = stats;
send('hash', { hash });
if (warnings.length > 0) {
if (options.send.warnings) {
send('warnings', { warnings });
}
} else {
send('ok');
}
},
validateCompiler(compiler) {
for (const comp of [].concat(compiler.compilers || compiler)) {
const { entry } = comp.options;
validateEntry(entry);
}
}
};
|