UNPKG

5.49 kBJavaScriptView Raw
1const hmrPrefix = 'HMR:';
2const log = {
3 info: (message) => console.info(`${hmrPrefix} ${message}`),
4 warn: (message) => console.warn(`${hmrPrefix} ${message}`),
5 error: (message) => console.error(`${hmrPrefix} ${message}`),
6};
7const refresh = 'Application needs to be restarted in order to apply the changes.';
8const hotOptions = {
9 ignoreUnaccepted: false,
10 ignoreDeclined: false,
11 ignoreErrored: false,
12 onUnaccepted(data) {
13 const chain = [].concat(data.chain);
14 const last = chain[chain.length - 1];
15
16 if (last === 0) {
17 chain.pop();
18 }
19
20 log.warn(`Ignored an update to unaccepted module: `);
21 chain.forEach(mod => log.warn(` ➭ ${mod}`));
22 },
23 onDeclined(data) {
24 log.warn(`Ignored an update to declined module:`);
25 data.chain.forEach(mod => log.warn(` ➭ ${mod}`));
26 },
27 onErrored(data) {
28 log.warn(
29 `Ignored an error while updating module ${data.moduleId} <${data.type}>`
30 );
31 log.warn(data.error);
32 },
33};
34
35let nextHash;
36let currentHash;
37
38function upToDate() {
39 return nextHash.indexOf(__webpack_hash__) >= 0;
40}
41
42function result(modules, appliedModules) {
43 const unaccepted = modules.filter(
44 (moduleId) => appliedModules && appliedModules.indexOf(moduleId) < 0
45 );
46
47 if (unaccepted.length > 0) {
48 log.warn('The following modules could not be updated:');
49
50 for (const moduleId of unaccepted) {
51 log.warn(` ⦻ ${moduleId}`);
52 }
53 }
54
55 if (!(appliedModules || []).length) {
56 log.info('No Modules Updated.');
57 } else {
58 log.info('The following modules were updated:');
59
60 for (const moduleId of appliedModules) {
61 log.info(` ↻ ${moduleId}`);
62 }
63
64 const numberIds = appliedModules.every(
65 (moduleId) => typeof moduleId === 'number'
66 );
67 if (numberIds) {
68 log.info(
69 'Please consider using the NamedModulesPlugin for module names.'
70 );
71 }
72 }
73}
74
75function check(options) {
76 return module.hot
77 .check()
78 .then((modules) => {
79 if (!modules) {
80 log.warn(
81 `Cannot find update. ${refresh}`
82 );
83 return null;
84 }
85
86 return module.hot
87 .apply(hotOptions)
88 .then((appliedModules) => {
89 let nextCheck;
90 if (!upToDate()) {
91 nextCheck = check(options);
92 }
93
94 result(modules, appliedModules);
95
96 if (upToDate()) {
97 // Do not modify message - CLI depends on this exact content to determine hmr operation status.
98 log.info(`Successfully applied update with hmr hash ${currentHash}. App is up to date.`);
99 }
100
101 return nextCheck || null;
102 })
103 .catch((err) => {
104 const status = module.hot.status();
105 if (['abort', 'fail'].indexOf(status) >= 0) {
106 // Do not modify message - CLI depends on this exact content to determine hmr operation status.
107 log.error(`Cannot apply update with hmr hash ${currentHash}.`);
108 log.error(err.message || err.stack);
109 } else {
110 log.error(`Update failed: ${err.message || err.stack}`);
111 }
112 });
113 })
114 .catch((err) => {
115 const status = module.hot.status();
116 if (['abort', 'fail'].indexOf(status) >= 0) {
117 log.error(`Cannot check for update. ${refresh}`);
118 log.error(err.message || err.stack);
119 } else {
120 log.error(`Update check failed: ${err.message || err.stack}`);
121 }
122 });
123}
124
125if (module.hot) {
126 log.info('Hot Module Replacement Enabled. Waiting for signal.');
127} else {
128 log.error('Hot Module Replacement is disabled.');
129}
130
131function update(latestHash, options) {
132 nextHash = latestHash;
133 if (!upToDate()) {
134 const status = module.hot.status();
135
136 if (status === 'idle') {
137 //Do not modify message - CLI depends on this exact content to determine hmr operation status.
138 log.info(`Checking for updates to the bundle with hmr hash ${currentHash}.`);
139 return check(options);
140 } else if (['abort', 'fail'].indexOf(status) >= 0) {
141 log.warn(
142 `Cannot apply update. A previous update ${status}ed. ${refresh}`
143 );
144 }
145 }
146};
147
148function getNextHash(hash, getFileContent) {
149 const file = getFileContent(`${hash}.hot-update.json`);
150 return file.readText().then(hotUpdateContent => {
151 if (hotUpdateContent) {
152 const manifest = JSON.parse(hotUpdateContent);
153 const newHash = manifest.h;
154 return getNextHash(newHash, getFileContent);
155 } else {
156 return Promise.resolve(hash);
157 }
158 }).catch(error => Promise.reject(error));
159}
160
161module.exports = function checkState(initialHash, getFileContent) {
162 currentHash = initialHash;
163 return getNextHash(initialHash, getFileContent).then(nextHash => {
164 if (nextHash != initialHash) {
165 return update(nextHash, {});
166 }
167 })
168}