Skip to content

Commit 68c3b28

Browse files
authored
Merge pull request #216 from elastic-coders/ignore-minor-npm-ls-warnings
Ignore irrelevant NPM problems when building the dependency graph
2 parents 8d4a98a + 51ad4b1 commit 68c3b28

File tree

2 files changed

+328
-113
lines changed

2 files changed

+328
-113
lines changed

lib/packExternalModules.js

Lines changed: 103 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -116,81 +116,115 @@ module.exports = {
116116
this.options.verbose && this.serverless.cli.log(`Fetch dependency graph from ${packageJsonPath}`);
117117
// Get first level dependency graph
118118
const command = 'npm ls -prod -json -depth=1'; // Only prod dependencies
119-
let dependencyGraph = {};
120-
try {
121-
const depJson = childProcess.execSync(command, {
119+
120+
const ignoredNpmErrors = [
121+
{ npmError: 'extraneous', log: false },
122+
{ npmError: 'missing', log: false },
123+
{ npmError: 'peer dep missing', log: true },
124+
];
125+
126+
return BbPromise.fromCallback(cb => {
127+
childProcess.exec(command, {
122128
cwd: path.dirname(packageJsonPath),
123129
maxBuffer: this.serverless.service.custom.packExternalModulesMaxBuffer || 200 * 1024,
124130
encoding: 'utf8'
131+
}, (err, stdout, stderr) => {
132+
if (err) {
133+
// Only exit with an error if we have critical npm errors for 2nd level inside
134+
const errors = _.split(stderr, '\n');
135+
const failed = _.reduce(errors, (failed, error) => {
136+
if (failed) {
137+
return true;
138+
}
139+
return !_.isEmpty(error) && !_.some(ignoredNpmErrors, ignoredError => _.startsWith(error, `npm ERR! ${ignoredError.npmError}`));
140+
}, false);
141+
142+
if (failed) {
143+
return cb(err);
144+
}
145+
}
146+
return cb(null, stdout);
125147
});
126-
dependencyGraph = JSON.parse(depJson);
127-
} catch (e) {
128-
// We rethrow here. It's not recoverable.
129-
throw e;
130-
}
131-
132-
// (1) Generate dependency composition
133-
const compositeModules = _.uniq(_.flatMap(stats.stats, compileStats => {
134-
const externalModules = getExternalModules.call(this, compileStats);
135-
return getProdModules.call(this, externalModules, packagePath, dependencyGraph);
136-
}));
148+
})
149+
.then(depJson => BbPromise.try(() => JSON.parse(depJson)))
150+
.then(dependencyGraph => {
151+
const problems = _.get(dependencyGraph, 'problems', []);
152+
if (this.options.verbose && !_.isEmpty(problems)) {
153+
this.serverless.cli.log(`Ignoring ${_.size(problems)} NPM errors:`);
154+
_.forEach(problems, problem => {
155+
this.serverless.cli.log(`=> ${problem}`);
156+
});
157+
}
137158

138-
// (1.a) Install all needed modules
139-
const compositeModulePath = path.join(this.webpackOutputPath, 'dependencies');
140-
const compositePackageJson = path.join(compositeModulePath, 'package.json');
141-
this.serverless.utils.writeFileSync(compositePackageJson, '{}');
159+
// (1) Generate dependency composition
160+
const compositeModules = _.uniq(_.flatMap(stats.stats, compileStats => {
161+
const externalModules = getExternalModules.call(this, compileStats);
162+
return getProdModules.call(this, externalModules, packagePath, dependencyGraph);
163+
}));
142164

143-
this.serverless.cli.log('Packing external modules: ' + compositeModules.join(', '));
165+
if (_.isEmpty(compositeModules)) {
166+
// The compiled code does not reference any external modules at all
167+
this.serverless.cli.log('No external modules needed');
168+
return BbPromise.resolve(stats);
169+
}
144170

145-
return new BbPromise((resolve, reject) => {
146-
const start = _.now();
147-
npm.install(compositeModules, {
148-
cwd: compositeModulePath,
149-
maxBuffer: this.serverless.service.custom.packExternalModulesMaxBuffer || 200 * 1024,
150-
save: true
151-
}).then(() => {
152-
this.options.verbose && this.serverless.cli.log(`Package took [${_.now() - start} ms]`); // eslint-disable-line promise/always-return
153-
resolve(stats.stats);
154-
}).catch(e => {
155-
reject(e);
156-
});
157-
})
158-
.mapSeries(compileStats => {
159-
const modulePath = compileStats.compilation.compiler.outputPath;
160-
161-
// Create package.json
162-
const modulePackageJson = path.join(modulePath, 'package.json');
163-
const modulePackage = {
164-
dependencies: {}
165-
};
166-
const prodModules = getProdModules.call(this, getExternalModules.call(this, compileStats), packagePath, dependencyGraph);
167-
_.forEach(prodModules, prodModule => {
168-
const splitModule = _.split(prodModule, '@');
169-
// If we have a scoped module we have to re-add the @
170-
if (_.startsWith(prodModule, '@')) {
171-
splitModule.splice(0, 1);
172-
splitModule[0] = '@' + splitModule[0];
173-
}
174-
const moduleVersion = _.join(_.tail(splitModule), '@');
175-
modulePackage.dependencies[_.first(splitModule)] = moduleVersion;
176-
});
177-
this.serverless.utils.writeFileSync(modulePackageJson, JSON.stringify(modulePackage, null, 2));
178-
179-
// Copy modules
180-
const startCopy = _.now();
181-
return BbPromise.fromCallback(callback => fse.copy(path.join(compositeModulePath, 'node_modules'), path.join(modulePath, 'node_modules'), callback))
182-
.tap(() => this.options.verbose && this.serverless.cli.log(`Copy modules: ${modulePath} [${_.now() - startCopy} ms]`))
183-
.then(() => {
184-
// Prune extraneous packages - removes not needed ones
185-
const startPrune = _.now();
186-
return BbPromise.fromCallback(callback => {
187-
childProcess.exec('npm prune', {
188-
cwd: modulePath
189-
}, callback);
190-
})
191-
.tap(() => this.options.verbose && this.serverless.cli.log(`Prune: ${modulePath} [${_.now() - startPrune} ms]`));
192-
});
193-
})
194-
.return(stats);
171+
// (1.a) Install all needed modules
172+
const compositeModulePath = path.join(this.webpackOutputPath, 'dependencies');
173+
const compositePackageJson = path.join(compositeModulePath, 'package.json');
174+
this.serverless.utils.writeFileSync(compositePackageJson, '{}');
175+
176+
this.serverless.cli.log('Packing external modules: ' + compositeModules.join(', '));
177+
178+
return new BbPromise((resolve, reject) => {
179+
const start = _.now();
180+
npm.install(compositeModules, {
181+
cwd: compositeModulePath,
182+
maxBuffer: this.serverless.service.custom.packExternalModulesMaxBuffer || 200 * 1024,
183+
save: true
184+
}).then(() => {
185+
this.options.verbose && this.serverless.cli.log(`Package took [${_.now() - start} ms]`); // eslint-disable-line promise/always-return
186+
resolve(stats.stats);
187+
}).catch(e => {
188+
reject(e);
189+
});
190+
})
191+
.mapSeries(compileStats => {
192+
const modulePath = compileStats.compilation.compiler.outputPath;
193+
194+
// Create package.json
195+
const modulePackageJson = path.join(modulePath, 'package.json');
196+
const modulePackage = {
197+
dependencies: {}
198+
};
199+
const prodModules = getProdModules.call(this, getExternalModules.call(this, compileStats), packagePath, dependencyGraph);
200+
_.forEach(prodModules, prodModule => {
201+
const splitModule = _.split(prodModule, '@');
202+
// If we have a scoped module we have to re-add the @
203+
if (_.startsWith(prodModule, '@')) {
204+
splitModule.splice(0, 1);
205+
splitModule[0] = '@' + splitModule[0];
206+
}
207+
const moduleVersion = _.join(_.tail(splitModule), '@');
208+
modulePackage.dependencies[_.first(splitModule)] = moduleVersion;
209+
});
210+
this.serverless.utils.writeFileSync(modulePackageJson, JSON.stringify(modulePackage, null, 2));
211+
212+
// Copy modules
213+
const startCopy = _.now();
214+
return BbPromise.fromCallback(callback => fse.copy(path.join(compositeModulePath, 'node_modules'), path.join(modulePath, 'node_modules'), callback))
215+
.tap(() => this.options.verbose && this.serverless.cli.log(`Copy modules: ${modulePath} [${_.now() - startCopy} ms]`))
216+
.then(() => {
217+
// Prune extraneous packages - removes not needed ones
218+
const startPrune = _.now();
219+
return BbPromise.fromCallback(callback => {
220+
childProcess.exec('npm prune', {
221+
cwd: modulePath
222+
}, callback);
223+
})
224+
.tap(() => this.options.verbose && this.serverless.cli.log(`Prune: ${modulePath} [${_.now() - startPrune} ms]`));
225+
});
226+
})
227+
.return(stats);
228+
});
195229
}
196230
};

0 commit comments

Comments
 (0)