0
# Package Management
1
2
JavaScript package manager abstraction layer supporting npm, yarn, and pnpm. Provides unified interface for dependency management operations across different package managers.
3
4
## Capabilities
5
6
### JsPackageManager Abstract Class
7
8
Base class providing common interface for all JavaScript package managers.
9
10
```typescript { .api }
11
/**
12
* Abstract base class for JavaScript package managers
13
*/
14
abstract class JsPackageManager {
15
/** Package manager type identifier */
16
abstract type: 'npm' | 'yarn1' | 'yarn2' | 'pnpm';
17
18
/**
19
* Get command-line arguments for package installation
20
* @returns Array of install command arguments
21
*/
22
abstract getInstallArgs(): string[];
23
24
/**
25
* Get the run command for executing package scripts
26
* @returns Run command string (e.g., 'npm run', 'yarn')
27
*/
28
abstract getRunCommand(): string;
29
30
/**
31
* Get command-line arguments for running scripts
32
* @returns Array of run command arguments
33
*/
34
abstract getRunArgs(): string[];
35
36
/**
37
* Get command-line arguments for adding packages
38
* @param installAsDevDependencies - Whether to install as dev dependencies
39
* @returns Array of add command arguments
40
*/
41
abstract getAddArgs(installAsDevDependencies: boolean): string[];
42
43
/**
44
* Add packages to project dependencies
45
* @param packages - Array of package names/versions to add
46
* @param installAsDevDependencies - Whether to install as dev dependencies
47
* @returns Promise resolving when packages are added
48
*/
49
abstract addDependencies(
50
packages: string[],
51
installAsDevDependencies?: boolean
52
): Promise<void>;
53
54
/**
55
* Remove packages from project dependencies
56
* @param packages - Array of package names to remove
57
* @returns Promise resolving when packages are removed
58
*/
59
abstract removeDependencies(packages: string[]): Promise<void>;
60
61
/**
62
* Install all project dependencies
63
* @returns Promise resolving when installation is complete
64
*/
65
abstract installDependencies(): Promise<void>;
66
67
/**
68
* Run package script
69
* @param script - Script name to run
70
* @param args - Additional arguments for the script
71
* @returns Promise resolving when script completes
72
*/
73
abstract runScript(script: string, args?: string[]): Promise<void>;
74
75
/**
76
* Get package information
77
* @param packageName - Name of package to get info for
78
* @returns Promise resolving to package information
79
*/
80
abstract getPackageInfo(packageName: string): Promise<any>;
81
82
/**
83
* Check if package is installed
84
* @param packageName - Name of package to check
85
* @returns Promise resolving to true if package is installed
86
*/
87
abstract isPackageInstalled(packageName: string): Promise<boolean>;
88
89
/**
90
* Get installed package version
91
* @param packageName - Name of package
92
* @returns Promise resolving to version string or undefined
93
*/
94
abstract getInstalledVersion(packageName: string): Promise<string | undefined>;
95
}
96
```
97
98
### JsPackageManagerFactory
99
100
Factory class for creating appropriate package manager instances based on project configuration.
101
102
```typescript { .api }
103
/**
104
* Factory for creating JavaScript package manager instances
105
*/
106
class JsPackageManagerFactory {
107
/**
108
* Create package manager instance based on project configuration
109
* @param options - Factory options
110
* @returns Appropriate package manager instance
111
*/
112
static getPackageManager(options?: {
113
/** Force specific package manager type */
114
force?: 'npm' | 'yarn1' | 'yarn2' | 'pnpm';
115
/** Working directory for package manager detection */
116
cwd?: string;
117
}): JsPackageManager;
118
119
/**
120
* Detect package manager type from project files
121
* @param cwd - Working directory to check
122
* @returns Detected package manager type
123
*/
124
static detectPackageManager(cwd?: string): 'npm' | 'yarn1' | 'yarn2' | 'pnpm';
125
}
126
```
127
128
**Usage Examples:**
129
130
```typescript
131
import { JsPackageManagerFactory } from "@storybook/core-common";
132
133
// Auto-detect package manager
134
const packageManager = JsPackageManagerFactory.getPackageManager();
135
console.log(`Using ${packageManager.type} package manager`);
136
137
// Force specific package manager
138
const yarnManager = JsPackageManagerFactory.getPackageManager({
139
force: 'yarn1'
140
});
141
142
// Install dependencies
143
await packageManager.installDependencies();
144
145
// Add Storybook addons
146
await packageManager.addDependencies([
147
'@storybook/addon-docs',
148
'@storybook/addon-controls'
149
], true); // Install as dev dependencies
150
151
// Run Storybook
152
await packageManager.runScript('storybook', ['--port', '6006']);
153
```
154
155
### Package Information Utilities
156
157
Parse and extract package information from strings and configurations.
158
159
```typescript { .api }
160
/**
161
* Parse package name and version from package string
162
* @param pkg - Package string (e.g., 'react@18.2.0', '@storybook/react')
163
* @returns Object with parsed package details
164
*/
165
function getPackageDetails(pkg: string): {
166
name: string;
167
version?: string;
168
scope?: string;
169
};
170
```
171
172
**Usage Example:**
173
174
```typescript
175
import { getPackageDetails } from "@storybook/core-common";
176
177
// Parse scoped package with version
178
const details1 = getPackageDetails('@storybook/react@8.6.14');
179
console.log(details1);
180
// {
181
// name: '@storybook/react',
182
// version: '8.6.14',
183
// scope: '@storybook'
184
// }
185
186
// Parse simple package name
187
const details2 = getPackageDetails('lodash');
188
console.log(details2);
189
// {
190
// name: 'lodash',
191
// scope: undefined
192
// }
193
```
194
195
### PackageJson Types and Utilities
196
197
TypeScript types and utilities for working with package.json files.
198
199
```typescript { .api }
200
/**
201
* Extended package.json interface with common properties
202
*/
203
interface PackageJson {
204
name?: string;
205
version?: string;
206
description?: string;
207
main?: string;
208
module?: string;
209
types?: string;
210
dependencies?: Record<string, string>;
211
devDependencies?: Record<string, string>;
212
peerDependencies?: Record<string, string>;
213
scripts?: Record<string, string>;
214
[key: string]: any;
215
}
216
```
217
218
## Advanced Usage Patterns
219
220
### Multi-Package Manager Support
221
222
```typescript
223
import { JsPackageManagerFactory } from "@storybook/core-common";
224
225
async function setupStorybookWithPackageManager() {
226
// Detect package manager
227
const packageManager = JsPackageManagerFactory.getPackageManager();
228
229
console.log(`Detected ${packageManager.type} package manager`);
230
231
// Install Storybook dependencies based on package manager
232
const storybookPackages = [
233
'storybook',
234
'@storybook/react',
235
'@storybook/addon-essentials'
236
];
237
238
try {
239
await packageManager.addDependencies(storybookPackages, true);
240
console.log('Storybook packages installed successfully');
241
242
// Run initial Storybook setup
243
await packageManager.runScript('storybook', ['init']);
244
245
} catch (error) {
246
console.error(`Failed to install with ${packageManager.type}:`, error);
247
248
// Fallback to npm if other package manager fails
249
if (packageManager.type !== 'npm') {
250
const npmManager = JsPackageManagerFactory.getPackageManager({
251
force: 'npm'
252
});
253
await npmManager.addDependencies(storybookPackages, true);
254
}
255
}
256
}
257
```
258
259
### Dependency Validation
260
261
```typescript
262
import { JsPackageManagerFactory, getPackageDetails } from "@storybook/core-common";
263
264
async function validateStorybookDependencies(requiredPackages: string[]) {
265
const packageManager = JsPackageManagerFactory.getPackageManager();
266
const results = [];
267
268
for (const pkg of requiredPackages) {
269
const details = getPackageDetails(pkg);
270
const isInstalled = await packageManager.isPackageInstalled(details.name);
271
272
if (isInstalled) {
273
const installedVersion = await packageManager.getInstalledVersion(details.name);
274
results.push({
275
name: details.name,
276
required: details.version,
277
installed: installedVersion,
278
valid: !details.version || installedVersion === details.version
279
});
280
} else {
281
results.push({
282
name: details.name,
283
required: details.version,
284
installed: null,
285
valid: false
286
});
287
}
288
}
289
290
return results;
291
}
292
293
// Usage
294
const validation = await validateStorybookDependencies([
295
'@storybook/react@8.6.14',
296
'@storybook/addon-essentials',
297
'react@^18.0.0'
298
]);
299
300
console.log(validation);
301
```
302
303
### Custom Package Manager Operations
304
305
```typescript
306
import { JsPackageManagerFactory } from "@storybook/core-common";
307
308
class StorybookPackageManager {
309
private packageManager: any;
310
311
constructor(force?: 'npm' | 'yarn1' | 'yarn2' | 'pnpm') {
312
this.packageManager = JsPackageManagerFactory.getPackageManager({ force });
313
}
314
315
async installStorybookAddons(addons: string[]) {
316
// Validate addon names
317
const validAddons = addons.filter(addon =>
318
addon.startsWith('@storybook/') || addon.includes('storybook')
319
);
320
321
if (validAddons.length !== addons.length) {
322
console.warn('Some addons may not be Storybook-compatible');
323
}
324
325
// Install as dev dependencies
326
await this.packageManager.addDependencies(validAddons, true);
327
328
// Update package.json scripts if needed
329
await this.updateStorybookScripts();
330
}
331
332
async removeStorybookAddons(addons: string[]) {
333
// Remove from dependencies
334
await this.packageManager.removeDependencies(addons);
335
336
// Clean up any related configuration
337
await this.cleanupAddonConfig(addons);
338
}
339
340
async updateStorybookVersion(version: string) {
341
// Get all Storybook packages
342
const packageInfo = await this.packageManager.getPackageInfo('storybook');
343
const storybookPackages = Object.keys(packageInfo.dependencies || {})
344
.filter(pkg => pkg.startsWith('@storybook/'));
345
346
// Add version to all packages
347
const packagesWithVersion = storybookPackages.map(pkg => `${pkg}@${version}`);
348
349
// Update all Storybook packages
350
await this.packageManager.addDependencies(packagesWithVersion, true);
351
}
352
353
private async updateStorybookScripts() {
354
// Implementation for updating package.json scripts
355
}
356
357
private async cleanupAddonConfig(addons: string[]) {
358
// Implementation for cleaning up addon configuration
359
}
360
}
361
362
// Usage
363
const sbPackageManager = new StorybookPackageManager();
364
await sbPackageManager.installStorybookAddons([
365
'@storybook/addon-docs',
366
'@storybook/addon-controls',
367
'@storybook/addon-actions'
368
]);
369
```
370
371
## Package Manager Specific Behavior
372
373
### NPM Specific
374
375
```typescript
376
// npm-specific commands generated:
377
// Install: ['install']
378
// Add: ['install', '--save-dev'] or ['install', '--save']
379
// Remove: ['uninstall']
380
// Run: 'npm run'
381
```
382
383
### Yarn 1 Specific
384
385
```typescript
386
// yarn1-specific commands generated:
387
// Install: ['install']
388
// Add: ['add', '--dev'] or ['add']
389
// Remove: ['remove']
390
// Run: 'yarn'
391
```
392
393
### Yarn 2+ Specific
394
395
```typescript
396
// yarn2-specific commands generated:
397
// Install: ['install']
398
// Add: ['add', '--dev'] or ['add']
399
// Remove: ['remove']
400
// Run: 'yarn'
401
```
402
403
### PNPM Specific
404
405
```typescript
406
// pnpm-specific commands generated:
407
// Install: ['install']
408
// Add: ['add', '--save-dev'] or ['add', '--save']
409
// Remove: ['remove']
410
// Run: 'pnpm'
411
```