diff --git a/lib/controllers/build-controller.ts b/lib/controllers/build-controller.ts index a5e0bbf2f2..fc94dab0fa 100644 --- a/lib/controllers/build-controller.ts +++ b/lib/controllers/build-controller.ts @@ -87,12 +87,8 @@ export class BuildController extends EventEmitter implements IBuildController { const projectData = this.$projectDataService.getProjectData(buildData.projectDir); const platformData = this.$platformsDataService.getPlatformData(buildData.platform, projectData); const outputPath = buildData.outputPath || platformData.getBuildOutputPath(buildData); - - if (buildData.release && this.$projectChangesService.currentChanges.hasChanges) { - return true; - } - const changesInfo = this.$projectChangesService.currentChanges || await this.$projectChangesService.checkForChanges(platformData, projectData, buildData); + if (changesInfo.changesRequireBuild) { return true; } diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index 1237555a06..bb46da92e5 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -4,6 +4,8 @@ import { cache, performanceLog } from "../common/decorators"; import { EventEmitter } from "events"; export class RunController extends EventEmitter implements IRunController { + private prepareReadyEventHandler: any = null; + constructor( protected $analyticsService: IAnalyticsService, private $buildController: IBuildController, @@ -23,6 +25,7 @@ export class RunController extends EventEmitter implements IRunController { private $prepareController: IPrepareController, private $prepareDataService: IPrepareDataService, private $prepareNativePlatformService: IPrepareNativePlatformService, + private $projectChangesService: IProjectChangesService, protected $projectDataService: IProjectDataService ) { super(); @@ -45,9 +48,21 @@ export class RunController extends EventEmitter implements IRunController { this.$hmrStatusService.attachToHmrStatusEvent(); } - this.$prepareController.on(PREPARE_READY_EVENT_NAME, async data => { - await this.syncChangedDataOnDevices(data, projectData, liveSyncInfo, deviceDescriptors); - }); + if (!this.prepareReadyEventHandler) { + this.prepareReadyEventHandler = async (data: IFilesChangeEventData) => { + if (data.hasNativeChanges) { + const platformData = this.$platformsDataService.getPlatformData(data.platform, projectData); + const prepareData = this.$prepareDataService.getPrepareData(liveSyncInfo.projectDir, data.platform, { ...liveSyncInfo, watch: !liveSyncInfo.skipWatcher }); + const changesInfo = await this.$projectChangesService.checkForChanges(platformData, projectData, prepareData); + if (changesInfo.hasChanges) { + await this.syncChangedDataOnDevices(data, projectData, liveSyncInfo); + } + } else { + await this.syncChangedDataOnDevices(data, projectData, liveSyncInfo); + } + }; + this.$prepareController.on(PREPARE_READY_EVENT_NAME, this.prepareReadyEventHandler.bind(this)); + } await this.syncInitialDataOnDevices(projectData, liveSyncInfo, deviceDescriptorsForInitialSync); @@ -58,6 +73,7 @@ export class RunController extends EventEmitter implements IRunController { const { projectDir, deviceIdentifiers, stopOptions } = data; const liveSyncProcessInfo = this.$liveSyncProcessDataService.getPersistedData(projectDir); if (liveSyncProcessInfo && !liveSyncProcessInfo.isStopped) { + // In case we are coming from error during livesync, the current action is the one that erred (but we are still executing it), // so we cannot await it as this will cause infinite loop. const shouldAwaitPendingOperation = !stopOptions || stopOptions.shouldAwaitAllActions; @@ -94,6 +110,11 @@ export class RunController extends EventEmitter implements IRunController { liveSyncProcessInfo.deviceDescriptors = []; + if (this.prepareReadyEventHandler) { + this.removeListener(PREPARE_READY_EVENT_NAME, this.prepareReadyEventHandler); + this.prepareReadyEventHandler = null; + } + const projectData = this.$projectDataService.getProjectData(projectDir); await this.$hooksService.executeAfterHooks('watch', { hookArgs: { @@ -313,10 +334,11 @@ export class RunController extends EventEmitter implements IRunController { await this.addActionToChain(projectData.projectDir, () => this.$devicesService.execute(deviceAction, (device: Mobile.IDevice) => _.some(deviceDescriptors, deviceDescriptor => deviceDescriptor.identifier === device.deviceInfo.identifier))); } - private async syncChangedDataOnDevices(data: IFilesChangeEventData, projectData: IProjectData, liveSyncInfo: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceDescriptor[]): Promise { + private async syncChangedDataOnDevices(data: IFilesChangeEventData, projectData: IProjectData, liveSyncInfo: ILiveSyncInfo): Promise { const rebuiltInformation: IDictionary<{ packageFilePath: string, platform: string, isEmulator: boolean }> = { }; const deviceAction = async (device: Mobile.IDevice) => { + const deviceDescriptors = this.$liveSyncProcessDataService.getDeviceDescriptors(projectData.projectDir); const deviceDescriptor = _.find(deviceDescriptors, dd => dd.identifier === device.deviceInfo.identifier); const platformData = this.$platformsDataService.getPlatformData(data.platform, projectData); const prepareData = this.$prepareDataService.getPrepareData(liveSyncInfo.projectDir, device.deviceInfo.platform, diff --git a/lib/services/platform/prepare-native-platform-service.ts b/lib/services/platform/prepare-native-platform-service.ts index 6b3549cb3f..1a9276beee 100644 --- a/lib/services/platform/prepare-native-platform-service.ts +++ b/lib/services/platform/prepare-native-platform-service.ts @@ -15,12 +15,11 @@ export class PrepareNativePlatformService implements IPrepareNativePlatformServi @hook('prepareNativeApp') public async prepareNativePlatform(platformData: IPlatformData, projectData: IProjectData, prepareData: IPrepareData): Promise { const { nativePrepare, release } = prepareData; + const changesInfo = await this.$projectChangesService.checkForChanges(platformData, projectData, prepareData); if (nativePrepare && nativePrepare.skipNativePrepare) { - return false; + return changesInfo.hasChanges; } - const changesInfo = await this.$projectChangesService.checkForChanges(platformData, projectData, prepareData); - const hasNativeModulesChange = !changesInfo || changesInfo.nativeChanged; const hasConfigChange = !changesInfo || changesInfo.configChanged; const hasChangesRequirePrepare = !changesInfo || changesInfo.changesRequirePrepare;