Skip to content

Commit 6539f86

Browse files
feat: Speed up adding native platform
The current logic for adding native platform is: 1. Install the runtime package (tns-ios or tns-android) as a dependency of the project 2. Copy all files from the `<project dir>/node_modules/<runtime package>/framework` to `<project dir>/plaforms/<platform>/...` (specific places there). 3. Uninstall the runtime package, so it is no longer dependency of the project. This solution becomes really slow when the project has a lot of dependencies. For example, for `tns-template-master-detail-ng`, all these steps take around 2 mins and 5 seconds on Windows (without SSD) and around 40 seconds on macOS (with SSD). In order to speed up this process, remove the installing and uninstalling of the runtime package. Instead of this, use the `pacote` package to extract the runtime to a directory in the `temp` and copy files from there to `platforms` directory. As we do not execute `npm install` and `npm uninstall` with this solution, the operation is not dependant on the number of dependencies used in the project. It takes around 5-9 second on both Windows and macOS. Also remove the usage of `$options` from `npmInstallationManager` - its purpose was to work with `--frameworkPath` on `tns platform add <platform>` command, but we no longer call `npmInstallationManager` for this case. Fix the tests for `platorm-service`'s addPlatform method as they were incorrectly passing.
1 parent cff6778 commit 6539f86

File tree

6 files changed

+103
-119
lines changed

6 files changed

+103
-119
lines changed

