Serverless Framework plugin that bundles Lambda functions with Webpack for optimized JavaScript deployment packages
—
External module detection, dependency resolution, and packaging system supporting npm and yarn with workspace and monorepo support.
Configure how external modules are detected, included, and packaged in the deployment artifact.
# Boolean format for simple inclusion
includeModules: boolean
# Object format for advanced configuration
includeModules:
packagePath: string # Relative path to package.json (default: './package.json')
nodeModulesRelativeDir: string # Relative path to node_modules directory
packageLockPath: string # Path to package-lock.json for NPM 8+ support
forceExclude: string[] # Modules to force exclude from packaging
forceInclude: string[] # Modules to force include in packagingUsage Examples:
# Simple inclusion - includes all external dependencies
custom:
webpack:
includeModules: true
# Advanced configuration
custom:
webpack:
includeModules:
packagePath: '../package.json' # Monorepo package.json location
nodeModulesRelativeDir: '../../' # Shared node_modules directory
packageLockPath: '../../package-lock.json' # Lock file for NPM 8+
forceExclude:
- 'aws-sdk' # Available in Lambda runtime
- 'optional-dev-dependency'
forceInclude:
- 'peer-dependency' # Include peer dependencies
- 'optional-runtime-dependency'Automatic detection of external modules used by webpack bundles.
/**
* External module detection and analysis
*/
interface ExternalModule {
name: string; // Module name (e.g., 'lodash', '@aws-sdk/client-s3')
version: string; // Version from package.json
dependencies: string[]; // Module's own dependencies
peerDependencies: string[]; // Required peer dependencies
optional: boolean; // Whether module is optional
builtin: boolean; // Whether module is Node.js builtin
}
/**
* Module detection process
*/
function detectExternalModules(compilation: any): ExternalModule[];The plugin automatically scans webpack compilation results to identify external modules that need to be included in the deployment package.
Usage Examples:
// webpack.config.js - Configure externals for detection
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: slsw.lib.entries,
target: 'node',
externals: [
nodeExternals({
// Modules to exclude from bundling but include in package
allowlist: ['some-module-to-bundle']
})
]
};Support for multiple package managers with specific configuration options.
# Package manager selection
packager: 'npm' | 'yarn'
# Packager-specific options
packagerOptions:
scripts: string[] # Additional scripts to run after install
noInstall: boolean # Skip install step (default: false)
ignoreLockfile: boolean # Ignore lock file during install
production: boolean # Install only production dependencies (default: true)
[customOption: string]: any # Additional packager-specific optionsUsage Examples:
# NPM configuration
custom:
webpack:
packager: 'npm'
packagerOptions:
scripts:
- 'rebuild' # Rebuild native modules
- 'prepare:lambda' # Custom preparation script
production: true
# Yarn configuration
custom:
webpack:
packager: 'yarn'
packagerOptions:
ignoreLockfile: false
scripts:
- 'postinstall'
production: trueNPM-specific packaging functionality with support for package-lock.json and npm workspaces.
/**
* NPM packager interface implementation
*/
class NpmPackager {
static lockfileName: 'package-lock.json';
static mustCopyModules: false;
/**
* Get NPM version information
*/
static getPackagerVersion(cwd: string): Promise<{version: string}>;
/**
* Get production dependencies with specified depth
*/
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
/**
* Install dependencies in specified directory
*/
static install(cwd: string, options?: object): Promise<void>;
/**
* Remove development dependencies
*/
static prune(cwd: string, options?: object): Promise<void>;
/**
* Run package scripts
*/
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
/**
* Rebase package-lock.json paths for relocated packages
*/
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
}Yarn-specific packaging functionality with workspace and monorepo support.
/**
* Yarn packager interface implementation
*/
class YarnPackager {
static lockfileName: 'yarn.lock';
static mustCopyModules: true;
/**
* Get Yarn version information
*/
static getPackagerVersion(cwd: string): Promise<{version: string}>;
/**
* Get production dependencies from yarn.lock
*/
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
/**
* Install dependencies using yarn
*/
static install(cwd: string, options?: object): Promise<void>;
/**
* Remove development dependencies
*/
static prune(cwd: string, options?: object): Promise<void>;
/**
* Run yarn scripts
*/
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
/**
* Rebase yarn.lock paths for relocated packages
*/
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
}Configuration for monorepo and workspace environments with shared dependencies.
# Monorepo configuration
custom:
webpack:
includeModules:
packagePath: '../package.json' # Workspace root package.json
nodeModulesRelativeDir: '../../' # Shared node_modules location
packageLockPath: '../../package-lock.json' # Root lock file locationUsage Examples:
# Yarn workspace configuration
custom:
webpack:
packager: 'yarn'
includeModules:
packagePath: '../../package.json' # Workspace root
nodeModulesRelativeDir: '../../' # Shared node_modules
# NPM workspace configuration
custom:
webpack:
packager: 'npm'
includeModules:
packagePath: '../package.json'
nodeModulesRelativeDir: '../'
packageLockPath: '../package-lock.json'For a typical monorepo structure:
workspace-root/
├── package.json
├── node_modules/
├── packages/
│ ├── service-a/
│ │ ├── package.json
│ │ └── serverless.yml
│ └── service-b/
│ ├── package.json
│ └── serverless.ymlMulti-step process for resolving and packaging external dependencies.
/**
* Dependency resolution process steps
*/
const resolutionSteps = [
'detectExternalModules', // Scan webpack output for external references
'analyzeDependencies', // Analyze package.json dependencies
'resolvePeerDependencies', // Include required peer dependencies
'applyForceIncludeExclude', // Apply force include/exclude rules
'generatePackageJson', // Create deployment package.json
'installDependencies', // Install using selected packager
'runPostInstallScripts', // Execute post-install scripts
'pruneDevDependencies', // Remove development dependencies
'copyToDeploymentPackage' // Copy to final deployment artifact
];
/**
* Dependency tree structure
*/
interface DependencyTree {
[moduleName: string]: {
version: string;
dependencies?: DependencyTree;
peerDependencies?: string[];
optional?: boolean;
};
}Fine-grained control over which modules are included or excluded from packaging.
# Force inclusion and exclusion configuration
includeModules:
forceExclude: string[] # Modules to always exclude
forceInclude: string[] # Modules to always includeUsage Examples:
custom:
webpack:
includeModules:
forceExclude:
- 'aws-sdk' # Available in Lambda runtime
- 'serverless-webpack' # Build-time only dependency
- '@types/*' # TypeScript type definitions
- 'devDependency' # Development-only modules
forceInclude:
- 'optional-dependency' # Optional deps not auto-detected
- 'peer-dependency' # Peer deps when not installed
- 'native-module' # Native modules needing rebuildCommon exclusion patterns:
Common inclusion patterns:
Automatic generation of deployment package.json with resolved dependencies.
/**
* Generated package.json structure for deployment
*/
interface DeploymentPackageJson {
name: string; // Service name
version: string; // Service version
description?: string; // Service description
main?: string; // Entry point (usually not needed)
dependencies: { // Production dependencies only
[name: string]: string; // Module name and version
};
scripts?: { // Post-install scripts if configured
[name: string]: string;
};
}The plugin generates a minimal package.json containing only:
Special handling for native modules requiring compilation for the Lambda environment.
/**
* Native module detection and handling
*/
interface NativeModuleConfig {
rebuildCommand: string; // Command to rebuild native modules
targetPlatform: string; // Target platform (e.g., 'linux')
targetArch: string; // Target architecture (e.g., 'x64')
dockerImage?: string; // Docker image for cross-compilation
}Usage Examples:
# Native module rebuilding
custom:
webpack:
packager: 'npm'
packagerOptions:
scripts:
- 'rebuild' # npm rebuild for native modules
# Yarn native module handling
custom:
webpack:
packager: 'yarn'
packagerOptions:
scripts:
- 'install --force' # Force reinstall native modulesOptimization techniques for faster packaging and smaller deployment artifacts.
/**
* Packaging performance optimization options
*/
interface PackagingOptimizations {
concurrency: number; // Parallel packaging operations
skipDuplicates: boolean; // Skip duplicate dependency resolution
cacheEnabled: boolean; // Enable packaging cache
symlinkHandling: 'preserve' | 'resolve' | 'ignore'; // Symlink handling strategy
}Usage Examples:
custom:
webpack:
concurrency: 4 # Limit concurrent operations
includeModules:
forceExclude:
- 'unused-*' # Exclude unused module patternsValidation and verification of packaged dependencies.
/**
* Package validation and verification
*/
interface PackageValidation {
validatePackageIntegrity: boolean; // Verify package contents
checkMissingDependencies: boolean; // Check for missing runtime deps
validateNativeModules: boolean; // Verify native module compatibility
reportPackageSize: boolean; // Report final package size
}The plugin automatically validates:
Common module packaging issues and solutions.
/**
* Common packaging issues and diagnostics
*/
interface PackagingDiagnostics {
missingModules: string[]; // Modules referenced but not found
circularDependencies: string[]; // Circular dependency warnings
oversizedPackages: string[]; // Packages exceeding size limits
nativeModuleIssues: string[]; // Native module compilation issues
}Common Solutions:
# Missing peer dependencies
custom:
webpack:
includeModules:
forceInclude:
- 'missing-peer-dep'
# Circular dependency resolution
custom:
webpack:
includeModules:
forceExclude:
- 'problematic-module'
# Large package optimization
custom:
webpack:
includeModules:
forceExclude:
- 'large-unused-module'
- 'development-only-module'Debug packaging issues:
# Enable debug output
export SLS_DEBUG=*
sls package
# Inspect .webpack directory contents
sls webpack --out debug-build
ls -la debug-build/Install with Tessl CLI
npx tessl i tessl/npm-serverless-webpack