Serverless Framework plugin that bundles Lambda functions with Webpack for optimized JavaScript deployment packages
—
Package manager abstraction supporting npm and yarn with workspace and monorepo capabilities. The packager system provides a unified interface for different package managers while handling their specific requirements and optimizations.
Factory function for obtaining packager instances.
/**
* Get a packager instance by identifier
* @param packagerId - Package manager type ('npm' or 'yarn')
* @returns Packager instance with static methods
*/
function get(packagerId: 'npm' | 'yarn'): Packager;Usage Examples:
const packagers = require('serverless-webpack/lib/packagers');
// Get npm packager
const npm = packagers.get('npm');
console.log('NPM lock file:', npm.lockfileName); // 'package-lock.json'
// Get yarn packager
const yarn = packagers.get('yarn');
console.log('Yarn lock file:', yarn.lockfileName); // 'yarn.lock'Common interface implemented by all package managers.
interface Packager {
/** Name of the lock file used by this packager */
static lockfileName: string;
/** Whether this packager requires copying node_modules */
static mustCopyModules: boolean;
/**
* Get sections of package.json to copy during packaging
* @param packagerOptions - Configuration options for the packager
* @returns Array of package.json section names to copy
*/
static copyPackageSectionNames(packagerOptions: object): string[];
/**
* Get version information for the package manager
* @param cwd - Working directory path
* @returns Promise resolving to version object
*/
static getPackagerVersion(cwd: string): Promise<{version: string}>;
/**
* Get production dependencies from package files
* @param cwd - Working directory path
* @param depth - Dependency tree depth (optional)
* @returns Promise resolving to dependency tree object
*/
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
/**
* Rebase lock file paths for different directory structure
* @param pathToPackageRoot - Path to package root directory
* @param lockfile - Lock file object to modify
*/
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
/**
* Install dependencies using the package manager
* @param cwd - Working directory path
* @param packagerOptions - Package manager specific options
* @returns Promise that resolves when installation completes
*/
static install(cwd: string, packagerOptions?: object): Promise<void>;
/**
* Remove development dependencies (production-only install)
* @param cwd - Working directory path
* @param packagerOptions - Package manager specific options
* @returns Promise that resolves when pruning completes
*/
static prune(cwd: string, packagerOptions?: object): Promise<void>;
/**
* Run package.json scripts
* @param cwd - Working directory path
* @param scriptNames - Array of script names to execute
* @returns Promise that resolves when scripts complete
*/
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
}NPM package manager implementation with support for all NPM versions and package-lock.json handling.
class NPM implements Packager {
static lockfileName: 'package-lock.json';
static mustCopyModules: false;
static copyPackageSectionNames(packagerOptions: object): string[];
static getPackagerVersion(cwd: string): Promise<{version: string}>;
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
static install(cwd: string, packagerOptions?: object): Promise<void>;
static prune(cwd: string, packagerOptions?: object): Promise<void>;
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
}Usage Examples:
const packagers = require('serverless-webpack/lib/packagers');
const npm = packagers.get('npm');
// Get NPM version
const version = await npm.getPackagerVersion('/path/to/project');
console.log('NPM version:', version.version);
// Install dependencies
await npm.install('/path/to/project', {
ignoreScripts: true,
production: true
});
// Get production dependencies
const deps = await npm.getProdDependencies('/path/to/project');
console.log('Dependencies:', Object.keys(deps.dependencies));
// Run custom scripts
await npm.runScripts('/path/to/project', ['postinstall', 'prepare']);Yarn package manager implementation with support for both Yarn Classic (v1) and Yarn Berry (v2+), workspaces, and yarn.lock handling.
class Yarn implements Packager {
static lockfileName: 'yarn.lock';
static mustCopyModules: true;
static copyPackageSectionNames(packagerOptions: object): string[];
static getPackagerVersion(cwd: string): Promise<{version: string}>;
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
static install(cwd: string, packagerOptions?: object): Promise<void>;
static prune(cwd: string, packagerOptions?: object): Promise<void>;
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
/**
* Check if this is Yarn Berry (v2+) vs Yarn Classic (v1)
* @param version - Yarn version string
* @returns True if Yarn Berry, false if Yarn Classic
*/
static isBerryVersion(version: string): boolean;
}Usage Examples:
const packagers = require('serverless-webpack/lib/packagers');
const yarn = packagers.get('yarn');
// Check Yarn version type
const version = await yarn.getPackagerVersion('/path/to/project');
const isBerry = yarn.isBerryVersion(version.version);
console.log('Using Yarn Berry:', isBerry);
// Install with yarn-specific options
await yarn.install('/path/to/project', {
ignoreScripts: false,
production: true,
frozenLockfile: true
});
// Yarn requires copying node_modules
console.log('Must copy modules:', yarn.mustCopyModules); // true
// Get production dependencies (handles workspaces)
const deps = await yarn.getProdDependencies('/path/to/project');Package managers can be configured through the webpack configuration in serverless.yml.
custom:
webpack:
packager: 'npm' | 'yarn' # Package manager selection
packagerOptions: # Packager-specific options
scripts: string[] # Scripts to run after install
noInstall: boolean # Skip install step
ignoreLockfile: boolean # Ignore lock file during install
ignoreScripts: boolean # Skip pre/post install scripts
production: boolean # Install only production dependencies
frozenLockfile: boolean # Use exact lock file versions (Yarn)
[customOption: string]: any # Additional packager-specific optionsConfiguration Examples:
# NPM configuration with custom options
custom:
webpack:
packager: 'npm'
packagerOptions:
scripts:
- 'rebuild' # Run after install
- 'prepare'
ignoreScripts: false # Allow pre/post install scripts
production: true # Production-only install
# Yarn configuration with Berry support
custom:
webpack:
packager: 'yarn'
packagerOptions:
frozenLockfile: true # Use exact lock file versions
scripts:
- 'postinstall'
production: true
# Yarn workspace configuration
custom:
webpack:
packager: 'yarn'
includeModules:
packagePath: '../package.json' # Workspace root package.json
nodeModulesRelativeDir: '../../' # Shared node_modules location
packagerOptions:
workspaces: true # Enable workspace supportBoth npm and yarn packagers support monorepo and workspace configurations:
// Automatic workspace detection
const packagers = require('serverless-webpack/lib/packagers');
const yarn = packagers.get('yarn');
// Yarn automatically handles workspace dependencies
const deps = await yarn.getProdDependencies('/workspace/package');
// Lock file rebasing for different directory structures
const lockfileContent = require('/workspace/yarn.lock');
yarn.rebaseLockfile('../', lockfileContent);Pass custom options to package managers:
const npm = packagers.get('npm');
// Install with custom NPM options
await npm.install('/path/to/project', {
'ignore-scripts': true,
'only': 'production',
'no-audit': true,
'no-fund': true
});Packager operations may throw errors for various failure conditions:
const { SpawnError } = require('serverless-webpack/lib/utils');
try {
await npm.install('/path/to/project');
} catch (error) {
if (error instanceof SpawnError) {
console.error('Install failed:', error.stderr);
console.log('Partial output:', error.stdout);
}
}The packager system integrates with the module packaging configuration:
custom:
webpack:
includeModules: true # Enable external module packaging
packager: 'yarn' # Use yarn for dependency management
packagerOptions:
frozenLockfile: true # Yarn-specific option
scripts: # Run after dependency install
- 'prepare:production'The packager handles:
The plugin automatically detects the appropriate package manager based on:
packager configurationpackage-lock.json vs yarn.lock)package.json// Manual packager selection based on environment
const packagers = require('serverless-webpack/lib/packagers');
const hasYarnLock = fs.existsSync('./yarn.lock');
const hasNpmLock = fs.existsSync('./package-lock.json');
const packager = hasYarnLock ? packagers.get('yarn') : packagers.get('npm');Install with Tessl CLI
npx tessl i tessl/npm-serverless-webpack