lib/npm-installation-manager.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export class NpmInstallationManager implements INpmInstallationManager {
66
constructor(private $npm: INodePackageManager,
77
private $childProcess: IChildProcess,
88
private $logger: ILogger,
9-
private $options: IOptions,
109
private $settingsService: ISettingsService,
1110
private $fs: IFileSystem,
1211
private $staticConfig: IStaticConfig,
@@ -39,9 +38,8 @@ export class NpmInstallationManager implements INpmInstallationManager {
3938
return maxSatisfying || latestVersion;
4039
}
4140

42-
public async install(packageName: string, projectDir: string, opts?: INpmInstallOptions): Promise<any> {
41+
public async install(packageToInstall: string, projectDir: string, opts?: INpmInstallOptions): Promise<any> {
4342
try {
44-
const packageToInstall = this.$options.frameworkPath || packageName;
4543
const pathToSave = projectDir;
4644
const version = (opts && opts.version) || null;
4745
const dependencyType = (opts && opts.dependencyType) || null;

lib/services/android-project-service.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
144144
const targetSdkVersion = androidToolsInfo && androidToolsInfo.targetSdkVersion;
145145
this.$logger.trace(`Using Android SDK '${targetSdkVersion}'.`);
146146

147-
this.isAndroidStudioTemplate = this.isAndroidStudioCompatibleTemplate(projectData);
147+
this.isAndroidStudioTemplate = this.isAndroidStudioCompatibleTemplate(projectData, frameworkVersion);
148148
if (this.isAndroidStudioTemplate) {
149149
this.copy(this.getPlatformData(projectData).projectRoot, frameworkDir, "*", "-R");
150150
} else {
@@ -703,20 +703,12 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
703703
}
704704
}
705705

706-
private isAndroidStudioCompatibleTemplate(projectData: IProjectData): boolean {
706+
private isAndroidStudioCompatibleTemplate(projectData: IProjectData, frameworkVersion?: string): boolean {
707707
const currentPlatformData: IDictionary<any> = this.$projectDataService.getNSValue(projectData.projectDir, constants.TNS_ANDROID_RUNTIME_NAME);
708-
let platformVersion = currentPlatformData && currentPlatformData[constants.VERSION_STRING];
708+
const platformVersion = (currentPlatformData && currentPlatformData[constants.VERSION_STRING]) || frameworkVersion;
709709

710710
if (!platformVersion) {
711-
const tnsAndroidPackageJsonPath = path.join(projectData.projectDir, constants.NODE_MODULES_FOLDER_NAME, constants.TNS_ANDROID_RUNTIME_NAME, constants.PACKAGE_JSON_FILE_NAME);
712-
if (this.$fs.exists(tnsAndroidPackageJsonPath)) {
713-
const projectPackageJson: any = this.$fs.readJson(tnsAndroidPackageJsonPath);
714-
if (projectPackageJson && projectPackageJson.version) {
715-
platformVersion = projectPackageJson.version;
716-
}
717-
} else {
718-
return true;
719-
}
711+
return true;
720712
}
721713

722714
if (platformVersion === constants.PackageVersion.NEXT || platformVersion === constants.PackageVersion.LATEST || platformVersion === constants.PackageVersion.RC) {

lib/services/platform-service.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@ export class PlatformService extends EventEmitter implements IPlatformService {
3636
private $mobileHelper: Mobile.IMobileHelper,
3737
private $hostInfo: IHostInfo,
3838
private $devicePathProvider: IDevicePathProvider,
39-
private $npm: INodePackageManager,
4039
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
4140
private $projectChangesService: IProjectChangesService,
4241
private $analyticsService: IAnalyticsService,
43-
private $terminalSpinnerService: ITerminalSpinnerService) {
42+
private $terminalSpinnerService: ITerminalSpinnerService,
43+
private $pacoteService: IPacoteService
44+
) {
4445
super();
4546
}
4647

@@ -92,10 +93,6 @@ export class PlatformService extends EventEmitter implements IPlatformService {
9293

9394
const platformData = this.$platformsData.getPlatformData(platform, projectData);
9495

95-
if (version === undefined) {
96-
version = this.getCurrentPlatformVersion(platform, projectData);
97-
}
98-
9996
// Log the values for project
10097
this.$logger.trace("Creating NativeScript project for the %s platform", platform);
10198
this.$logger.trace("Path: %s", platformData.projectRoot);
@@ -105,28 +102,28 @@ export class PlatformService extends EventEmitter implements IPlatformService {
105102
this.$logger.out("Copying template files...");
106103

107104
let packageToInstall = "";
108-
const npmOptions: IStringDictionary = {
109-
pathToSave: path.join(projectData.platformsDir, platform),
110-
dependencyType: "save"
111-
};
105+
if (frameworkPath) {
106+
packageToInstall = path.resolve(frameworkPath);
107+
} else {
108+
if (!version) {
109+
version = this.getCurrentPlatformVersion(platform, projectData) ||
110+
await this.$npmInstallationManager.getLatestCompatibleVersion(platformData.frameworkPackageName);
111+
}
112112

113-
if (!frameworkPath) {
114-
packageToInstall = platformData.frameworkPackageName;
115-
npmOptions["version"] = version;
113+
packageToInstall = `${platformData.frameworkPackageName}@${version}`;
116114
}
117115

118116
const spinner = this.$terminalSpinnerService.createSpinner();
119-
const projectDir = projectData.projectDir;
120117
const platformPath = path.join(projectData.platformsDir, platform);
121118

122119
try {
123120
spinner.start();
124-
const downloadedPackagePath = await this.$npmInstallationManager.install(packageToInstall, projectDir, npmOptions);
121+
const downloadedPackagePath = temp.mkdirSync("runtimeDir");
122+
temp.track();
123+
await this.$pacoteService.extractPackage(packageToInstall, downloadedPackagePath);
125124
let frameworkDir = path.join(downloadedPackagePath, constants.PROJECT_FRAMEWORK_FOLDER_NAME);
126125
frameworkDir = path.resolve(frameworkDir);
127-
128-
const coreModuleName = await this.addPlatformCore(platformData, frameworkDir, platformTemplate, projectData, config, nativePrepare);
129-
await this.$npm.uninstall(coreModuleName, { save: true }, projectData.projectDir);
126+
await this.addPlatformCore(platformData, frameworkDir, platformTemplate, projectData, config, nativePrepare);
130127
} catch (err) {
131128
this.$fs.deleteDirectory(platformPath);
132129
throw err;
@@ -842,15 +839,15 @@ export class PlatformService extends EventEmitter implements IPlatformService {
842839
const data = this.$projectDataService.getNSValue(projectData.projectDir, platformData.frameworkPackageName);
843840
const currentVersion = data && data.version ? data.version : "0.2.0";
844841

842+
const installedModuleDir = temp.mkdirSync("runtime-to-update");
845843
let newVersion = version === constants.PackageVersion.NEXT ?
846844
await this.$npmInstallationManager.getNextVersion(platformData.frameworkPackageName) :
847845
version || await this.$npmInstallationManager.getLatestCompatibleVersion(platformData.frameworkPackageName);
848-
const installedModuleDir = await this.$npmInstallationManager.install(platformData.frameworkPackageName, projectData.projectDir, { version: newVersion, dependencyType: "save" });
846+
await this.$pacoteService.extractPackage(`${platformData.frameworkPackageName}@${newVersion}`, installedModuleDir);
849847
const cachedPackageData = this.$fs.readJson(path.join(installedModuleDir, "package.json"));
850848
newVersion = (cachedPackageData && cachedPackageData.version) || newVersion;
851849

852850
const canUpdate = platformData.platformProjectService.canUpdatePlatform(installedModuleDir, projectData);
853-
await this.$npm.uninstall(platformData.frameworkPackageName, { save: true }, projectData.projectDir);
854851
if (canUpdate) {
855852
if (!semver.valid(newVersion)) {
856853
this.$errors.fail("The version %s is not valid. The version should consists from 3 parts separated by dot.", newVersion);

test/npm-support.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ function createTestInjector(): IInjector {
104104
getChanges: () => Promise.resolve({}),
105105
generateHashes: () => Promise.resolve()
106106
});
107+
testInjector.register("pacoteService", {
108+
extractPackage: async (packageName: string, destinationDirectory: string, options?: IPacoteExtractOptions): Promise<void> => undefined
109+
});
107110

108111
return testInjector;
109112
}

test/platform-commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ function createTestInjector() {
168168
testInjector.register("platformEnvironmentRequirements", {
169169
checkEnvironmentRequirements: async (platform?: string, projectDir?: string, runtimeVersion?: string): Promise<boolean> => true
170170
});
171+
testInjector.register("pacoteService", {
172+
extractPackage: async (packageName: string, destinationDirectory: string, options?: IPacoteExtractOptions): Promise<void> => undefined
173+
});
171174

172175
return testInjector;
173176
}

0 commit comments

Comments
 (0)