From 2c905c53b6bd7b671cd3a84cf12ac9246b424590 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Thu, 29 Sep 2016 18:34:24 +0300 Subject: [PATCH] Stop calling npm install on each prepare of ng projects During project preparation CLI's trying to detect if all dependencies from package.json are installed by listing contents of node_modules directory. In case any of them are missing, CLI calls `npm install` inside the project. This executes all postinstall scripts of the dependencies and leads to slower prepare (and also slower builds in lots of cases). The problem is that the code is reading the contents of node_modules directory, but scoped dependencies (used in all angular projects) are not in the root of node_modules. So in all Angular projects each prepare calls `npm install`. Fix the listing of the directories to include scoped packages, so in case everything is installed, CLI will not call npm install on the next preparation of the project. --- lib/services/plugins-service.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/services/plugins-service.ts b/lib/services/plugins-service.ts index e67bec772e..fc91f67fc6 100644 --- a/lib/services/plugins-service.ts +++ b/lib/services/plugins-service.ts @@ -145,9 +145,21 @@ export class PluginsService implements IPluginsService { public ensureAllDependenciesAreInstalled(): IFuture { return (() => { let installedDependencies = this.$fs.exists(this.nodeModulesPath).wait() ? this.$fs.readDirectory(this.nodeModulesPath).wait() : []; + // Scoped dependencies are not on the root of node_modules, + // so we have to list the contents of all directories, starting with @ + // and add them to installed dependencies, so we can apply correct comparison against package.json's dependencies. + _(installedDependencies) + .filter(dependencyName => _.startsWith(dependencyName, "@")) + .each(scopedDependencyDir => { + let contents = this.$fs.readDirectory(path.join(this.nodeModulesPath, scopedDependencyDir)).wait(); + installedDependencies = installedDependencies.concat(...contents.map(dependencyName => `${scopedDependencyDir}/${dependencyName}`)); + }); + let packageJsonContent = this.$fs.readJson(this.getPackageJsonFilePath()).wait(); let allDependencies = _.keys(packageJsonContent.dependencies).concat(_.keys(packageJsonContent.devDependencies)); - if (this.$options.force || _.difference(allDependencies, installedDependencies).length) { + let notInstalledDependencies = _.difference(allDependencies, installedDependencies); + if (this.$options.force || notInstalledDependencies.length) { + this.$logger.trace("Npm install will be called from CLI. Force option is: ", this.$options.force, " Not installed dependencies are: ", notInstalledDependencies); this.$npm.install(this.$projectData.projectDir, this.$projectData.projectDir, { "ignore-scripts": this.$options.ignoreScripts }).wait(); } }).future()();