Skip to content

Commit e2b55b2

Browse files
author
Dimitar Tachev
authored
Merge pull request #4142 from NativeScript/fatme/remove-prepare-from-preview
Don't prepare the project on preview command
2 parents 7f0af19 + 76f084d commit e2b55b2

File tree

7 files changed

+289
-172
lines changed

7 files changed

+289
-172
lines changed

lib/bootstrap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ $injector.requirePublicClass("androidLivesyncTool", "./services/livesync/android
136136
$injector.require("androidLiveSyncService", "./services/livesync/android-livesync-service");
137137
$injector.require("iOSLiveSyncService", "./services/livesync/ios-livesync-service");
138138
$injector.require("usbLiveSyncService", "./services/livesync/livesync-service"); // The name is used in https://github.com/NativeScript/nativescript-dev-typescript
139+
$injector.require("previewAppFilesService", "./services/livesync/playground/preview-app-files-service");
139140
$injector.require("previewAppLiveSyncService", "./services/livesync/playground/preview-app-livesync-service");
140141
$injector.require("previewAppLogProvider", "./services/livesync/playground/preview-app-log-provider");
141142
$injector.require("previewAppPluginsService", "./services/livesync/playground/preview-app-plugins-service");

lib/common/helpers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,10 @@ export function getWinRegPropertyValue(key: string, propertyName: string): Promi
563563
});
564564
}
565565

566+
export function stringify(value: any, replacer?: (key: string, value: any) => any, space?: string | number): string {
567+
return JSON.stringify(value, replacer, space || 2);
568+
}
569+
566570
//--- begin part copied from AngularJS
567571

568572
//The MIT License

lib/definitions/preview-app-livesync.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ declare global {
88
stopLiveSync(): Promise<void>;
99
}
1010

11+
interface IPreviewAppFilesService {
12+
getInitialFilesPayload(liveSyncData: IPreviewAppLiveSyncData, platform: string, deviceId?: string): FilesPayload;
13+
getFilesPayload(liveSyncData: IPreviewAppLiveSyncData, filesData: IPreviewAppFilesData, platform: string, deviceId?: string): FilesPayload;
14+
}
15+
16+
interface IPreviewAppFilesData {
17+
filesToSync: string[];
18+
filesToRemove?: string[];
19+
}
20+
1121
interface IPreviewAppLiveSyncData extends IProjectDir, IHasUseHotModuleReloadOption, IBundle, IEnvOptions { }
1222

