1
1
import * as path from "path" ;
2
- import { FilePayload , Device , FilesPayload } from "nativescript-preview-sdk" ;
3
- import { PreviewSdkEventNames } from "./preview-app-constants" ;
4
- import { APP_FOLDER_NAME , APP_RESOURCES_FOLDER_NAME , TNS_MODULES_FOLDER_NAME } from "../../../constants" ;
2
+ import { Device , FilesPayload } from "nativescript-preview-sdk" ;
3
+ import { APP_RESOURCES_FOLDER_NAME , APP_FOLDER_NAME } from "../../../constants" ;
5
4
import { HmrConstants } from "../../../common/constants" ;
6
- const isTextOrBinary = require ( 'istextorbinary' ) ;
7
-
8
- interface ISyncFilesOptions {
9
- filesToSync ?: string [ ] ;
10
- filesToRemove ?: string [ ] ;
11
- isInitialSync ?: boolean ;
12
- skipPrepare ?: boolean ;
13
- useHotModuleReload ?: boolean ;
14
- deviceId ?: string ;
15
- }
5
+ import { stringify } from "../../../common/helpers" ;
16
6
17
7
export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
18
- private excludedFileExtensions = [ ".ts" , ".sass" , ".scss" , ".less" ] ;
19
- private excludedFiles = [ ".DS_Store" ] ;
8
+
20
9
private deviceInitializationPromise : IDictionary < Promise < FilesPayload > > = { } ;
21
10
22
- constructor ( private $fs : IFileSystem ,
11
+ constructor (
23
12
private $errors : IErrors ,
24
13
private $hooksService : IHooksService ,
25
14
private $logger : ILogger ,
26
- private $platformService : IPlatformService ,
27
15
private $platformsData : IPlatformsData ,
28
16
private $projectDataService : IProjectDataService ,
29
17
private $previewSdkService : IPreviewSdkService ,
18
+ private $previewAppFilesService : IPreviewAppFilesService ,
30
19
private $previewAppPluginsService : IPreviewAppPluginsService ,
31
20
private $previewDevicesService : IPreviewDevicesService ,
32
- private $projectFilesManager : IProjectFilesManager ,
33
21
private $hmrStatusService : IHmrStatusService ,
34
- private $projectFilesProvider : IProjectFilesProvider ) { }
22
+ ) { }
35
23
36
24
public async initialize ( data : IPreviewAppLiveSyncData ) : Promise < void > {
37
25
await this . $previewSdkService . initialize ( async ( device : Device ) => {
@@ -43,7 +31,7 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
43
31
return this . deviceInitializationPromise [ device . id ] ;
44
32
}
45
33
46
- this . deviceInitializationPromise [ device . id ] = this . initializePreviewForDevice ( data , device ) ;
34
+ this . deviceInitializationPromise [ device . id ] = this . getInitialFilesForDevice ( data , device ) ;
47
35
try {
48
36
const payloads = await this . deviceInitializationPromise [ device . id ] ;
49
37
return payloads ;
@@ -65,27 +53,28 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
65
53
. map ( device => device . platform )
66
54
. uniq ( )
67
55
. value ( ) ;
56
+
68
57
for ( const platform of platforms ) {
69
- await this . syncFilesForPlatformSafe ( data , platform , { filesToSync, filesToRemove, useHotModuleReload : data . useHotModuleReload } ) ;
58
+ await this . syncFilesForPlatformSafe ( data , { filesToSync, filesToRemove } , platform ) ;
70
59
}
71
60
}
72
61
73
62
public async stopLiveSync ( ) : Promise < void > {
74
63
this . $previewSdkService . stop ( ) ;
75
64
}
76
65
77
- private async initializePreviewForDevice ( data : IPreviewAppLiveSyncData , device : Device ) : Promise < FilesPayload > {
66
+ private async getInitialFilesForDevice ( data : IPreviewAppLiveSyncData , device : Device ) : Promise < FilesPayload > {
78
67
const hookArgs = this . getHookArgs ( data , device ) ;
79
68
await this . $hooksService . executeBeforeHooks ( "preview-sync" , { hookArgs } ) ;
80
69
await this . $previewAppPluginsService . comparePluginsOnDevice ( data , device ) ;
81
- const payloads = await this . syncFilesForPlatformSafe ( data , device . platform , { isInitialSync : true , useHotModuleReload : data . useHotModuleReload } ) ;
70
+ const payloads = await this . getInitialFilesForPlatformSafe ( data , device . platform ) ;
82
71
return payloads ;
83
72
}
84
73
85
74
private getHookArgs ( data : IPreviewAppLiveSyncData , device : Device ) {
86
75
const filesToSyncMap : IDictionary < string [ ] > = { } ;
87
76
const hmrData : IDictionary < IPlatformHmrData > = { } ;
88
- const promise = Promise . resolve < FilesPayload > ( null ) ;
77
+ const promise = Promise . resolve ( ) ;
89
78
const result = {
90
79
projectData : this . $projectDataService . getProjectData ( data . projectDir ) ,
91
80
hmrData,
@@ -106,14 +95,44 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
106
95
return result ;
107
96
}
108
97
109
- private async onWebpackCompilationComplete ( data : IPreviewAppLiveSyncData , hmrData : IDictionary < IPlatformHmrData > , filesToSyncMap : IDictionary < string [ ] > , promise : Promise < FilesPayload > , platform : string ) {
98
+ private async getInitialFilesForPlatformSafe ( data : IPreviewAppLiveSyncData , platform : string ) : Promise < FilesPayload > {
99
+ this . $logger . info ( `Start sending initial files for platform ${ platform } .` ) ;
100
+
101
+ try {
102
+ const payloads = this . $previewAppFilesService . getInitialFilesPayload ( data , platform ) ;
103
+ this . $logger . info ( `Successfully sent initial files for platform ${ platform } .` ) ;
104
+ return payloads ;
105
+ } catch ( err ) {
106
+ this . $logger . warn ( `Unable to apply changes for platform ${ platform } . Error is: ${ err } , ${ stringify ( err ) } ` ) ;
107
+ }
108
+ }
109
+
110
+ private async syncFilesForPlatformSafe ( data : IPreviewAppLiveSyncData , filesData : IPreviewAppFilesData , platform : string , deviceId ?: string ) : Promise < void > {
111
+ this . $logger . info ( `Start syncing changes for platform ${ platform } .` ) ;
112
+
113
+ try {
114
+ const payloads = this . $previewAppFilesService . getFilesPayload ( data , filesData , platform ) ;
115
+ await this . $previewSdkService . applyChanges ( payloads ) ;
116
+ this . $logger . info ( `Successfully synced ${ payloads . files . map ( filePayload => filePayload . file . yellow ) } for platform ${ platform } .` ) ;
117
+ } catch ( err ) {
118
+ this . $logger . warn ( `Unable to apply changes for platform ${ platform } . Error is: ${ err } , ${ stringify ( err ) } .` ) ;
119
+ }
120
+ }
121
+
122
+ private async onWebpackCompilationComplete ( data : IPreviewAppLiveSyncData , hmrData : IDictionary < IPlatformHmrData > , filesToSyncMap : IDictionary < string [ ] > , promise : Promise < void > , platform : string ) {
110
123
await promise
111
124
. then ( async ( ) => {
112
125
const currentHmrData = _ . cloneDeep ( hmrData ) ;
113
126
const platformHmrData = currentHmrData [ platform ] || < any > { } ;
114
- const filesToSync = _ . cloneDeep ( filesToSyncMap [ platform ] ) ;
115
- // We don't need to prepare when webpack emits changed files. We just need to send a message to pubnub.
116
- promise = this . syncFilesForPlatformSafe ( data , platform , { filesToSync, skipPrepare : true , useHotModuleReload : data . useHotModuleReload } ) ;
127
+ const projectData = this . $projectDataService . getProjectData ( data . projectDir ) ;
128
+ const platformData = this . $platformsData . getPlatformData ( platform , projectData ) ;
129
+ const clonedFiles = _ . cloneDeep ( filesToSyncMap [ platform ] ) ;
130
+ const filesToSync = _ . map ( clonedFiles , fileToSync => {
131
+ const result = path . join ( platformData . appDestinationDirectoryPath , APP_FOLDER_NAME , path . relative ( projectData . getAppDirectoryPath ( ) , fileToSync ) ) ;
132
+ return result ;
133
+ } ) ;
134
+
135
+ promise = this . syncFilesForPlatformSafe ( data , { filesToSync } , platform ) ;
117
136
await promise ;
118
137
119
138
if ( data . useHotModuleReload && platformHmrData . hash ) {
@@ -122,123 +141,20 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
122
141
await Promise . all ( _ . map ( devices , async ( previewDevice : Device ) => {
123
142
const status = await this . $hmrStatusService . getHmrStatus ( previewDevice . id , platformHmrData . hash ) ;
124
143
if ( status === HmrConstants . HMR_ERROR_STATUS ) {
125
- await this . syncFilesForPlatformSafe ( data , platform , { filesToSync : platformHmrData . fallbackFiles , useHotModuleReload : false , deviceId : previewDevice . id } ) ;
144
+ const originalUseHotModuleReload = data . useHotModuleReload ;
145
+ data . useHotModuleReload = false ;
146
+ await this . syncFilesForPlatformSafe ( data , { filesToSync : platformHmrData . fallbackFiles } , platform , previewDevice . id ) ;
147
+ data . useHotModuleReload = originalUseHotModuleReload ;
126
148
}
127
149
} ) ) ;
128
150
}
129
151
} ) ;
130
152
filesToSyncMap [ platform ] = [ ] ;
131
153
}
132
154
133
- private async syncFilesForPlatformSafe ( data : IPreviewAppLiveSyncData , platform : string , opts ?: ISyncFilesOptions ) : Promise < FilesPayload > {
134
- this . $logger . info ( `Start syncing changes for platform ${ platform } .` ) ;
135
-
136
- opts = opts || { } ;
137
- let payloads = null ;
138
-
139
- try {
140
- const { env, projectDir } = data ;
141
- const projectData = this . $projectDataService . getProjectData ( projectDir ) ;
142
- const platformData = this . $platformsData . getPlatformData ( platform , projectData ) ;
143
-
144
- if ( ! opts . skipPrepare ) {
145
- await this . preparePlatform ( platform , data , env , projectData ) ;
146
- }
147
-
148
- if ( opts . isInitialSync ) {
149
- const platformsAppFolderPath = path . join ( platformData . appDestinationDirectoryPath , APP_FOLDER_NAME ) ;
150
- opts . filesToSync = this . $projectFilesManager . getProjectFiles ( platformsAppFolderPath ) ;
151
- payloads = this . getFilesPayload ( platformData , projectData , opts ) ;
152
- this . $logger . info ( `Successfully synced changes for platform ${ platform } .` ) ;
153
- } else {
154
- opts . filesToSync = _ . map ( opts . filesToSync , file => this . $projectFilesProvider . mapFilePath ( file , platformData . normalizedPlatformName , projectData ) ) ;
155
- payloads = this . getFilesPayload ( platformData , projectData , opts ) ;
156
- await this . $previewSdkService . applyChanges ( payloads ) ;
157
- this . $logger . info ( `Successfully synced ${ payloads . files . map ( filePayload => filePayload . file . yellow ) } for platform ${ platform } .` ) ;
158
- }
159
-
160
- return payloads ;
161
- } catch ( err ) {
162
- this . $logger . warn ( `Unable to apply changes for platform ${ platform } . Error is: ${ err } , ${ JSON . stringify ( err , null , 2 ) } .` ) ;
163
- }
164
- }
165
-
166
- private getFilesPayload ( platformData : IPlatformData , projectData : IProjectData , opts ?: ISyncFilesOptions ) : FilesPayload {
167
- const { filesToSync, filesToRemove, deviceId } = opts ;
168
-
169
- const filesToTransfer = filesToSync
170
- . filter ( file => file . indexOf ( TNS_MODULES_FOLDER_NAME ) === - 1 )
171
- . filter ( file => file . indexOf ( APP_RESOURCES_FOLDER_NAME ) === - 1 )
172
- . filter ( file => ! _ . includes ( this . excludedFiles , path . basename ( file ) ) )
173
- . filter ( file => ! _ . includes ( this . excludedFileExtensions , path . extname ( file ) ) ) ;
174
-
175
- this . $logger . trace ( `Transferring ${ filesToTransfer . join ( "\n" ) } .` ) ;
176
-
177
- const payloadsToSync = filesToTransfer . map ( file => this . createFilePayload ( file , platformData , projectData , PreviewSdkEventNames . CHANGE_EVENT_NAME ) ) ;
178
- const payloadsToRemove = _ . map ( filesToRemove , file => this . createFilePayload ( file , platformData , projectData , PreviewSdkEventNames . UNLINK_EVENT_NAME ) ) ;
179
- const payloads = payloadsToSync . concat ( payloadsToRemove ) ;
180
-
181
- const hmrMode = opts . useHotModuleReload ? 1 : 0 ;
182
- return { files : payloads , platform : platformData . normalizedPlatformName . toLowerCase ( ) , hmrMode, deviceId } ;
183
- }
184
-
185
- private async preparePlatform ( platform : string , data : IPreviewAppLiveSyncData , env : Object , projectData : IProjectData ) : Promise < void > {
186
- const appFilesUpdaterOptions = {
187
- bundle : data . bundle ,
188
- useHotModuleReload : data . useHotModuleReload ,
189
- release : false
190
- } ;
191
- const nativePrepare = { skipNativePrepare : true } ;
192
- const config = < IPlatformOptions > { } ;
193
- const platformTemplate = < string > null ;
194
- const prepareInfo = {
195
- platform,
196
- appFilesUpdaterOptions,
197
- env,
198
- projectData,
199
- nativePrepare,
200
- config,
201
- platformTemplate,
202
- skipCopyTnsModules : true ,
203
- skipCopyAppResourcesFiles : true
204
- } ;
205
- await this . $platformService . preparePlatform ( prepareInfo ) ;
206
- }
207
-
208
155
private showWarningsForNativeFiles ( files : string [ ] ) : void {
209
156
_ . filter ( files , file => file . indexOf ( APP_RESOURCES_FOLDER_NAME ) > - 1 )
210
157
. forEach ( file => this . $logger . warn ( `Unable to apply changes from ${ APP_RESOURCES_FOLDER_NAME } folder. You need to build your application in order to make changes in ${ APP_RESOURCES_FOLDER_NAME } folder.` ) ) ;
211
158
}
212
-
213
- private createFilePayload ( file : string , platformData : IPlatformData , projectData : IProjectData , event : string ) : FilePayload {
214
- const projectFileInfo = this . $projectFilesProvider . getProjectFileInfo ( file , platformData . normalizedPlatformName , null ) ;
215
- const binary = isTextOrBinary . isBinarySync ( file ) ;
216
- let fileContents = "" ;
217
- let filePath = "" ;
218
-
219
- if ( event === PreviewSdkEventNames . CHANGE_EVENT_NAME ) {
220
- const relativePath = path . relative ( path . join ( platformData . appDestinationDirectoryPath , APP_FOLDER_NAME ) , file ) ;
221
- filePath = path . join ( path . dirname ( relativePath ) , projectFileInfo . onDeviceFileName ) ;
222
-
223
- if ( binary ) {
224
- const bitmap = < string > this . $fs . readFile ( file ) ;
225
- const base64 = Buffer . from ( bitmap ) . toString ( 'base64' ) ;
226
- fileContents = base64 ;
227
- } else {
228
- fileContents = this . $fs . readText ( path . join ( path . dirname ( projectFileInfo . filePath ) , projectFileInfo . onDeviceFileName ) ) ;
229
- }
230
- } else if ( event === PreviewSdkEventNames . UNLINK_EVENT_NAME ) {
231
- filePath = path . relative ( path . join ( projectData . projectDir , APP_FOLDER_NAME ) , file ) ;
232
- }
233
-
234
- const filePayload = {
235
- event,
236
- file : filePath ,
237
- binary,
238
- fileContents
239
- } ;
240
-
241
- return filePayload ;
242
- }
243
159
}
244
160
$injector . register ( "previewAppLiveSyncService" , PreviewAppLiveSyncService ) ;
0 commit comments