• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

serverless-heaven / serverless-webpack / 24743128938

21 Apr 2026 07:51PM UTC coverage: 91.605% (-1.1%) from 92.749%
24743128938

Pull #2409

github

web-flow
Merge 7c5ae6af1 into 1b2f2ee5a
Pull Request #2409: Remove bluebird and use native Promise

1005 of 1145 branches covered (87.77%)

Branch coverage included in aggregate %.

569 of 631 new or added lines in 13 files covered. (90.17%)

2 existing lines in 1 file now uncovered.

2563 of 2750 relevant lines covered (93.2%)

72.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.52
/lib/packExternalModules.js
1
const _ = require('lodash');
2✔
2
const path = require('node:path');
2✔
3
const fse = require('fs-extra');
2✔
4
const findWorkspaceRoot = require('find-yarn-workspace-root');
2✔
5

2✔
6
const Packagers = require('./packagers');
2✔
7
const { isProviderGoogle } = require('./utils');
2✔
8

2✔
9
function callWithOptionalCallback(fn, ...args) {
88✔
10
  return new Promise((resolve, reject) => {
88✔
11
    let settled = false;
88✔
12

88✔
13
    const callback = (error, result) => {
88✔
14
      settled = true;
88✔
15
      if (error) {
88!
NEW
16
        reject(error);
×
NEW
17
        return;
×
NEW
18
      }
×
19
      resolve(result);
88✔
20
    };
88✔
21

88✔
22
    let result;
88✔
23
    try {
88✔
24
      result = fn(...args, callback);
88✔
25
    } catch (error) {
88!
NEW
26
      reject(error);
×
NEW
27
      return;
×
NEW
28
    }
×
29

88✔
30
    if (result && typeof result.then === 'function') {
88!
NEW
31
      result.then(
×
NEW
32
        value => {
×
NEW
33
          if (!settled) {
×
NEW
34
            resolve(value);
×
NEW
35
          }
×
NEW
36
        },
×
NEW
37
        error => {
×
NEW
38
          if (!settled) {
×
NEW
39
            reject(error);
×
NEW
40
          }
×
NEW
41
        }
×
NEW
42
      );
×
NEW
43
      return;
×
NEW
44
    }
×
45

88✔
46
    if (!settled) {
88✔
47
      resolve(result);
8✔
48
    }
8✔
49
  });
88✔
50
}
88✔
51

2✔
52
function rebaseFileReferences(pathToPackageRoot, moduleVersion) {
270✔
53
  if (/^(?:file:[^/]{2}|\.\/|\.\.\/)/.test(moduleVersion)) {
270✔
54
    const filePath = _.replace(moduleVersion, /^file:/, '');
4✔
55
    return _.replace(
4✔
56
      `${_.startsWith(moduleVersion, 'file:') ? 'file:' : ''}${pathToPackageRoot}/${filePath}`,
4!
57
      /\\/g,
4✔
58
      '/'
4✔
59
    );
4✔
60
  }
4✔
61

266✔
62
  return moduleVersion;
266✔
63
}
266✔
64

2✔
65
/**
2✔
66
 * Add the given modules to a package json's dependencies.
2✔
67
 */
2✔
68
function addModulesToPackageJson(externalModules, packageJson, pathToPackageRoot) {
90✔
69
  _.forEach(externalModules.sort(), externalModule => {
90✔
70
    const splitModule = _.split(externalModule, '@');
270✔
71
    // If we have a scoped module we have to re-add the @
270✔
72
    if (_.startsWith(externalModule, '@')) {
270✔
73
      splitModule.splice(0, 1);
62✔
74
      splitModule[0] = `@${splitModule[0]}`;
62✔
75
    }
62✔
76
    let moduleVersion = _.join(_.tail(splitModule), '@');
270✔
77
    // We have to rebase file references to the target package.json
270✔
78
    moduleVersion = rebaseFileReferences(pathToPackageRoot, moduleVersion);
270✔
79
    packageJson.dependencies = packageJson.dependencies || {};
270✔
80
    packageJson.dependencies[_.first(splitModule)] = moduleVersion;
270✔
81
  });
90✔
82
}
90✔
83

2✔
84
/**
2✔
85
 * Remove a given list of excluded modules from a module list
2✔
86
 * @this - The active plugin instance
2✔
87
 */
