0
# Packager System
1
2
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.
3
4
## Capabilities
5
6
### Packager Factory
7
8
Factory function for obtaining packager instances.
9
10
```javascript { .api }
11
/**
12
* Get a packager instance by identifier
13
* @param packagerId - Package manager type ('npm' or 'yarn')
14
* @returns Packager instance with static methods
15
*/
16
function get(packagerId: 'npm' | 'yarn'): Packager;
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
const packagers = require('serverless-webpack/lib/packagers');
23
24
// Get npm packager
25
const npm = packagers.get('npm');
26
console.log('NPM lock file:', npm.lockfileName); // 'package-lock.json'
27
28
// Get yarn packager
29
const yarn = packagers.get('yarn');
30
console.log('Yarn lock file:', yarn.lockfileName); // 'yarn.lock'
31
```
32
33
### Packager Interface
34
35
Common interface implemented by all package managers.
36
37
```javascript { .api }
38
interface Packager {
39
/** Name of the lock file used by this packager */
40
static lockfileName: string;
41
42
/** Whether this packager requires copying node_modules */
43
static mustCopyModules: boolean;
44
45
/**
46
* Get sections of package.json to copy during packaging
47
* @param packagerOptions - Configuration options for the packager
48
* @returns Array of package.json section names to copy
49
*/
50
static copyPackageSectionNames(packagerOptions: object): string[];
51
52
/**
53
* Get version information for the package manager
54
* @param cwd - Working directory path
55
* @returns Promise resolving to version object
56
*/
57
static getPackagerVersion(cwd: string): Promise<{version: string}>;
58
59
/**
60
* Get production dependencies from package files
61
* @param cwd - Working directory path
62
* @param depth - Dependency tree depth (optional)
63
* @returns Promise resolving to dependency tree object
64
*/
65
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
66
67
/**
68
* Rebase lock file paths for different directory structure
69
* @param pathToPackageRoot - Path to package root directory
70
* @param lockfile - Lock file object to modify
71
*/
72
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
73
74
/**
75
* Install dependencies using the package manager
76
* @param cwd - Working directory path
77
* @param packagerOptions - Package manager specific options
78
* @returns Promise that resolves when installation completes
79
*/
80
static install(cwd: string, packagerOptions?: object): Promise<void>;
81
82
/**
83
* Remove development dependencies (production-only install)
84
* @param cwd - Working directory path
85
* @param packagerOptions - Package manager specific options
86
* @returns Promise that resolves when pruning completes
87
*/
88
static prune(cwd: string, packagerOptions?: object): Promise<void>;
89
90
/**
91
* Run package.json scripts
92
* @param cwd - Working directory path
93
* @param scriptNames - Array of script names to execute
94
* @returns Promise that resolves when scripts complete
95
*/
96
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
97
}
98
```
99
100
## NPM Packager
101
102
NPM package manager implementation with support for all NPM versions and package-lock.json handling.
103
104
```javascript { .api }
105
class NPM implements Packager {
106
static lockfileName: 'package-lock.json';
107
static mustCopyModules: false;
108
109
static copyPackageSectionNames(packagerOptions: object): string[];
110
static getPackagerVersion(cwd: string): Promise<{version: string}>;
111
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
112
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
113
static install(cwd: string, packagerOptions?: object): Promise<void>;
114
static prune(cwd: string, packagerOptions?: object): Promise<void>;
115
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
116
}
117
```
118
119
**Usage Examples:**
120
121
```javascript
122
const packagers = require('serverless-webpack/lib/packagers');
123
const npm = packagers.get('npm');
124
125
// Get NPM version
126
const version = await npm.getPackagerVersion('/path/to/project');
127
console.log('NPM version:', version.version);
128
129
// Install dependencies
130
await npm.install('/path/to/project', {
131
ignoreScripts: true,
132
production: true
133
});
134
135
// Get production dependencies
136
const deps = await npm.getProdDependencies('/path/to/project');
137
console.log('Dependencies:', Object.keys(deps.dependencies));
138
139
// Run custom scripts
140
await npm.runScripts('/path/to/project', ['postinstall', 'prepare']);
141
```
142
143
## Yarn Packager
144
145
Yarn package manager implementation with support for both Yarn Classic (v1) and Yarn Berry (v2+), workspaces, and yarn.lock handling.
146
147
```javascript { .api }
148
class Yarn implements Packager {
149
static lockfileName: 'yarn.lock';
150
static mustCopyModules: true;
151
152
static copyPackageSectionNames(packagerOptions: object): string[];
153
static getPackagerVersion(cwd: string): Promise<{version: string}>;
154
static getProdDependencies(cwd: string, depth?: number): Promise<object>;
155
static rebaseLockfile(pathToPackageRoot: string, lockfile: object): void;
156
static install(cwd: string, packagerOptions?: object): Promise<void>;
157
static prune(cwd: string, packagerOptions?: object): Promise<void>;
158
static runScripts(cwd: string, scriptNames: string[]): Promise<void>;
159
160
/**
161
* Check if this is Yarn Berry (v2+) vs Yarn Classic (v1)
162
* @param version - Yarn version string
163
* @returns True if Yarn Berry, false if Yarn Classic
164
*/
165
static isBerryVersion(version: string): boolean;
166
}
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
const packagers = require('serverless-webpack/lib/packagers');
173
const yarn = packagers.get('yarn');
174
175
// Check Yarn version type
176
const version = await yarn.getPackagerVersion('/path/to/project');
177
const isBerry = yarn.isBerryVersion(version.version);
178
console.log('Using Yarn Berry:', isBerry);
179
180
// Install with yarn-specific options
181
await yarn.install('/path/to/project', {
182
ignoreScripts: false,
183
production: true,
184
frozenLockfile: true
185
});
186
187
// Yarn requires copying node_modules
188
console.log('Must copy modules:', yarn.mustCopyModules); // true
189
190
// Get production dependencies (handles workspaces)
191
const deps = await yarn.getProdDependencies('/path/to/project');
192
```
193
194
## Packager Configuration
195
196
Package managers can be configured through the webpack configuration in serverless.yml.
197
198
```yaml { .api }
199
custom:
200
webpack:
201
packager: 'npm' | 'yarn' # Package manager selection
202
packagerOptions: # Packager-specific options
203
scripts: string[] # Scripts to run after install
204
noInstall: boolean # Skip install step
205
ignoreLockfile: boolean # Ignore lock file during install
206
ignoreScripts: boolean # Skip pre/post install scripts
207
production: boolean # Install only production dependencies
208
frozenLockfile: boolean # Use exact lock file versions (Yarn)
209
[customOption: string]: any # Additional packager-specific options
210
```
211
212
**Configuration Examples:**
213
214
```yaml
215
# NPM configuration with custom options
216
custom:
217
webpack:
218
packager: 'npm'
219
packagerOptions:
220
scripts:
221
- 'rebuild' # Run after install
222
- 'prepare'
223
ignoreScripts: false # Allow pre/post install scripts
224
production: true # Production-only install
225
226
# Yarn configuration with Berry support
227
custom:
228
webpack:
229
packager: 'yarn'
230
packagerOptions:
231
frozenLockfile: true # Use exact lock file versions
232
scripts:
233
- 'postinstall'
234
production: true
235
236
# Yarn workspace configuration
237
custom:
238
webpack:
239
packager: 'yarn'
240
includeModules:
241
packagePath: '../package.json' # Workspace root package.json
242
nodeModulesRelativeDir: '../../' # Shared node_modules location
243
packagerOptions:
244
workspaces: true # Enable workspace support
245
```
246
247
## Advanced Usage Patterns
248
249
### Monorepo and Workspace Support
250
251
Both npm and yarn packagers support monorepo and workspace configurations:
252
253
```javascript
254
// Automatic workspace detection
255
const packagers = require('serverless-webpack/lib/packagers');
256
const yarn = packagers.get('yarn');
257
258
// Yarn automatically handles workspace dependencies
259
const deps = await yarn.getProdDependencies('/workspace/package');
260
261
// Lock file rebasing for different directory structures
262
const lockfileContent = require('/workspace/yarn.lock');
263
yarn.rebaseLockfile('../', lockfileContent);
264
```
265
266
### Custom Packager Options
267
268
Pass custom options to package managers:
269
270
```javascript
271
const npm = packagers.get('npm');
272
273
// Install with custom NPM options
274
await npm.install('/path/to/project', {
275
'ignore-scripts': true,
276
'only': 'production',
277
'no-audit': true,
278
'no-fund': true
279
});
280
```
281
282
### Error Handling
283
284
Packager operations may throw errors for various failure conditions:
285
286
```javascript
287
const { SpawnError } = require('serverless-webpack/lib/utils');
288
289
try {
290
await npm.install('/path/to/project');
291
} catch (error) {
292
if (error instanceof SpawnError) {
293
console.error('Install failed:', error.stderr);
294
console.log('Partial output:', error.stdout);
295
}
296
}
297
```
298
299
## Integration with Module Packaging
300
301
The packager system integrates with the module packaging configuration:
302
303
```yaml
304
custom:
305
webpack:
306
includeModules: true # Enable external module packaging
307
packager: 'yarn' # Use yarn for dependency management
308
packagerOptions:
309
frozenLockfile: true # Yarn-specific option
310
scripts: # Run after dependency install
311
- 'prepare:production'
312
```
313
314
The packager handles:
315
- Installing external dependencies detected by webpack
316
- Running custom scripts for build preparation
317
- Managing lock files for consistent installs
318
- Workspace and monorepo dependency resolution
319
- Production-only dependency filtering
320
321
## Package Manager Detection
322
323
The plugin automatically detects the appropriate package manager based on:
324
1. Explicit `packager` configuration
325
2. Presence of lock files (`package-lock.json` vs `yarn.lock`)
326
3. Workspace configuration in `package.json`
327
328
```javascript
329
// Manual packager selection based on environment
330
const packagers = require('serverless-webpack/lib/packagers');
331
332
const hasYarnLock = fs.existsSync('./yarn.lock');
333
const hasNpmLock = fs.existsSync('./package-lock.json');
334
335
const packager = hasYarnLock ? packagers.get('yarn') : packagers.get('npm');
336
```