Skip to content

fix: persist the next hmr hash per platform #5086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions lib/services/webpack/webpack-compiler-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { WEBPACK_COMPILATION_COMPLETE, WEBPACK_PLUGIN_NAME } from "../../constan

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

constructor(
private $errors: IErrors,
Expand Down Expand Up @@ -42,14 +42,14 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
if (message.emittedFiles) {
if (isFirstWebpackWatchCompilation) {
isFirstWebpackWatchCompilation = false;
this.expectedHash = message.hash;
this.expectedHashes[platformData.platformNameLowerCase] = message.hash;
return;
}

let result;

if (prepareData.hmr) {
result = this.getUpdatedEmittedFiles(message.emittedFiles, message.chunkFiles, message.hash);
result = this.getUpdatedEmittedFiles(message.emittedFiles, message.chunkFiles, message.hash, platformData.platformNameLowerCase);
} else {
result = { emittedFiles: message.emittedFiles, fallbackFiles: <string[]>[], hash: "" };
}
Expand Down Expand Up @@ -248,7 +248,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
return args;
}

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

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

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

Expand Down
37 changes: 27 additions & 10 deletions test/services/webpack/webpack-compiler-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Yok } from "../../../lib/common/yok";
import { WebpackCompilerService } from "../../../lib/services/webpack/webpack-compiler-service";
import { assert } from "chai";

const iOSPlatformName = "ios";
const androidPlatformName = "android";
const chunkFiles = ["bundle.js", "runtime.js", "vendor.js"];

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

assert.deepEqual(result.emittedFiles, expectedEmittedFiles);
});
// 2 successful webpack compilations
it("should return only hot updates when nextHash is provided", async () => {
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2");
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash2"), chunkFiles, "hash3");
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
const result = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash2"), chunkFiles, "hash3", iOSPlatformName);

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

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

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

assert.deepEqual(result.emittedFiles, ["bundle.hash1.hot-update.js", "hash1.hot-update.json"]);
});
it("should return correct hashes when there are more than one platform", () => {
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash1"), chunkFiles, "hash2", iOSPlatformName);
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash3"), chunkFiles, "hash4", androidPlatformName);

webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash2"), chunkFiles, "hash5", iOSPlatformName);
webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash4"), chunkFiles, "hash6", androidPlatformName);

const iOSResult = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash5"), chunkFiles, "hash7", iOSPlatformName);
assert.deepEqual(iOSResult.emittedFiles, ["bundle.hash5.hot-update.js", "hash5.hot-update.json"]);

const androidResult = webpackCompilerService.getUpdatedEmittedFiles(getAllEmittedFiles("hash6"), chunkFiles, "hash8", androidPlatformName);
assert.deepEqual(androidResult.emittedFiles, ["bundle.hash6.hot-update.js", "hash6.hot-update.json"]);
});
});
});