Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.

Commit 47e63f1

Browse files
KristianDDsis0k0
authored andcommitted
feat: send data for fallback if hmr apply fails (#687)
There is a hash added for start, success or fail of the hmr operation and there are properties in the hookArgs which are populated with information about current hmr operation.
1 parent 5e8f0dc commit 47e63f1

File tree

4 files changed

+78
-64
lines changed

4 files changed

+78
-64
lines changed

hot.js

+23-22
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ const log = {
66
};
77
const refresh = 'Application needs to be restarted in order to apply the changes.';
88
const hotOptions = {
9-
ignoreUnaccepted: true,
10-
ignoreDeclined: true,
11-
ignoreErrored: true,
9+
ignoreUnaccepted: false,
10+
ignoreDeclined: false,
11+
ignoreErrored: false,
1212
onUnaccepted(data) {
1313
const chain = [].concat(data.chain);
1414
const last = chain[chain.length - 1];
@@ -30,10 +30,11 @@ const hotOptions = {
3030
},
3131
};
3232

33-
let lastHash;
33+
let nextHash;
34+
let currentHash;
3435

3536
function upToDate() {
36-
return lastHash.indexOf(__webpack_hash__) >= 0;
37+
return nextHash.indexOf(__webpack_hash__) >= 0;
3738
}
3839

3940
function result(modules, appliedModules) {
@@ -90,17 +91,16 @@ function check(options) {
9091
result(modules, appliedModules);
9192

9293
if (upToDate()) {
93-
log.info('App is up to date.');
94+
//Do not modify message - CLI depends on this exact content to determine hmr operation status.
95+
log.info(`Successfully applied update with hmr hash ${currentHash}. App is up to date.`);
9496
}
9597
})
9698
.catch((err) => {
9799
const status = module.hot.status();
98100
if (['abort', 'fail'].indexOf(status) >= 0) {
99-
log.warn(`Cannot apply update. ${refresh}`);
101+
//Do not modify message - CLI depends on this exact content to determine hmr operation status.
102+
log.warn(`Cannot apply update with hmr hash ${currentHash}.`);
100103
log.warn(err.stack || err.message);
101-
if (options.reload) {
102-
window.location.reload();
103-
}
104104
} else {
105105
log.warn(`Update failed: ${err.stack || err.message}`);
106106
}
@@ -123,13 +123,14 @@ if (module.hot) {
123123
log.error('Hot Module Replacement is disabled.');
124124
}
125125

126-
function update(currentHash, options) {
127-
lastHash = currentHash;
126+
function update(latestHash, options) {
127+
nextHash = latestHash;
128128
if (!upToDate()) {
129129
const status = module.hot.status();
130130

131131
if (status === 'idle') {
132-
log.info('Checking for updates to the bundle.');
132+
//Do not modify message - CLI depends on this exact content to determine hmr operation status.
133+
log.info(`Checking for updates to the bundle with hmr hash ${currentHash}.`);
133134
check(options);
134135
} else if (['abort', 'fail'].indexOf(status) >= 0) {
135136
log.warn(
@@ -139,24 +140,24 @@ function update(currentHash, options) {
139140
}
140141
};
141142

142-
function getCurrentHash(currentHash, getFileContent) {
143-
const file = getFileContent(`${currentHash}.hot-update.json`);
143+
function getNextHash(hash, getFileContent) {
144+
const file = getFileContent(`${hash}.hot-update.json`);
144145
return file.readText().then(hotUpdateContent => {
145146
if(hotUpdateContent) {
146147
const manifest = JSON.parse(hotUpdateContent);
147148
const newHash = manifest.h;
148-
return getCurrentHash(newHash, getFileContent);
149+
return getNextHash(newHash, getFileContent);
149150
} else {
150-
return Promise.resolve(currentHash);
151+
return Promise.resolve(hash);
151152
}
152153
}).catch(error => Promise.reject(error));
153154
}
154155

155156
module.exports = function checkState(initialHash, getFileContent) {
156-
getCurrentHash(initialHash, getFileContent).then(currentHash => {
157-
if(currentHash != initialHash) {
158-
update(currentHash, {});
157+
currentHash = initialHash;
158+
getNextHash(initialHash, getFileContent).then(nextHash => {
159+
if(nextHash != initialHash) {
160+
update(nextHash, {});
159161
}
160162
})
161-
}
162-
163+
}

lib/compiler.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const { existsSync } = require("fs");
55
const readline = require("readline");
66

77
const { messages } = require("../plugins/WatchStateLoggerPlugin");
8-
const { buildEnvData, debuggingEnabled } = require("./utils");
8+
const { buildEnvData, debuggingEnabled, getUpdatedEmittedFiles } = require("./utils");
99

1010
let hasBeenInvoked = false;
1111

@@ -80,11 +80,18 @@ exports.runWebpackCompiler = function runWebpackCompiler(config, $projectData, $
8080
return;
8181
}
8282

83+
const result = getUpdatedEmittedFiles(message.emittedFiles);
84+
85+
if (hookArgs.hmrData && hookArgs.hmrData.fallbackFiles) {
86+
hookArgs.hmrData.fallbackFiles[platform] = result.fallbackFiles;
87+
hookArgs.hmrData.hash = result.hash || "";
88+
}
89+
8390
if (hookArgs.filesToSyncMap && hookArgs.startSyncFilesTimeout) {
84-
hookArgs.filesToSyncMap[platform] = message.emittedFiles;
91+
hookArgs.filesToSyncMap[platform] = result.emittedFiles;
8592
hookArgs.startSyncFilesTimeout(platform);
8693
} else if (hookArgs.filesToSync && hookArgs.startSyncFilesTimeout) {
87-
hookArgs.filesToSync.push(...message.emittedFiles);
94+
hookArgs.filesToSync.push(...result.emittedFiles);
8895
hookArgs.startSyncFilesTimeout(platform);
8996
}
9097
}

lib/utils.js

+43-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,46 @@ function buildEnvData($projectData, platform, env) {
2929
return envData;
3030
}
3131

32+
/**
33+
* Checks if there's a file in the following pattern 5e0326f3bb50f9f26cf0.hot-update.json
34+
* if yes this is a HMR update and remove all bundle files as we don't need them to be synced,
35+
* but only the update chunks
36+
*/
37+
function getUpdatedEmittedFiles(emittedFiles) {
38+
let fallbackFiles = [];
39+
let hotHash;
40+
if (emittedFiles.some(x => x.endsWith('.hot-update.json'))) {
41+
let result = emittedFiles.slice();
42+
const hotUpdateScripts = emittedFiles.filter(x => x.endsWith('.hot-update.js'));
43+
hotUpdateScripts.forEach(hotUpdateScript => {
44+
const { name, hash } = parseHotUpdateChunkName(hotUpdateScript);
45+
hotHash = hash;
46+
// remove bundle/vendor.js files if there's a bundle.XXX.hot-update.js or vendor.XXX.hot-update.js
47+
result = result.filter(file => file !== `${name}.js`);
48+
});
49+
//if applying of hot update fails, we must fallback to the full files
50+
fallbackFiles = emittedFiles.filter(file => result.indexOf(file) === -1);
51+
return { emittedFiles: result, fallbackFiles, hash: hotHash };
52+
}
53+
else {
54+
return { emittedFiles, fallbackFiles };
55+
}
56+
}
57+
58+
/**
59+
* Parse the filename of the hot update chunk.
60+
* @param name bundle.deccb264c01d6d42416c.hot-update.js
61+
* @returns { name: string, hash: string } { name: 'bundle', hash: 'deccb264c01d6d42416c' }
62+
*/
63+
function parseHotUpdateChunkName(name) {
64+
const matcher = /^(.+)\.(.+)\.hot-update/gm;
65+
const matches = matcher.exec(name);
66+
return {
67+
name: matches[1] || "",
68+
hash: matches[2] || "",
69+
};
70+
}
71+
3272
function shouldSnapshot(config) {
3373
const platformSupportsSnapshot = isAndroid(config.platform);
3474
const osSupportsSnapshot = os.type() !== "Windows_NT";
@@ -39,5 +79,7 @@ function shouldSnapshot(config) {
3979
module.exports = {
4080
buildEnvData,
4181
debuggingEnabled,
42-
shouldSnapshot
82+
shouldSnapshot,
83+
getUpdatedEmittedFiles,
84+
parseHotUpdateChunkName
4385
};

plugins/WatchStateLoggerPlugin.ts

+2-38
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { join } from "path";
22
import { writeFileSync, readFileSync } from "fs";
3+
const utils = require("../lib/utils");
34

45
export enum messages {
56
compilationComplete = "Webpack compilation complete.",
@@ -40,8 +41,6 @@ export class WatchStateLoggerPlugin {
4041
WatchStateLoggerPlugin.rewriteHotUpdateChunk(compiler, compilation, emittedFiles);
4142
}
4243

43-
emittedFiles = WatchStateLoggerPlugin.getUpdatedEmittedFiles(emittedFiles);
44-
4544
// provide fake paths to the {N} CLI - relative to the 'app' folder
4645
// in order to trigger the livesync process
4746
const emittedFilesFakePaths = emittedFiles
@@ -64,7 +63,7 @@ export class WatchStateLoggerPlugin {
6463
return;
6564
}
6665

67-
const { name } = this.parseHotUpdateChunkName(chunk);
66+
const { name } = utils.parseHotUpdateChunkName(chunk);
6867
if (!name) {
6968
return;
7069
}
@@ -92,26 +91,6 @@ export class WatchStateLoggerPlugin {
9291
return content.substring(startIndex, endIndex);
9392
}
9493

95-
/**
96-
* Checks if there's a file in the following pattern 5e0326f3bb50f9f26cf0.hot-update.json
97-
* if yes this is a HMR update and remove all bundle files as we don't need them to be synced,
98-
* but only the update chunks
99-
*/
100-
static getUpdatedEmittedFiles(emittedFiles) {
101-
if(emittedFiles.some(x => x.endsWith('.hot-update.json'))) {
102-
let result = emittedFiles.slice();
103-
const hotUpdateScripts = emittedFiles.filter(x => x.endsWith('.hot-update.js'));
104-
hotUpdateScripts.forEach(hotUpdateScript => {
105-
const { name } = this.parseHotUpdateChunkName(hotUpdateScript);
106-
// remove bundle/vendor.js files if there's a bundle.XXX.hot-update.js or vendor.XXX.hot-update.js
107-
result = result.filter(file => file !== `${name}.js`);
108-
});
109-
return result;
110-
} else {
111-
return emittedFiles;
112-
}
113-
}
114-
11594
/**
11695
* Gets the webpackHotUpdate call with updated modules not to include the ones with errors
11796
*/
@@ -130,19 +109,4 @@ export class WatchStateLoggerPlugin {
130109
}
131110
webpackHotUpdate('${moduleName}', filter(${updatedModules}, ${JSON.stringify(errorModuleIds)}));`;
132111
}
133-
134-
/**
135-
* Parse the filename of the hot update chunk.
136-
* @param name bundle.deccb264c01d6d42416c.hot-update.js
137-
* @returns { name: string, hash: string } { name: 'bundle', hash: 'deccb264c01d6d42416c' }
138-
*/
139-
private static parseHotUpdateChunkName(name) {
140-
const matcher = /^(.+)\.(.+)\.hot-update/gm;
141-
const matches = matcher.exec(name);
142-
143-
return {
144-
name: matches[1] || "",
145-
hash: matches[2] || "",
146-
};
147-
}
148112
}

0 commit comments

Comments
 (0)