Skip to content

Commit 647b0f6

Browse files
committed
fix: persist the next hmr hash per platform
The NativeScript CLI persists the hash of the next hmr compilation locally and based on that decides if the reported hash is valid or not. However, in case when `tns run` command is executed, the application is randomly restarted on some devices. This happens as in this situation we have 2 webpack processes but the hmr hash is not persisted per platform. Rel to: #5080
1 parent e85406e commit 647b0f6

File tree

2 files changed

+33
-16
lines changed

2 files changed

+33
-16
lines changed

lib/services/webpack/webpack-compiler-service.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { WEBPACK_COMPILATION_COMPLETE, WEBPACK_PLUGIN_NAME } from "../../constan
77

88
export class WebpackCompilerService extends EventEmitter implements IWebpackCompilerService {
99
private webpackProcesses: IDictionary<child_process.ChildProcess> = {};
10-
private expectedHash: string = null;
10+
private expectedHashes: IStringDictionary = {};
1111

1212
constructor(
1313
private $errors: IErrors,
@@ -42,14 +42,14 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
4242
if (message.emittedFiles) {
4343
if (isFirstWebpackWatchCompilation) {
4444
isFirstWebpackWatchCompilation = false;
45-
this.expectedHash = message.hash;
45+
this.expectedHashes[platformData.platformNameLowerCase] = message.hash;
4646
return;
4747
}
4848

4949
let result;
5050

5151
if (prepareData.hmr) {
52-
result = this.getUpdatedEmittedFiles(message.emittedFiles, message.chunkFiles, message.hash);
52+
result = this.getUpdatedEmittedFiles(message.emittedFiles, message.chunkFiles, message.hash, platformData.platformNameLowerCase);
5353
} else {
5454
result = { emittedFiles: message.emittedFiles, fallbackFiles: <string[]>[], hash: "" };
5555
}
@@ -248,7 +248,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
248248
return args;
249249
}
250250

251-
public getUpdatedEmittedFiles(allEmittedFiles: string[], chunkFiles: string[], nextHash: string) {
251+
public getUpdatedEmittedFiles(allEmittedFiles: string[], chunkFiles: string[], nextHash: string, platform: string) {
252252
const currentHash = this.getCurrentHotUpdateHash(allEmittedFiles);
253253

254254
// This logic is needed as there are already cases when webpack doesn't emit any files physically.
@@ -260,8 +260,8 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
260260
// if files will be emitted or not. This way, the first successful compilation after fixing the compilation error generates
261261
// a hash that is not the same as the one expected in the latest emitted hot-update.json file.
262262
// As a result, the hmr chain is broken and the changes are not applied.
263-
const isHashValid = nextHash ? this.expectedHash === currentHash : true;
264-
this.expectedHash = nextHash;
263+
const isHashValid = nextHash ? this.expectedHashes[platform] === currentHash : true;
264+
this.expectedHashes[platform] = nextHash;
265265

266266
const emittedHotUpdatesAndAssets = isHashValid ? _.difference(allEmittedFiles, chunkFiles) : allEmittedFiles;
267267

test/services/webpack/webpack-compiler-service.ts

+27-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Yok } from "../../../lib/common/yok";
22
import { WebpackCompilerService } from "../../../lib/services/webpack/webpack-compiler-service";
33
import { assert } from "chai";
44

5+
const iOSPlatformName = "ios";
6+
const androidPlatformName = "android";
57
const chunkFiles = ["bundle.js", "runtime.js", "vendor.js"];
68

79
function getAllEmittedFiles(hash: string) {
@@ -35,39 +37,54 @@ describe("WebpackCompilerService", () => {
3537
describe("getUpdatedEmittedFiles", () => {
3638
// backwards compatibility with old versions of nativescript-dev-webpack
3739
it("should return only hot updates when nextHash is not provided", async () => {
38-
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, null);
40+
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, null, iOSPlatformName);
3941
const expectedEmittedFiles = ['bundle.hash1.hot-update.js', 'hash1.hot-update.json'];
4042

4143
assert.deepEqual(result.emittedFiles, expectedEmittedFiles);
4244
});
4345
// 2 successful webpack compilations
4446
it("should return only hot updates when nextHash is provided", async () => {
45-
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2");
46-
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash2"), chunkFiles, "hash3");
47+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
48+
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash2"), chunkFiles, "hash3", iOSPlatformName);
4749

4850
assert.deepEqual(result.emittedFiles, ['bundle.hash2.hot-update.js', 'hash2.hot-update.json']);
4951
});
5052
// 1 successful webpack compilation, n compilations with no emitted files
5153
it("should return all files when there is a webpack compilation with no emitted files", () => {
52-
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2");
53-
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash4"), chunkFiles, "hash5");
54+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
55+
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash4"), chunkFiles, "hash5", iOSPlatformName);
5456

5557
assert.deepEqual(result.emittedFiles, ['bundle.js', 'runtime.js', 'bundle.hash4.hot-update.js', 'hash4.hot-update.json']);
5658
});
5759
// 1 successful webpack compilation, n compilations with no emitted files, 1 successful webpack compilation
5860
it("should return only hot updates after fixing the compilation error", () => {
59-
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2");
60-
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash5"), chunkFiles, "hash6");
61-
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash6"), chunkFiles, "hash7");
61+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
62+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash5"), chunkFiles, "hash6", iOSPlatformName);
63+
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash6"), chunkFiles, "hash7", iOSPlatformName);
6264

6365
assert.deepEqual(result.emittedFiles, ['bundle.hash6.hot-update.js', 'hash6.hot-update.json']);
6466
});
6567
// 1 webpack compilation with no emitted files
6668
it("should return all files when first compilation on livesync change is not successful", () => {
67-
(<any>webpackCompilerService).expectedHash = "hash1";
68-
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2");
69+
(<any>webpackCompilerService).expectedHashes = {
70+
"ios": "hash1"
71+
};
72+
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
6973

7074
assert.deepEqual(result.emittedFiles, ["bundle.hash1.hot-update.js", "hash1.hot-update.json"]);
7175
});
76+
it("should return correct hashes when there are more than one platform", () => {
77+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
78+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash3"), chunkFiles, "hash4", androidPlatformName);
79+
80+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash2"), chunkFiles, "hash5", iOSPlatformName);
81+
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash4"), chunkFiles, "hash6", androidPlatformName);
82+
83+
const iOSResult = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash5"), chunkFiles, "hash7", iOSPlatformName);
84+
assert.deepEqual(iOSResult.emittedFiles, ["bundle.hash5.hot-update.js", "hash5.hot-update.json"]);
85+
86+
const androidResult = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash6"), chunkFiles, "hash8", androidPlatformName);
87+
assert.deepEqual(androidResult.emittedFiles, ["bundle.hash6.hot-update.js", "hash6.hot-update.json"]);
88+
});
7289
});
7390
});

0 commit comments

Comments
 (0)