From 6f3ae4bf85807dfee7f788936647af5255364e62 Mon Sep 17 00:00:00 2001 From: Dimitar Kerezov Date: Thu, 1 Feb 2018 13:12:48 +0200 Subject: [PATCH 1/3] feat(livesync): enable livesync with bundling Enable LiveSync whenever a bundling plugin is present. Allow the bundling plugin to instruct CLI on what files should be watched and enable plugins to call `startSyncFilesTimeout` method in order to sync files modified by the bundling plugin itself. --- lib/commands/run.ts | 4 --- lib/common | 2 +- lib/definitions/livesync.d.ts | 17 +++++++--- lib/services/livesync/livesync-service.ts | 41 ++++++++++++++++------- lib/services/platform-service.ts | 4 +-- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/lib/commands/run.ts b/lib/commands/run.ts index 2d1c5cc361..cae512b9ae 100644 --- a/lib/commands/run.ts +++ b/lib/commands/run.ts @@ -49,10 +49,6 @@ export class RunCommandBase extends BundleBase implements ICommand { } public async executeCore(args: string[]): Promise { - if (this.$options.bundle) { - this.$options.watch = false; - } - await this.$devicesService.initialize({ deviceId: this.$options.device, platform: this.platform, diff --git a/lib/common b/lib/common index e4c92e9ccb..262dbdf2f0 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit e4c92e9ccbaa98120eb67c1a6df0d63ac7fa3938 +Subproject commit 262dbdf2f035f067c8321b743fb1f91704c18495 diff --git a/lib/definitions/livesync.d.ts b/lib/definitions/livesync.d.ts index c051909688..1fa0168408 100644 --- a/lib/definitions/livesync.d.ts +++ b/lib/definitions/livesync.d.ts @@ -108,15 +108,17 @@ interface ILiveSyncDeviceInfo extends IOptionalOutputPath, IOptionalDebuggingOpt platformSpecificOptions?: IPlatformOptions; } -/** - * Describes a LiveSync operation. - */ -interface ILiveSyncInfo extends IProjectDir, IEnvOptions, IBundle, IRelease { +interface IOptionalSkipWatcher { /** * Defines if the watcher should be skipped. If not passed, fs.Watcher will be started. */ skipWatcher?: boolean; +} +/** + * Describes a LiveSync operation. + */ +interface ILiveSyncInfo extends IProjectDir, IEnvOptions, IBundle, IRelease, IOptionalSkipWatcher { /** * Defines if all project files should be watched for changes. In case it is not passed, only `app` dir of the project will be watched for changes. * In case it is set to true, the package.json of the project and node_modules directory will also be watched, so any change there will be transferred to device(s). @@ -207,6 +209,13 @@ interface ILiveSyncService { * Describes LiveSync operations while debuggging. */ interface IDebugLiveSyncService extends ILiveSyncService { + /** + * Method used to retrieve the glob patterns which CLI will watch for file changes. Defaults to the whole app directory. + * @param {ILiveSyncInfo} liveSyncData Information needed for livesync - for example if bundle is passed or if a release build should be performed. + * @returns {Promise} The glob patterns. + */ + getWatcherPatterns(liveSyncData: ILiveSyncInfo): Promise; + /** * Prints debug information. * @param {IDebugInformation} debugInformation Information to be printed. diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index 5967b988d5..235ccb8558 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -4,7 +4,7 @@ import { EOL } from "os"; import { EventEmitter } from "events"; import { hook } from "../../common/helpers"; import { APP_FOLDER_NAME, PACKAGE_JSON_FILE_NAME, LiveSyncTrackActionNames, USER_INTERACTION_NEEDED_EVENT_NAME, DEBUGGER_ATTACHED_EVENT_NAME, DEBUGGER_DETACHED_EVENT_NAME, TrackActionNames } from "../../constants"; -import { FileExtensions, DeviceTypes, DeviceDiscoveryEventNames } from "../../common/constants"; +import { DeviceTypes, DeviceDiscoveryEventNames } from "../../common/constants"; import { cache } from "../../common/decorators"; const deviceDescriptorPrimaryKey = "identifier"; @@ -289,6 +289,12 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi return _.map(deviceOptions, d => this.disableDebuggingCore(d, debuggingAdditionalOptions)); } + @hook('watchPatterns') + public async getWatcherPatterns(liveSyncData: ILiveSyncInfo): Promise { + // liveSyncData is used by plugins that make use of the watchPatterns hook + return [APP_FOLDER_NAME]; + } + public async disableDebuggingCore(deviceOption: IDisableDebuggingDeviceOptions, debuggingAdditionalOptions: IDebuggingAdditionalOptions): Promise { const liveSyncProcessInfo = this.liveSyncProcessesInfo[debuggingAdditionalOptions.projectDir]; if (liveSyncProcessInfo.currentSyncAction) { @@ -328,7 +334,10 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi // Should be set after prepare this.$usbLiveSyncService.isInitialized = true; - await this.startWatcher(projectData, liveSyncData); + const devicesIds = deviceDescriptors.map(dd => dd.identifier); + const devices = _.filter(this.$devicesService.getDeviceInstances(), device => _.includes(devicesIds, device.deviceInfo.identifier)); + const platforms = _(devices).map(device => device.deviceInfo.platform).uniq().value(); + await this.startWatcher(projectData, liveSyncData, platforms); } } @@ -515,8 +524,8 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi }; } - private async startWatcher(projectData: IProjectData, liveSyncData: ILiveSyncInfo): Promise { - const patterns = [APP_FOLDER_NAME]; + private async startWatcher(projectData: IProjectData, liveSyncData: ILiveSyncInfo, platforms: string[]): Promise { + const patterns = await this.getWatcherPatterns(liveSyncData); if (liveSyncData.watchAllFiles) { const productionDependencies = this.$nodeModulesDependenciesBuilder.getProductionDependencies(projectData.projectDir); @@ -535,18 +544,18 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi currentWatcherInfo.watcher.close(); } - let filesToSync: string[] = []; + const filesToSync: string[] = []; let filesToRemove: string[] = []; let timeoutTimer: NodeJS.Timer; - const startTimeout = () => { + const startSyncFilesTimeout = () => { timeoutTimer = setTimeout(async () => { // Push actions to the queue, do not start them simultaneously await this.addActionToChain(projectData.projectDir, async () => { if (filesToSync.length || filesToRemove.length) { try { const currentFilesToSync = _.cloneDeep(filesToSync); - filesToSync = []; + filesToSync.splice(0, filesToSync.length); const currentFilesToRemove = _.cloneDeep(filesToRemove); filesToRemove = []; @@ -622,7 +631,18 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi await this.$hooksService.executeBeforeHooks('watch', { hookArgs: { - projectData + projectData, + config: { + env: liveSyncData.env, + appFilesUpdaterOptions: { + bundle: liveSyncData.bundle, + release: liveSyncData.release + }, + platforms + }, + filesToSync, + filesToRemove, + startSyncFilesTimeout: startSyncFilesTimeout.bind(this) } }); @@ -650,10 +670,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi filesToRemove.push(filePath); } - // Do not sync typescript files directly - wait for javascript changes to occur in order to restart the app only once - if (path.extname(filePath) !== FileExtensions.TYPESCRIPT_FILE) { - startTimeout(); - } + startSyncFilesTimeout(); }); this.liveSyncProcessesInfo[liveSyncData.projectDir].watcherInfo = { watcher, patterns }; diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index a97da8dc7a..d955403dd8 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -193,11 +193,11 @@ export class PlatformService extends EventEmitter implements IPlatformService { const changesInfo = await this.initialPrepare(platformInfo.platform, platformData, platformInfo.appFilesUpdaterOptions, platformInfo.platformTemplate, platformInfo.projectData, platformInfo.config, platformInfo.nativePrepare, platformInfo); const requiresNativePrepare = (!platformInfo.nativePrepare || !platformInfo.nativePrepare.skipNativePrepare) && changesInfo.nativePlatformStatus === constants.NativePlatformStatus.requiresPrepare; - if (changesInfo.hasChanges || platformInfo.appFilesUpdaterOptions.bundle || requiresNativePrepare) { + if (changesInfo.hasChanges || requiresNativePrepare) { // Always clear up the app directory in platforms if `--bundle` value has changed in between builds or is passed in general // this is done as user has full control over what goes in platforms when `--bundle` is passed // and we may end up with duplicate symbols which would fail the build - if (changesInfo.bundleChanged || platformInfo.appFilesUpdaterOptions.bundle) { + if (changesInfo.bundleChanged) { await this.cleanDestinationApp(platformInfo); } From 5a2c05461ae8e1a3b025b02ac7e78787fe754e92 Mon Sep 17 00:00:00 2001 From: Dimitar Kerezov Date: Fri, 9 Feb 2018 12:00:45 +0200 Subject: [PATCH 2/3] refactor(livesync): include resources in initial patterns --- lib/services/livesync/livesync-service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index 235ccb8558..4f113d2e9a 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -3,7 +3,7 @@ import * as choki from "chokidar"; import { EOL } from "os"; import { EventEmitter } from "events"; import { hook } from "../../common/helpers"; -import { APP_FOLDER_NAME, PACKAGE_JSON_FILE_NAME, LiveSyncTrackActionNames, USER_INTERACTION_NEEDED_EVENT_NAME, DEBUGGER_ATTACHED_EVENT_NAME, DEBUGGER_DETACHED_EVENT_NAME, TrackActionNames } from "../../constants"; +import { APP_FOLDER_NAME, APP_RESOURCES_FOLDER_NAME, PACKAGE_JSON_FILE_NAME, LiveSyncTrackActionNames, USER_INTERACTION_NEEDED_EVENT_NAME, DEBUGGER_ATTACHED_EVENT_NAME, DEBUGGER_DETACHED_EVENT_NAME, TrackActionNames } from "../../constants"; import { DeviceTypes, DeviceDiscoveryEventNames } from "../../common/constants"; import { cache } from "../../common/decorators"; @@ -292,7 +292,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi @hook('watchPatterns') public async getWatcherPatterns(liveSyncData: ILiveSyncInfo): Promise { // liveSyncData is used by plugins that make use of the watchPatterns hook - return [APP_FOLDER_NAME]; + return [APP_FOLDER_NAME, path.join(APP_FOLDER_NAME, APP_RESOURCES_FOLDER_NAME)]; } public async disableDebuggingCore(deviceOption: IDisableDebuggingDeviceOptions, debuggingAdditionalOptions: IDebuggingAdditionalOptions): Promise { From 418fa6b86db5305339cc3e0bd191036161d73f5c Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Mon, 26 Feb 2018 18:04:52 +0200 Subject: [PATCH 3/3] chore: Update common --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index 262dbdf2f0..e4c92e9ccb 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 262dbdf2f035f067c8321b743fb1f91704c18495 +Subproject commit e4c92e9ccbaa98120eb67c1a6df0d63ac7fa3938