Skip to content
2 changes: 1 addition & 1 deletion lib/commands/create-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class CreateProjectCommand implements ICommand {
}

this.createdProjectData = await this.$projectService.createProject({
projectName: projectName,
projectName,
template: selectedTemplate,
appId: this.$options.appid,
pathToProject: this.$options.path,
Expand Down
24 changes: 22 additions & 2 deletions lib/controllers/run-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "../common/declarations";
import { IInjector } from "../common/definitions/yok";
import { injector } from "../common/yok";
// import { ISharedEventBus } from "../declarations";

export class RunController extends EventEmitter implements IRunController {
private prepareReadyEventHandler: any = null;
Expand All @@ -47,12 +48,17 @@ export class RunController extends EventEmitter implements IRunController {
private $prepareDataService: IPrepareDataService,
private $prepareNativePlatformService: IPrepareNativePlatformService,
private $projectChangesService: IProjectChangesService,
protected $projectDataService: IProjectDataService
protected $projectDataService: IProjectDataService // private $sharedEventBus: ISharedEventBus
) {
super();
}
currentStartingHash = "";

public async run(runData: IRunData): Promise<void> {
// this.$sharedEventBus.on("lastHashChanged", (v) => {
// this.lastHash = v;
// console.log("lasthashchanged", v);
// });
const { liveSyncInfo, deviceDescriptors } = runData;
const { projectDir } = liveSyncInfo;

Expand Down Expand Up @@ -776,13 +782,27 @@ export class RunController extends EventEmitter implements IRunController {
deviceDescriptor,
fullSyncAction
);
// console.log(`FILESTOSYNC ${filesToSync}`);
const startingHash = this.$hmrStatusService.getStartingHash();

if (
!liveSyncResultInfo.didRecover &&
isInHMRMode &&
filesToSync.some((file) => file.includes("hot-update")) &&
(!startingHash ||
this.currentStartingHash === startingHash ||
startingHash === data.hmrData.hash)
) {
this.currentStartingHash = startingHash;
console.time("hmrStatus");

if (!liveSyncResultInfo.didRecover && isInHMRMode) {
const status = await this.$hmrStatusService.getHmrStatus(
device.deviceInfo.identifier,
data.hmrData.hash
);

console.timeEnd("hmrStatus");

// the timeout is assumed OK as the app could be blocked on a breakpoint
if (status === HmrConstants.HMR_ERROR_STATUS) {
await fullSyncAction();
Expand Down
1 change: 1 addition & 0 deletions lib/definitions/hmr-status-service.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ interface IHmrStatusService {
watchHmrStatus(deviceId: string, operationHash: string): void;
getHmrStatus(deviceId: string, operationHash: string): Promise<number>;
attachToHmrStatusEvent(): void;
getStartingHash(): string;
}
20 changes: 19 additions & 1 deletion lib/services/hmr-status-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class HmrStatusService implements IHmrStatusService {
public static STARTED_MESSAGE = "Checking for updates to the bundle with";
public static SUCCESS_MESSAGE = "Successfully applied update with";
public static FAILED_MESSAGE = "Cannot apply update with";
private startingBundleHash: string;
private hashOperationStatuses: IDictionary<any> = {};
private intervals: IDictionary<any> = {};

Expand All @@ -27,14 +28,24 @@ export class HmrStatusService implements IHmrStatusService {
): Promise<number> {
return new Promise((resolve, reject) => {
const key = `${deviceId}${operationHash}`;

this.$logger.trace("INITIAL CHECKING HASH STATUS", operationHash);
const status = this.getStatusByKey(operationHash);
if (status) {
resolve(status);

return;
}

let retryCount = 40;

this.intervals[key] = setInterval(() => {
this.$logger.trace("CHECKING HASH STATUS", operationHash);
const status = this.getStatusByKey(key);
if (status || retryCount === 0) {
clearInterval(this.intervals[key]);
this.intervals[key] = null;
resolve(status);
resolve(status ?? HmrConstants.HMR_ERROR_STATUS);
} else {
retryCount--;
}
Expand Down Expand Up @@ -75,6 +86,9 @@ export class HmrStatusService implements IHmrStatusService {
regex: /\[HMR]\[(.+)]\s*(\w+)\s*\|/,
handler: (matches: RegExpMatchArray, deviceId: string) => {
const [hash, status] = matches.slice(1);
if (status.trim() === "boot") {
this.startingBundleHash = hash;
}
const mappedStatus = statusStringMap[status.trim()];
if (mappedStatus) {
this.setData(deviceId, hash, statusStringMap[status]);
Expand All @@ -84,6 +98,10 @@ export class HmrStatusService implements IHmrStatusService {
});
}

public getStartingHash() {
return this.startingBundleHash;
}

private handleAppCrash(matches: RegExpMatchArray, deviceId: string): void {
for (const operationId in this.hashOperationStatuses) {
const operation = this.hashOperationStatuses[operationId];
Expand Down
56 changes: 38 additions & 18 deletions lib/services/webpack/webpack-compiler-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export class WebpackCompilerService
private webpackProcesses: IDictionary<child_process.ChildProcess> = {};
private expectedHashes: IStringDictionary = {};

private hashQueue: string[] = [];
private currentCompilationHash: string;

constructor(
private $options: IOptions,
private $errors: IErrors,
Expand All @@ -63,7 +66,7 @@ export class WebpackCompilerService
private $mobileHelper: Mobile.IMobileHelper,
private $cleanupService: ICleanupService,
private $packageManager: IPackageManager,
private $packageInstallationManager: IPackageInstallationManager // private $sharedEventBus: ISharedEventBus
private $packageInstallationManager: IPackageInstallationManager
) {
super();
}
Expand Down Expand Up @@ -97,6 +100,16 @@ export class WebpackCompilerService
"version" in message &&
"type" in message
) {
const currentHash = (message as IWebpackMessage<
IWebpackCompilation
>).hash;
if (
this.hashQueue.length == 0 ||
this.hashQueue[this.hashQueue.length - 1] !== currentHash
) {
this.hashQueue.push(currentHash);
}
this.currentCompilationHash = currentHash;
// first compilation can be ignored because it will be synced regardless
// handling it here would trigger 2 syncs
if (isFirstWebpackWatchCompilation) {
Expand Down Expand Up @@ -504,6 +517,7 @@ export class WebpackCompilerService
}

private getCurrentHotUpdateHash(emittedFiles: string[]) {
// TODO: don't do this. use the hashQueue instead
let hotHash;
const hotUpdateScripts = emittedFiles.filter((x) =>
x.endsWith(".hot-update.js")
Expand All @@ -529,6 +543,7 @@ export class WebpackCompilerService
}
}

lastEmittedHash = "";
private handleHMRMessage(
message: IWebpackMessage,
platformData: IPlatformData,
Expand All @@ -544,7 +559,7 @@ export class WebpackCompilerService

this.$logger.trace("Webpack build done!");

const files = message.data.emittedAssets.map((asset: string) =>
const files: string[] = message.data.emittedAssets.map((asset: string) =>
path.join(platformData.appDestinationDirectoryPath, "app", asset)
);
const staleFiles = message.data.staleAssets.map((asset: string) =>
Expand All @@ -553,33 +568,38 @@ export class WebpackCompilerService

// console.log({ staleFiles });

// extract last hash from emitted filenames
const lastHash = (() => {
const fileWithLastHash = files.find((fileName: string) =>
fileName.endsWith("hot-update.js")
);

if (!fileWithLastHash) {
return null;
}
const matches = fileWithLastHash.match(/\.(.+).hot-update\.js/);

if (matches) {
return matches[1];
}
})();
// grab the next hash that needs to be processed. Fallback to current hash.

if (!files.length) {
// ignore compilations if no new files are emitted
return;
}
// console.log(
// `HANDLE HMR MESSAGE ${this.hashQueue} ${this.currentCompilationHash} ${files}`
// );
let currentIdx = 0;
let lastHash =
this.hashQueue.length > 0
? this.hashQueue[currentIdx]
: this.currentCompilationHash;
while (lastHash !== this.currentCompilationHash) {
if (files.some((f) => f.endsWith(`${lastHash}.hot-update.js`))) {
this.hashQueue.splice(0, currentIdx + 1);
break;
}
currentIdx++;
lastHash =
this.hashQueue.length > currentIdx
? this.hashQueue[currentIdx]
: this.currentCompilationHash;
}

this.emit(WEBPACK_COMPILATION_COMPLETE, {
files,
staleFiles,
hasOnlyHotUpdateFiles: prepareData.hmr,
hmrData: {
hash: lastHash || message.hash,
hash: lastHash,
fallbackFiles: [],
},
platform: platformData.platformNameLowerCase,
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"minimatch": "3.0.4",
"mkdirp": "1.0.4",
"mute-stream": "0.0.8",
"nativescript-dev-xcode": "0.2.1",
"nativescript-dev-xcode": "0.4.0",
"nativescript-preview-sdk": "0.4.2",
"open": "7.1.0",
"ora": "5.0.0",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4926,10 +4926,10 @@
"snapdragon" "^0.8.1"
"to-regex" "^3.0.1"

"nativescript-dev-xcode@0.2.1":
"integrity" "sha512-uzqkcUnEx0YIi6jkz/EvdhkCBoOmv6XL40qoNYnPQpSAHmbHIOduZC2sg3TQJs4nq1vnKz+J6myq7Pmyocm6tw=="
"resolved" "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.2.1.tgz"
"version" "0.2.1"
"nativescript-dev-xcode@0.4.0":
"integrity" "sha512-6pSGJOoFvTd1nNRA6RvBSgXWW5VV4WChhqiAWpLBv46VePwpccPqrAQ0qXvxHk373DwU9GwojQVFa178KVYTBw=="
"resolved" "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.4.0.tgz"
"version" "0.4.0"
dependencies:
"simple-plist" "^1.0.0"
"uuid" "^3.3.2"
Expand Down