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

packagers.mddocs/

Packager System

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.

Capabilities

Packager Factory

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'

Packager Interface

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 Packager

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 Packager

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

Packager Configuration

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 options

Configuration 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 support

Advanced Usage Patterns

Monorepo and Workspace Support

Both 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);

Custom Packager Options

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

Error Handling

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

Integration with Module Packaging

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:

  • Installing external dependencies detected by webpack
  • Running custom scripts for build preparation
  • Managing lock files for consistent installs
  • Workspace and monorepo dependency resolution
  • Production-only dependency filtering

Package Manager Detection

The plugin automatically detects the appropriate package manager based on:

  1. Explicit packager configuration
  2. Presence of lock files (package-lock.json vs yarn.lock)
  3. Workspace configuration in 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

docs

build-compilation.md

configuration.md

development-integration.md

index.md

module-packaging.md

packagers.md

utilities.md

webpack-integration.md

tile.json