2✔
88
function removeExcludedModules(modules, packageForceExcludes, log) {
92✔
89
  const excludedModules = _.remove(modules, externalModule => {
92✔
90
    const splitModule = _.split(externalModule, '@');
274✔
91
    // If we have a scoped module we have to re-add the @
274✔
92
    if (_.startsWith(externalModule, '@')) {
274✔
93
      splitModule.splice(0, 1);
62✔
94
      splitModule[0] = `@${splitModule[0]}`;
62✔
95
    }
62✔
96
    const moduleName = _.first(splitModule);
274✔
97
    return _.includes(packageForceExcludes, moduleName);
274✔
98
  });
92✔
99

92✔
100
  if (log && !_.isEmpty(excludedModules)) {
92✔
101
    if (this.log) {
2!
102
      this.log(`Excluding external modules: ${_.join(excludedModules, ', ')}`);
×
103
    } else {
2✔
104
      this.serverless.cli.log(`Excluding external modules: ${_.join(excludedModules, ', ')}`);
2✔
105
    }
2✔
106
  }
2✔
107
}
92✔
108

2✔
109
/**
2✔
110
 * Resolve the needed versions of production dependencies for external modules.
2✔
111
 * @this - The active plugin instance
2✔
112
 */
2✔
113
function getProdModules(externalModules, packagePath, nodeModulesRelativeDir, dependencyGraph, forceExcludes) {
106✔
114
  const packageJsonPath = path.join(process.cwd(), packagePath);
106✔
115
  const packageJson = require(packageJsonPath);
106✔
116
  const prodModules = [];
106✔
117

106✔
118
  // only process the module stated in dependencies section
106✔
119
  if (!packageJson.dependencies) {
106!
120
    return [];
×
121
  }
×
122

106✔
123
  // Get versions of all transient modules
106✔
124
  _.forEach(externalModules, module => {
106✔
125
    let moduleVersion = packageJson.dependencies[module.external];
288✔
126

288✔
127
    if (moduleVersion) {
288✔
128
      prodModules.push(`${module.external}@${moduleVersion}`);
258✔
129

258✔
130
      let nodeModulesBase = path.join(path.dirname(path.join(process.cwd(), packagePath)), 'node_modules');
258✔
131

258✔
132
      if (nodeModulesRelativeDir) {
258✔
133
        const customNodeModulesDir = path.join(process.cwd(), nodeModulesRelativeDir, 'node_modules');
12✔
134

12✔
135
        if (fse.pathExistsSync(customNodeModulesDir)) {
12✔
136
          nodeModulesBase = customNodeModulesDir;
12✔
137
        } else {
12!
138
          if (this.log) {
×
139
            this.log.warning(`${customNodeModulesDir} dose not exist. Please check nodeModulesRelativeDir setting`);
×
140
          } else {
×
141
            this.serverless.cli.log(
×
142
              `WARNING: ${customNodeModulesDir} dose not exist. Please check nodeModulesRelativeDir setting`
×
143
            );
×
144
          }
×
145
        }
×
146
      }
12✔
147

258✔
148
      // Check if the module has any peer dependencies and include them too
258✔
149
      try {
258✔
150
        const modulePackagePath = path.join(nodeModulesBase, module.external, 'package.json');
258✔
151

258✔
152
        const peerDependencies = require(modulePackagePath).peerDependencies;
258✔
153
        if (!_.isEmpty(peerDependencies)) {
258✔
154
          if (this.log) {
12!
155
            this.log.verbose(`Adding explicit peers for dependency ${module.external}`);
×
156
          } else {
12✔
157
            this.options.verbose && this.serverless.cli.log(`Adding explicit peers for dependency ${module.external}`);
12✔
158
          }
12✔
159

12✔
160
          const peerDependenciesMeta = require(modulePackagePath).peerDependenciesMeta;
12✔
161

12✔
162
          if (!_.isEmpty(peerDependenciesMeta)) {
12✔
163
            _.forEach(peerDependencies, (_value, key) => {
8✔
164
              if (peerDependenciesMeta[key] && peerDependenciesMeta[key].optional === true) {
12✔
165
                if (this.log) {
4!
166
                  this.log.verbose(
×
167
                    `Skipping peers dependency ${key} for dependency ${module.external} because it's optional`
×
168
                  );
×
169
                } else {
4✔
170
                  this.options.verbose &&
4✔
171
                    this.serverless.cli.log(
4✔
172
                      `Skipping peers dependency ${key} for dependency ${module.external} because it's optional`
4✔
173
                    );
4✔
174
                }
4✔
175
                _.unset(peerDependencies, key);
4✔
176
              }
4✔
177
            });
8✔
178
          }
8✔
179

12✔
180
          if (!_.isEmpty(peerDependencies)) {
12✔
181
            const peerModules = getProdModules.call(
12✔
182
              this,
12✔
183
              _.map(peerDependencies, (_value, key) => ({ external: key })),
12✔
184
              packagePath,
12✔
185
              nodeModulesRelativeDir,
12✔
186
              dependencyGraph,
12✔
187
              forceExcludes
12✔
188
            );
12✔
189
            Array.prototype.push.apply(prodModules, peerModules);
12✔
190
          }
12✔
191
        }
12✔
192
      } catch (_e) {
258✔
193
        if (this.log) {
110✔
194
          this.log.warning(
4✔
195
            `Could not check for peer dependencies of ${module.external}. Set nodeModulesRelativeDir if node_modules is in different directory.`
4✔
196
          );
4✔
197
        } else {
110✔
198
          this.serverless.cli.log(
106✔
199
            `WARNING: Could not check for peer dependencies of ${module.external}. Set nodeModulesRelativeDir if node_modules is in different directory.`
106✔
200
          );
106✔
201
        }
106✔
202
      }
110✔
203
    } else {
288✔
204
      if (!packageJson.devDependencies?.[module.external]) {
30✔
205
        // Add transient dependencies if they appear not in the service's dev dependencies
16✔
206
        const originInfo = _.get(dependencyGraph, 'dependencies', {})[module.origin] || {};
16✔
207
        moduleVersion = _.get(_.get(originInfo, 'dependencies', {})[module.external], 'version');
16✔
208
        if (!moduleVersion) {
16✔
209
          moduleVersion = _.get(dependencyGraph, ['dependencies', module.external, 'version']);
16✔
210
        }
16✔
211
        if (!moduleVersion) {
16✔
212
          if (this.log) {
12!
213
            this.log.warning(`Could not determine version of module ${module.external}`);
×
214
          } else {
12✔
215
            this.serverless.cli.log(`WARNING: Could not determine version of module ${module.external}`);
12✔
216
          }
12✔
217
        }
12✔
218
        prodModules.push(moduleVersion ? `${module.external}@${moduleVersion}` : module.external);
16✔
219
      } else if (packageJson.devDependencies?.[module.external] && !_.includes(forceExcludes, module.external)) {
30✔
220
        // To minimize the chance of breaking setups we whitelist packages available on AWS here. These are due to the previously missing check
10✔
221
        // most likely set in devDependencies and should not lead to an error now.
10✔
222
        const ignoredDevDependencies = ['aws-sdk'];
10✔
223

10✔
224
        if (!_.includes(ignoredDevDependencies, module.external)) {
10✔
225
          // Runtime dependency found in devDependencies but not forcefully excluded
2✔
226
          if (this.log) {
2!
227
            this.log.error(
×
228
              `Runtime dependency '${module.external}' found in devDependencies. Move it to dependencies or use forceExclude to explicitly exclude it.`
×
229
            );
×
230
          } else {
2✔
231
            this.serverless.cli.log(
2✔
232
              `ERROR: Runtime dependency '${module.external}' found in devDependencies. Move it to dependencies or use forceExclude to explicitly exclude it.`
2✔
233
            );
2✔
234
          }
2✔
235
          throw new this.serverless.classes.Error(`Serverless-webpack dependency error: ${module.external}.`);
2✔
236
        }
2✔
237
        if (this.log) {
10✔
238
          this.log.verbose(
4✔
239
            `Runtime dependency '${module.external}' found in devDependencies. It has been excluded automatically.`
4✔
240
          );
4✔
241
        } else {
4✔
242
          this.options.verbose &&
4✔
243
            this.serverless.cli.log(
4✔
244
              `INFO: Runtime dependency '${module.external}' found in devDependencies. It has been excluded automatically.`
4✔
245
            );
4✔
246
        }
4✔
247
      }
10✔
248
    }
30✔
249
  });
106✔
250

106✔
251
  return prodModules;
106✔
252
}
106✔
253

