1
- import { Device , FilesPayload } from "nativescript-preview-sdk" ;
2
1
import { TrackActionNames , PREPARE_READY_EVENT_NAME } from "../constants" ;
3
2
import { PrepareController } from "./prepare-controller" ;
3
+ import { Device , FilesPayload } from "nativescript-preview-sdk" ;
4
4
import { performanceLog } from "../common/decorators" ;
5
- import { stringify } from "../common/helpers" ;
5
+ import { stringify , deferPromise } from "../common/helpers" ;
6
6
import { HmrConstants } from "../common/constants" ;
7
7
import { EventEmitter } from "events" ;
8
8
import { PrepareDataService } from "../services/prepare-data-service" ;
@@ -11,7 +11,9 @@ import { PreviewAppLiveSyncEvents } from "../services/livesync/playground/previe
11
11
export class PreviewAppController extends EventEmitter implements IPreviewAppController {
12
12
private prepareReadyEventHandler : any = null ;
13
13
private deviceInitializationPromise : IDictionary < boolean > = { } ;
14
- private promise = Promise . resolve ( ) ;
14
+ private devicesLiveSyncChain : IDictionary < Promise < void > > = { } ;
15
+ private devicesCanExecuteHmr : IDictionary < boolean > = { } ;
16
+ private devicesHmrFiles : IDictionary < string [ ] > = { } ;
15
17
16
18
constructor (
17
19
private $analyticsService : IAnalyticsService ,
@@ -89,6 +91,7 @@ export class PreviewAppController extends EventEmitter implements IPreviewAppCon
89
91
90
92
if ( data . useHotModuleReload ) {
91
93
this . $hmrStatusService . attachToHmrStatusEvent ( ) ;
94
+ this . devicesCanExecuteHmr [ device . id ] = true ;
92
95
}
93
96
94
97
await this . $previewAppPluginsService . comparePluginsOnDevice ( data , device ) ;
@@ -129,28 +132,63 @@ export class PreviewAppController extends EventEmitter implements IPreviewAppCon
129
132
130
133
@performanceLog ( )
131
134
private async handlePrepareReadyEvent ( data : IPreviewAppLiveSyncData , currentPrepareData : IFilesChangeEventData ) {
132
- await this . promise
133
- . then ( async ( ) => {
134
- const { hmrData, files, platform } = currentPrepareData ;
135
- const platformHmrData = _ . cloneDeep ( hmrData ) ;
135
+ const { hmrData, files, platform } = currentPrepareData ;
136
+ const platformHmrData = _ . cloneDeep ( hmrData ) ;
137
+ const connectedDevices = this . $previewDevicesService . getDevicesForPlatform ( platform ) ;
138
+ if ( ! connectedDevices || ! connectedDevices . length ) {
139
+ this . $logger . warn ( "Unable to find any connected devices. In order to execute live sync, open your Preview app and optionally re-scan the QR code using the Playground app." ) ;
140
+ return ;
141
+ }
136
142
137
- this . promise = this . syncFilesForPlatformSafe ( data , { filesToSync : files } , platform ) ;
138
- await this . promise ;
143
+ await Promise . all ( _ . map ( connectedDevices , async ( device ) => {
144
+ const previousSync = this . devicesLiveSyncChain [ device . id ] || Promise . resolve ( ) ;
145
+ const currentSyncDeferPromise = deferPromise < void > ( ) ;
146
+ this . devicesLiveSyncChain [ device . id ] = currentSyncDeferPromise . promise ;
147
+ this . devicesHmrFiles [ device . id ] = this . devicesHmrFiles [ device . id ] || [ ] ;
148
+ this . devicesHmrFiles [ device . id ] . push ( ...files ) ;
149
+ await previousSync ;
150
+ if ( ! this . devicesHmrFiles [ device . id ] || ! this . devicesHmrFiles [ device . id ] . length ) {
151
+ this . $logger . info ( "Skipping files sync. The changes are already batch transferred in a previous sync." ) ;
152
+ currentSyncDeferPromise . resolve ( ) ;
153
+ return ;
154
+ }
139
155
156
+ try {
157
+ let executeHmrSync = false ;
140
158
if ( data . useHotModuleReload && platformHmrData . hash ) {
141
- const devices = this . $previewDevicesService . getDevicesForPlatform ( platform ) ;
142
-
143
- await Promise . all ( _ . map ( devices , async ( previewDevice : Device ) => {
144
- const status = await this . $hmrStatusService . getHmrStatus ( previewDevice . id , platformHmrData . hash ) ;
145
- if ( status === HmrConstants . HMR_ERROR_STATUS ) {
146
- const originalUseHotModuleReload = data . useHotModuleReload ;
147
- data . useHotModuleReload = false ;
148
- await this . syncFilesForPlatformSafe ( data , { filesToSync : platformHmrData . fallbackFiles } , platform , previewDevice . id ) ;
149
- data . useHotModuleReload = originalUseHotModuleReload ;
150
- }
151
- } ) ) ;
159
+ if ( this . devicesCanExecuteHmr [ device . id ] ) {
160
+ executeHmrSync = true ;
161
+ this . $hmrStatusService . watchHmrStatus ( device . id , platformHmrData . hash ) ;
162
+ }
152
163
}
153
- } ) ;
164
+
165
+ const filesToSync = executeHmrSync ? this . devicesHmrFiles [ device . id ] : platformHmrData . fallbackFiles ;
166
+ this . devicesHmrFiles [ device . id ] = [ ] ;
167
+ if ( executeHmrSync ) {
168
+ await this . syncFilesForPlatformSafe ( data , { filesToSync } , platform , device ) ;
169
+ const status = await this . $hmrStatusService . getHmrStatus ( device . id , platformHmrData . hash ) ;
170
+ if ( ! status ) {
171
+ this . devicesCanExecuteHmr [ device . id ] = false ;
172
+ const noStatusWarning = this . getDeviceMsg ( device . name ,
173
+ "Unable to get LiveSync status from the Preview app. Ensure the app is running in order to sync changes." ) ;
174
+ this . $logger . warn ( noStatusWarning ) ;
175
+ } else {
176
+ this . devicesCanExecuteHmr [ device . id ] = status === HmrConstants . HMR_SUCCESS_STATUS ;
177
+ }
178
+ } else {
179
+ const noHmrData = _ . assign ( { } , data , { useHotModuleReload : false } ) ;
180
+ await this . syncFilesForPlatformSafe ( noHmrData , { filesToSync } , platform , device ) ;
181
+ this . devicesCanExecuteHmr [ device . id ] = true ;
182
+ }
183
+ currentSyncDeferPromise . resolve ( ) ;
184
+ } catch ( e ) {
185
+ currentSyncDeferPromise . resolve ( ) ;
186
+ }
187
+ } ) ) ;
188
+ }
189
+
190
+ private getDeviceMsg ( deviceId : string , message : string ) {
191
+ return `[${ deviceId } ] ${ message } ` ;
154
192
}
155
193
156
194
private async getInitialFilesForPlatformSafe ( data : IPreviewAppLiveSyncData , platform : string ) : Promise < FilesPayload > {
@@ -165,16 +203,21 @@ export class PreviewAppController extends EventEmitter implements IPreviewAppCon
165
203
}
166
204
}
167
205
168
- private async syncFilesForPlatformSafe ( data : IPreviewAppLiveSyncData , filesData : IPreviewAppFilesData , platform : string , deviceId ?: string ) : Promise < void > {
206
+ private async syncFilesForPlatformSafe ( data : IPreviewAppLiveSyncData , filesData : IPreviewAppFilesData , platform : string , device ?: Device ) : Promise < void > {
207
+ const targetType = device ? "device" : "platform" ;
208
+ const targetValue = device ? device . name : platform ;
209
+ const deviceId = device && device . id || "" ;
210
+
169
211
try {
170
212
const payloads = this . $previewAppFilesService . getFilesPayload ( data , filesData , platform ) ;
213
+ payloads . deviceId = deviceId ;
171
214
if ( payloads && payloads . files && payloads . files . length ) {
172
- this . $logger . info ( `Start syncing changes for platform ${ platform } .` ) ;
215
+ this . $logger . info ( `Start syncing changes for ${ targetType } ${ targetValue } .` ) ;
173
216
await this . $previewSdkService . applyChanges ( payloads ) ;
174
- this . $logger . info ( `Successfully synced ${ payloads . files . map ( filePayload => filePayload . file . yellow ) } for platform ${ platform } .` ) ;
217
+ this . $logger . info ( `Successfully synced ${ payloads . files . map ( filePayload => filePayload . file . yellow ) } for ${ targetType } ${ targetValue } .` ) ;
175
218
}
176
219
} catch ( error ) {
177
- this . $logger . warn ( `Unable to apply changes for platform ${ platform } . Error is: ${ error } , ${ JSON . stringify ( error , null , 2 ) } .` ) ;
220
+ this . $logger . warn ( `Unable to apply changes for ${ targetType } ${ targetValue } . Error is: ${ error } , ${ JSON . stringify ( error , null , 2 ) } .` ) ;
178
221
this . emit ( PreviewAppLiveSyncEvents . PREVIEW_APP_LIVE_SYNC_ERROR , {
179
222
error,
180
223
data,
0 commit comments