CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-serverless-webpack

Serverless Framework plugin that bundles Lambda functions with Webpack for optimized JavaScript deployment packages

Pending
Overview
Eval results
Files

module-packaging.mddocs/

Module Packaging

External module detection, dependency resolution, and packaging system supporting npm and yarn with workspace and monorepo support.

Capabilities

Module Inclusion Configuration

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 packaging

Usage 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'

External Module Detection

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']
    })
  ]
};

Packager Integration

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 options

Usage 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: true

NPM Packager Implementation

NPM-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 Packager Implementation

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;
}

Workspace and Monorepo Support

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 location

Usage 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.yml

Dependency Resolution Process

Multi-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;
  };
}

Force Include and Exclude Rules

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 include

Usage 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 rebuild

Common exclusion patterns:

  • aws-sdk: Available in AWS Lambda runtime environment
  • serverless-webpack: Build tool, not needed at runtime
  • @types/: TypeScript definitions, compiled away
  • webpack: Build tool dependencies

Common inclusion patterns:

  • peer-dependencies: When not automatically installed
  • optional-dependencies: Runtime-optional but required modules
  • native-modules: Binary modules needing platform-specific builds

Package.json Generation

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:

  • Production dependencies actually used by the code
  • Resolved versions from original package.json/lock files
  • Optional post-install scripts if configured

Native Module Handling

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 modules

Performance Optimization

Optimization 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 patterns

Packaging Validation

Validation 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:

  • All detected external modules are properly packaged
  • No missing dependencies that would cause runtime errors
  • Native modules are compiled for the correct platform
  • Package size warnings for large deployments

Troubleshooting Common Issues

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

docs

build-compilation.md

configuration.md

development-integration.md

index.md

module-packaging.md

packagers.md

utilities.md

webpack-integration.md

tile.json