2✔
254
module.exports = {
2✔
255
  /**
2✔
256
   * We need a performant algorithm to install the packages for each single
2✔
257
   * function (in case we package individually).
2✔
258
   * (1) We fetch ALL packages needed by ALL functions in a first step
2✔
259
   * and use this as a base npm checkout. The checkout will be done to a
2✔
260
   * separate temporary directory with a package.json that contains everything.
2✔
261
   * (2) For each single compile we copy the whole node_modules to the compile
2✔
262
   * directory and create a (function) compile specific package.json and store
2✔
263
   * it in the compile directory. Now we start npm again there, and npm will just
2✔
264
   * remove the superfluous packages and optimize the remaining dependencies.
2✔
265
   * This will utilize the npm cache at its best and give us the needed results
2✔
266
   * and performance.
2✔
267
   */
2✔
268
  async packExternalModules() {
2✔
269
    if (this.skipCompile) {
56✔
270
      return;
2✔
271
    }
2✔
272

54✔
273
    const stats = this.compileStats;
54✔
274

54✔
275
    const includes = this.configuration.includeModules;
54✔
276

54✔
277
    if (!includes) {
56✔
278
      return;
2✔
279
    }
2✔
280
    if (this.log) {
56✔
281
      this.log.verbose('Packing external modules');
6✔
282
      this.progress.get('webpack').notice('[Webpack] Packing external modules');
6✔
283
    }
6✔
284

52✔
285
    // Read plugin configuration
52✔
286
    const packageForceIncludes = _.get(includes, 'forceInclude', []);
52✔
287
    const packageForceExcludes = _.get(includes, 'forceExclude', []);
52✔
288
    const packagePath = includes.packagePath || './package.json';
56✔
289
    const nodeModulesRelativeDir = includes.nodeModulesRelativeDir;
56✔
290
    const packageJsonPath = path.join(process.cwd(), packagePath);
56✔
291
    const packageScripts = _.reduce(
56✔
292
      this.configuration.packagerOptions.scripts || [],
56✔
293
      (__, script, index) => {
56✔
294
        __[`script${index}`] = script;
×
295
        return __;
×
296
      },
56✔
297
      {}
56✔
298
    );
56✔
299

56✔
300
    // Determine and create packager
56✔
301
    const packager = Packagers.get.call(this, this.configuration.packager);
56✔
302

56✔
303
    // Fetch needed original package.json sections
56✔
304
    const sectionNames = packager.copyPackageSectionNames(this.configuration.packagerOptions);
56✔
305
    const packageJson = this.serverless.utils.readFileSync(packageJsonPath);
56✔
306
    const packageSections = _.pick(packageJson, sectionNames);
56✔
307
    if (!_.isEmpty(packageSections)) {
56✔
308
      if (this.log) {
4!
NEW
309
        this.log.verbose(`Using package.json sections ${_.join(_.keys(packageSections), ', ')}`);
×
310
      } else {
4✔
311
        this.options.verbose &&
4✔
312
          this.serverless.cli.log(`Using package.json sections ${_.join(_.keys(packageSections), ', ')}`);
4✔
313
      }
4✔
314
    }
4✔
315

52✔
316
    // Get first level dependency graph
52✔
317
    if (this.log) {
56✔
318
      this.log.verbose(`Fetch dependency graph from ${packageJsonPath}`);
6✔
319
    } else {
56✔
320
      this.options.verbose && this.serverless.cli.log(`Fetch dependency graph from ${packageJsonPath}`);
46✔
321
    }
46✔
322

52✔
323
    const dependencyGraph = await packager.getProdDependencies(
52✔
324
      path.dirname(packageJsonPath),
52✔
325
      1,
52✔
326
      this.configuration.packagerOptions
52✔
327
    );
52✔
328
    const problems = _.get(dependencyGraph, 'problems', []);
50✔
329
    if (this.options.verbose && !_.isEmpty(problems)) {
56✔
330
      if (this.log) {
2!
NEW
331
        this.log.verbose(`Ignoring ${_.size(problems)} NPM errors:`);
×
332
      } else {
2✔
333
        this.serverless.cli.log(`Ignoring ${_.size(problems)} NPM errors:`);
2✔
334
      }
2✔
335
      _.forEach(problems, problem => {
2✔
336
        if (this.log) {
4!
NEW
337
          this.log.verbose(`=> ${problem}`);
×
338
        } else {
4✔
339
          this.serverless.cli.log(`=> ${problem}`);
4✔
340
        }
4✔
341
      });
2✔
342
    }
2✔
343

50✔
344
    // (1) Generate dependency composition
50✔
345
    const compositeModules = _.uniq(
50✔
346
      _.flatMap(stats.stats, compileStats => {
50✔
347
        const externalModules = _.concat(
50✔
348
          compileStats.externalModules,
50✔
349
          _.map(packageForceIncludes, whitelistedPackage => ({
50✔
350
            external: whitelistedPackage
8✔
351
          }))
50✔
352
        );
50✔
353
        return getProdModules.call(
50✔
354
          this,
50✔
355
          externalModules,
50✔
356
          packagePath,
50✔
357
          nodeModulesRelativeDir,
50✔
358
          dependencyGraph,
50✔
359
          packageForceExcludes
50✔
360
        );
50✔
361
      })
50✔
362
    );
50✔
363
    removeExcludedModules.call(this, compositeModules, packageForceExcludes, true);
50✔
364

50✔
365
    if (_.isEmpty(compositeModules)) {
56✔
366
      // The compiled code does not reference any external modules at all
2✔
367
      if (this.log) {
2!
NEW
368
        this.log('No external modules needed');
×
369
      } else {
2✔
370
        this.serverless.cli.log('No external modules needed');
2✔
371
      }
2✔
372
      return;
2✔
373
    }
2✔
374

46✔
375
    // (1.a) Install all needed modules
46✔
376
    const compositeModulePath = path.join(this.webpackOutputPath, 'dependencies');
46✔
377
    const compositePackageJson = path.join(compositeModulePath, 'package.json');
46✔
378

46✔
379
    // (1.a.1) Create a package.json
46✔
380
    const compositePackage = _.defaults(
46✔
381
      {
46✔
382
        name: this.serverless.service.service,
46✔
383
        version: '1.0.0',
46✔
384
        description: `Packaged externals for ${this.serverless.service.service}`,
46✔
385
        private: true,
46✔
386
        scripts: packageScripts
46✔
387
      },
46✔
388
      packageSections
46✔
389
    );
46✔
390
    const relPath = path.relative(compositeModulePath, path.dirname(packageJsonPath));
46✔
391
    addModulesToPackageJson(compositeModules, compositePackage, relPath);
46✔
392
    this.serverless.utils.writeFileSync(compositePackageJson, JSON.stringify(compositePackage, null, 2));
46✔
393

46✔
394
    // (1.a.2) Copy package-lock.json if it exists, to prevent unwanted upgrades
46✔
395
    const packagerOptions = this.configuration.packagerOptions || {};
56!
396
    const packageLockPath = path.join(
56✔
397
      findWorkspaceRoot(path.dirname(packageJsonPath)) || path.dirname(packageJsonPath),
56✔
398
      packagerOptions.lockFile || packager.lockfileName
56✔
399
    );
56✔
400
    let hasPackageLock = false;
56✔
401
    const exists = await callWithOptionalCallback(fse.pathExists, packageLockPath);
56✔
402
    if (exists) {
56✔
403
      if (this.log) {
10!
NEW
404
        this.log('Package lock found - Using locked versions');
×
405
      } else {
10✔
406
        this.serverless.cli.log('Package lock found - Using locked versions');
10✔
407
      }
10✔
408
      try {
10✔
409
        let packageLockFile = this.serverless.utils.readFileSync(packageLockPath);
10✔
410
        packageLockFile = packager.rebaseLockfile(relPath, packageLockFile);
10✔
411
        if (_.isObject(packageLockFile)) {
10✔
412
          packageLockFile = JSON.stringify(packageLockFile, null, 2);
6✔
413
        }
6✔
414

6✔
415
        this.serverless.utils.writeFileSync(path.join(compositeModulePath, packager.lockfileName), packageLockFile);
6✔
416
        hasPackageLock = true;
6✔
417
      } catch (err) {
10✔
418
        if (this.log) {
4!
NEW
419
          this.log.warning(`Could not read lock file: ${err.message}`);
×
420
        } else {
4✔
421
          this.serverless.cli.log(`Warning: Could not read lock file: ${err.message}`);
4✔
422
        }
4✔
423
      }
4✔
424
    }
10✔
425

46✔
426
    const start = _.now();
46✔
427
    if (this.log) {
56✔
428
      this.log(`Packing external modules: ${compositeModules.join(', ')}`);
6✔
429
    } else {
56✔
430
      this.serverless.cli.log(`Packing external modules: ${compositeModules.join(', ')}`);
40✔
431
    }
40✔
432

46✔
433
    const compositePackagerVersion = await packager.getPackagerVersion(compositeModulePath);
46✔
434
    await packager.install(compositeModulePath, this.configuration.packagerOptions, compositePackagerVersion);
46✔
435
    if (this.log) {
56✔
436
      this.log.verbose(`Package took [${_.now() - start} ms]`);
6✔
437
    } else {
56✔
438
      this.options.verbose && this.serverless.cli.log(`Package took [${_.now() - start} ms]`);
38✔
439
    }
38✔
440

44✔
441
    for (const compileStats of stats.stats) {
44✔
442
      const modulePath = compileStats.outputPath;
44✔
443

44✔
444
      // Create package.json
44✔
445
      const modulePackageJson = path.join(modulePath, 'package.json');
44✔
446
      const modulePackage = _.defaults(
44✔
447
        {
44✔
448
          name: this.serverless.service.service,
44✔
449
          version: '1.0.0',
44✔
450
          description: `Packaged externals for ${this.serverless.service.service}`,
44✔
451
          private: true,
44✔
452
          scripts: packageScripts,
44✔
453
          dependencies: {}
44✔
454
        },
44✔
455
        packageSections
44✔
456
      );
44✔
457
      const prodModules = getProdModules.call(
44✔
458
        this,
44✔
459
        _.concat(
44✔
460
          compileStats.externalModules,
44✔
461
          _.map(packageForceIncludes, whitelistedPackage => ({
44✔
462
            external: whitelistedPackage
8✔
463
          }))
44✔
464
        ),
44✔
465
        packagePath,
44✔
466
        nodeModulesRelativeDir,
44✔
467
        dependencyGraph,
44✔
468
        packageForceExcludes
44✔
469
      );
44✔
470
      removeExcludedModules.call(this, prodModules, packageForceExcludes);
44✔
471
      const moduleRelPath = path.relative(modulePath, path.dirname(packageJsonPath));
44✔
472
      addModulesToPackageJson(prodModules, modulePackage, moduleRelPath);
44✔
473
      this.serverless.utils.writeFileSync(modulePackageJson, JSON.stringify(modulePackage, null, 2));
44✔
474

44✔
475
      // GOOGLE: Copy modules only if not google-cloud-functions
44✔
476
      //         GCF Auto installs the package json
44✔
477
      if (isProviderGoogle(this.serverless)) {
44✔
478
        continue;
2✔
479
      }
2✔
480

42✔
481
      const startCopy = _.now();
42✔
482
      // Only copy dependency modules if demanded by packager
42✔
483
      if (packager.mustCopyModules) {
44✔
484
        await callWithOptionalCallback(
36✔
485
          fse.copy,
36✔
486
          path.join(compositeModulePath, 'node_modules'),
36✔
487
          path.join(modulePath, 'node_modules')
36✔
488
        );
36✔
489
      }
36✔
490
      if (hasPackageLock) {
44✔
491
        await callWithOptionalCallback(
6✔
492
          fse.copy,
6✔
493
          path.join(compositeModulePath, packager.lockfileName),
6✔
494
          path.join(modulePath, packager.lockfileName)
6✔
495
        );
6✔
496
      }
6✔
497
      if (this.log) {
44✔
498
        this.log.verbose(`Copy modules: ${modulePath} [${_.now() - startCopy} ms]`);
6✔
499
      } else {
44✔
500
        this.options.verbose && this.serverless.cli.log(`Copy modules: ${modulePath} [${_.now() - startCopy} ms]`);
36✔
501
      }
36✔
502

42✔
503
      // Prune extraneous packages - removes not needed ones
42✔
504
      const startPrune = _.now();
42✔
505
      const modulePackagerVersion = await packager.getPackagerVersion(modulePath);
42✔
506
      await packager.prune(modulePath, this.configuration.packagerOptions, modulePackagerVersion);
42✔
507
      if (this.log) {
44✔
508
        this.log.verbose(`Prune: ${modulePath} [${_.now() - startPrune} ms]`);
6✔
509
      } else {
44✔
510
        this.options.verbose && this.serverless.cli.log(`Prune: ${modulePath} [${_.now() - startPrune} ms]`);
36✔
511
      }
36✔
512

42✔
513
      // Run package scripts after prune
42✔
514
      const startRunScripts = _.now();
42✔
515
      await packager.runScripts(modulePath, _.keys(packageScripts));
42✔
516
      if (this.log) {
44✔
517
        this.log.verbose(`Run scripts: ${modulePath} [${_.now() - startRunScripts} ms]`);
6✔
518
      } else {
44✔
519
        this.options.verbose && this.serverless.cli.log(`Run scripts: ${modulePath} [${_.now() - startRunScripts} ms]`);
36✔
520
      }
36✔
521
    }
44✔
522
  }
44✔
523
};
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc