diff --git a/lib/commands/create-project.ts b/lib/commands/create-project.ts index c7ad65e82c..0304f44db5 100644 --- a/lib/commands/create-project.ts +++ b/lib/commands/create-project.ts @@ -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, diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index 62c07915ea..28613c70ac 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -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; @@ -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 { + // this.$sharedEventBus.on("lastHashChanged", (v) => { + // this.lastHash = v; + // console.log("lasthashchanged", v); + // }); const { liveSyncInfo, deviceDescriptors } = runData; const { projectDir } = liveSyncInfo; @@ -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(); diff --git a/lib/definitions/hmr-status-service.d.ts b/lib/definitions/hmr-status-service.d.ts index ca78363518..e2a6e1d946 100644 --- a/lib/definitions/hmr-status-service.d.ts +++ b/lib/definitions/hmr-status-service.d.ts @@ -2,4 +2,5 @@ interface IHmrStatusService { watchHmrStatus(deviceId: string, operationHash: string): void; getHmrStatus(deviceId: string, operationHash: string): Promise; attachToHmrStatusEvent(): void; + getStartingHash(): string; } diff --git a/lib/services/hmr-status-service.ts b/lib/services/hmr-status-service.ts index 288dcabd86..16325f0be8 100644 --- a/lib/services/hmr-status-service.ts +++ b/lib/services/hmr-status-service.ts @@ -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 = {}; private intervals: IDictionary = {}; @@ -27,14 +28,24 @@ export class HmrStatusService implements IHmrStatusService { ): Promise { 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--; } @@ -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]); @@ -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]; diff --git a/lib/services/webpack/webpack-compiler-service.ts b/lib/services/webpack/webpack-compiler-service.ts index 85118b5b6d..f25373ed22 100644 --- a/lib/services/webpack/webpack-compiler-service.ts +++ b/lib/services/webpack/webpack-compiler-service.ts @@ -52,6 +52,9 @@ export class WebpackCompilerService private webpackProcesses: IDictionary = {}; private expectedHashes: IStringDictionary = {}; + private hashQueue: string[] = []; + private currentCompilationHash: string; + constructor( private $options: IOptions, private $errors: IErrors, @@ -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(); } @@ -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) { @@ -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") @@ -529,6 +543,7 @@ export class WebpackCompilerService } } + lastEmittedHash = ""; private handleHMRMessage( message: IWebpackMessage, platformData: IPlatformData, @@ -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) => @@ -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, diff --git a/package-lock.json b/package-lock.json index b78910b3e6..7dda22acb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,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", @@ -8784,9 +8784,9 @@ } }, "node_modules/nativescript-dev-xcode": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.2.1.tgz", - "integrity": "sha512-uzqkcUnEx0YIi6jkz/EvdhkCBoOmv6XL40qoNYnPQpSAHmbHIOduZC2sg3TQJs4nq1vnKz+J6myq7Pmyocm6tw==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.4.0.tgz", + "integrity": "sha512-6pSGJOoFvTd1nNRA6RvBSgXWW5VV4WChhqiAWpLBv46VePwpccPqrAQ0qXvxHk373DwU9GwojQVFa178KVYTBw==", "dependencies": { "simple-plist": "^1.0.0", "uuid": "^3.3.2" @@ -20040,9 +20040,9 @@ } }, "nativescript-dev-xcode": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.2.1.tgz", - "integrity": "sha512-uzqkcUnEx0YIi6jkz/EvdhkCBoOmv6XL40qoNYnPQpSAHmbHIOduZC2sg3TQJs4nq1vnKz+J6myq7Pmyocm6tw==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.4.0.tgz", + "integrity": "sha512-6pSGJOoFvTd1nNRA6RvBSgXWW5VV4WChhqiAWpLBv46VePwpccPqrAQ0qXvxHk373DwU9GwojQVFa178KVYTBw==", "requires": { "simple-plist": "^1.0.0", "uuid": "^3.3.2" diff --git a/package.json b/package.json index a24844e1ea..ef0f1713bb 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/yarn.lock b/yarn.lock index fb036e6eac..a2ea3760a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"