1323
interface IPreviewSdkService extends EventEmitter {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as path from "path";
2+
import { APP_FOLDER_NAME, TNS_MODULES_FOLDER_NAME, APP_RESOURCES_FOLDER_NAME } from "../../../constants";
3+
import { PreviewSdkEventNames } from "./preview-app-constants";
4+
import { FilePayload, FilesPayload } from "nativescript-preview-sdk";
5+
const isTextOrBinary = require('istextorbinary');
6+
7+
export class PreviewAppFilesService implements IPreviewAppFilesService {
8+
private excludedFileExtensions = [".ts", ".sass", ".scss", ".less"];
9+
private excludedFiles = [".DS_Store"];
10+
11+
constructor(
12+
private $fs: IFileSystem,
13+
private $logger: ILogger,
14+
private $platformsData: IPlatformsData,
15+
private $projectDataService: IProjectDataService,
16+
private $projectFilesManager: IProjectFilesManager
17+
) { }
18+
19+
public getInitialFilesPayload(data: IPreviewAppLiveSyncData, platform: string, deviceId?: string): FilesPayload {
20+
const rootFilesDir = this.getRootFilesDir(data, platform);
21+
const filesToSync = this.$projectFilesManager.getProjectFiles(rootFilesDir);
22+
const payloads = this.getFilesPayload(data, { filesToSync }, platform, deviceId);
23+
return payloads;
24+
}
25+
26+
public getFilesPayload(data: IPreviewAppLiveSyncData, filesData: IPreviewAppFilesData, platform: string, deviceId?: string): FilesPayload {
27+
const { filesToSync, filesToRemove } = filesData;
28+
29+
const filesToTransfer = filesToSync
30+
.filter(file => file.indexOf(TNS_MODULES_FOLDER_NAME) === -1)
31+
.filter(file => file.indexOf(APP_RESOURCES_FOLDER_NAME) === -1)
32+
.filter(file => !_.includes(this.excludedFiles, path.basename(file)))
33+
.filter(file => !_.includes(this.excludedFileExtensions, path.extname(file)));
34+
35+
this.$logger.trace(`Sending ${filesToTransfer.join("\n")}.`);
36+
37+
const rootFilesDir = this.getRootFilesDir(data, platform);
38+
const payloadsToSync = _.map(filesToTransfer, file => this.createFilePayload(file, rootFilesDir, PreviewSdkEventNames.CHANGE_EVENT_NAME));
39+
const payloadsToRemove = _.map(filesToRemove, file => this.createFilePayload(file, rootFilesDir, PreviewSdkEventNames.UNLINK_EVENT_NAME));
40+
const payloads = payloadsToSync.concat(payloadsToRemove);
41+
42+
return {
43+
files: payloads,
44+
platform: platform,
45+
hmrMode: data.useHotModuleReload ? 1 : 0,
46+
deviceId
47+
};
48+
}
49+
50+
private createFilePayload(file: string, rootFilesDir: string, event: string): FilePayload {
51+
let fileContents = "";
52+
let binary = false;
53+
54+
if (event === PreviewSdkEventNames.CHANGE_EVENT_NAME) {
55+
binary = isTextOrBinary.isBinarySync(file);
56+
if (binary) {
57+
const bitmap = <string>this.$fs.readFile(file);
58+
const base64 = Buffer.from(bitmap).toString('base64');
59+
fileContents = base64;
60+
} else {
61+
fileContents = this.$fs.readText(file);
62+
}
63+
}
64+
65+
const filePayload = {
66+
event,
67+
file: path.relative(rootFilesDir, file),
68+
binary,
69+
fileContents
70+
};
71+
72+
return filePayload;
73+
}
74+
75+
private getRootFilesDir(data: IPreviewAppLiveSyncData, platform: string): string {
76+
const projectData = this.$projectDataService.getProjectData(data.projectDir);
77+
const platformData = this.$platformsData.getPlatformData(platform, projectData);
78+
79+
let rootFilesDir = null;
80+
if (data.bundle) {
81+
rootFilesDir = path.join(platformData.appDestinationDirectoryPath, APP_FOLDER_NAME);
82+
} else {
83+
rootFilesDir = projectData.getAppDirectoryPath();
84+
}
85+
86+
return rootFilesDir;
87+
}
88+
}
89+
$injector.register("previewAppFilesService", PreviewAppFilesService);
Lines changed: 51 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,25 @@
11
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";
54
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";
166

177
export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
18-
private excludedFileExtensions = [".ts", ".sass", ".scss", ".less"];
19-
private excludedFiles = [".DS_Store"];
8+
209
private deviceInitializationPromise: IDictionary<Promise<FilesPayload>> = {};
2110

22-
constructor(private $fs: IFileSystem,
11+
constructor(
2312
private $errors: IErrors,
2413
private $hooksService: IHooksService,
2514
private $logger: ILogger,
26-
private $platformService: IPlatformService,
2715
private $platformsData: IPlatformsData,
2816
private $projectDataService: IProjectDataService,
2917
private $previewSdkService: IPreviewSdkService,
18+
private $previewAppFilesService: IPreviewAppFilesService,
3019
private $previewAppPluginsService: IPreviewAppPluginsService,
3120
private $previewDevicesService: IPreviewDevicesService,
32-
private $projectFilesManager: IProjectFilesManager,
3321
private $hmrStatusService: IHmrStatusService,
34-
private $projectFilesProvider: IProjectFilesProvider) { }
22+
) { }
3523

3624
public async initialize(data: IPreviewAppLiveSyncData): Promise<void> {
3725
await this.$previewSdkService.initialize(async (device: Device) => {
@@ -43,7 +31,7 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
4331
return this.deviceInitializationPromise[device.id];
4432
}
4533

46-
this.deviceInitializationPromise[device.id] = this.initializePreviewForDevice(data, device);
34+
this.deviceInitializationPromise[device.id] = this.getInitialFilesForDevice(data, device);
4735
try {
4836
const payloads = await this.deviceInitializationPromise[device.id];
4937
return payloads;
@@ -65,27 +53,28 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
6553
.map(device => device.platform)
6654
.uniq()
6755
.value();
56+
6857
for (const platform of platforms) {
69-
await this.syncFilesForPlatformSafe(data, platform, { filesToSync, filesToRemove, useHotModuleReload: data.useHotModuleReload });
58+
await this.syncFilesForPlatformSafe(data, { filesToSync, filesToRemove }, platform);
7059
}
7160
}
7261

7362
public async stopLiveSync(): Promise<void> {
7463
this.$previewSdkService.stop();
7564
}
7665

77-
private async initializePreviewForDevice(data: IPreviewAppLiveSyncData, device: Device): Promise<FilesPayload> {
66+
private async getInitialFilesForDevice(data: IPreviewAppLiveSyncData, device: Device): Promise<FilesPayload> {
7867
const hookArgs = this.getHookArgs(data, device);
7968
await this.$hooksService.executeBeforeHooks("preview-sync", { hookArgs });
8069
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);
8271
return payloads;
8372
}
8473

8574
private getHookArgs(data: IPreviewAppLiveSyncData, device: Device) {
8675
const filesToSyncMap: IDictionary<string[]> = {};
8776
const hmrData: IDictionary<IPlatformHmrData> = {};
88-
const promise = Promise.resolve<FilesPayload>(null);
77+
const promise = Promise.resolve();
8978
const result = {
9079
projectData: this.$projectDataService.getProjectData(data.projectDir),
9180
hmrData,
@@ -106,14 +95,44 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
10695
return result;
10796
}
10897

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) {
110123
await promise
111124
.then(async () => {
112125
const currentHmrData = _.cloneDeep(hmrData);
113126
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);
117136
await promise;
118137

119138
if (data.useHotModuleReload && platformHmrData.hash) {
@@ -122,123 +141,20 @@ export class PreviewAppLiveSyncService implements IPreviewAppLiveSyncService {
122141
await Promise.all(_.map(devices, async (previewDevice: Device) => {
123142
const status = await this.$hmrStatusService.getHmrStatus(previewDevice.id, platformHmrData.hash);
124143
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;
126148
}
127149
}));
128150
}
129151
});
130152
filesToSyncMap[platform] = [];
131153
}
132154

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-
208155
private showWarningsForNativeFiles(files: string[]): void {
209156
_.filter(files, file => file.indexOf(APP_RESOURCES_FOLDER_NAME) > -1)
210157
.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.`));
211158
}
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-
}
243159
}
244160
$injector.register("previewAppLiveSyncService", PreviewAppLiveSyncService);

0 commit comments

Comments
 (0)