0
# @lerna/link
1
2
@lerna/link is a Lerna command package that creates symbolic links between packages that depend on each other within a Lerna monorepo. It enables local development workflows where changes in one package are immediately reflected in dependent packages without requiring package republishing or manual linking.
3
4
## Package Information
5
6
- **Package Name**: @lerna/link
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @lerna/link` or available via `lerna` CLI
10
- **Engine Requirements**: Node.js ^14.17.0 || >=16.0.0
11
12
## Core Imports
13
14
```javascript
15
// CommonJS style (Node.js require)
16
const linkCommand = require("@lerna/link");
17
const { LinkCommand } = require("@lerna/link");
18
const command = require("@lerna/link/command");
19
```
20
21
```typescript
22
// TypeScript style (using CommonJS imports)
23
import linkCommand = require("@lerna/link");
24
import { LinkCommand } = require("@lerna/link");
25
import command = require("@lerna/link/command");
26
```
27
28
## Basic Usage
29
30
### Command Line Interface
31
32
```bash
33
# Link all interdependent packages
34
lerna link
35
36
# Force linking regardless of version ranges
37
lerna link --force-local
38
39
# Use specific subdirectory as symlink source
40
lerna link --contents dist
41
42
# Convert existing links to file: specifiers
43
lerna link convert
44
```
45
46
### Programmatic Usage
47
48
```typescript
49
const linkCommand = require("@lerna/link");
50
51
// Create command instance
52
const command = linkCommand(process.argv);
53
54
// Initialize and execute
55
await command.initialize();
56
await command.execute();
57
```
58
59
## Architecture
60
61
@lerna/link is built around several key components:
62
63
- **Factory Pattern**: The main export is a factory function that creates `LinkCommand` instances, allowing for dependency injection and testing flexibility
64
- **Command Class Structure**: Extends Lerna's base `Command` class, integrating with the Lerna command system and lifecycle management
65
- **Package Graph Analysis**: Uses `PackageGraph` to analyze dependencies between packages and determine which packages need linking
66
- **Symbolic Link Management**: Creates and manages symbolic links in `node_modules` directories and `.bin` directories for executables
67
- **Package Manager Integration**: Validates npm client compatibility and throws errors for unsupported package managers like pnpm
68
- **File Specification Conversion**: Provides capability to convert symbolic links to relative `file:` specifications in package.json files
69
70
The command operates in two main modes: standard linking (creating symbolic links) and conversion mode (updating package.json files with file: specifications).
71
72
## Capabilities
73
74
### Factory Function
75
76
Creates a new LinkCommand instance with provided command-line arguments.
77
78
```typescript { .api }
79
function factory(argv: NodeJS.Process["argv"]): LinkCommand;
80
```
81
82
### LinkCommand Class
83
84
Main command class that handles package linking operations. Extends Lerna's base Command class.
85
86
```typescript { .api }
87
class LinkCommand extends Command<LinkCommandOptions> {
88
allPackages: Package[];
89
targetGraph?: PackageGraph;
90
91
get requiresGit(): boolean;
92
initialize(): void;
93
execute(): Promise<any>;
94
convertLinksToFileSpecs(): Promise<any>;
95
}
96
```
97
98
#### Properties
99
100
- `allPackages`: Array of all packages in the monorepo
101
- `targetGraph`: Graph of package dependencies for linking operations
102
103
#### Methods
104
105
- `requiresGit`: Returns false, indicating git is not required for this command
106
- `initialize()`: Sets up the command, validates npm client, and builds package graph
107
- `execute()`: Performs the linking operation or converts links to file specifications
108
- `convertLinksToFileSpecs()`: Converts symbolic links to relative file: specifications in package.json files
109
110
### Command Module
111
112
Yargs command module configuration for CLI integration. Provides the CLI interface and option definitions.
113
114
```typescript { .api }
115
interface CommandModule {
116
command: string;
117
describe: string;
118
builder: (yargs: any) => any;
119
handler: (argv: any) => any;
120
}
121
```
122
123
The command module exports:
124
- **command**: "link"
125
- **describe**: "Symlink together all packages that are dependencies of each other"
126
- **builder**: Configures command options including `--force-local`, `--contents`, and the `convert` subcommand
127
- **handler**: Delegates to the factory function to create and execute the LinkCommand instance
128
129
The builder function also registers the `convert` subcommand with the description "Replace local sibling version ranges with relative file: specifiers".
130
131
### Command Options
132
133
Options interface extending Lerna's base CommandConfigOptions.
134
135
```typescript { .api }
136
interface LinkCommandOptions extends CommandConfigOptions {
137
contents: string;
138
forceLocal: boolean;
139
}
140
```
141
142
#### Option Properties
143
144
- `contents`: Subdirectory to use as the source of the symlink (default: current directory)
145
- `forceLocal`: Force local sibling links regardless of version range match
146
147
### Command Line Options
148
149
#### --force-local
150
151
Forces creation of symbolic links for local dependencies regardless of whether their version ranges match.
152
153
```bash
154
lerna link --force-local
155
```
156
157
#### --contents
158
159
Specifies a subdirectory to use as the source of the symlink, applying to all packages.
160
161
```bash
162
lerna link --contents dist
163
```
164
165
#### convert subcommand
166
167
Replaces local sibling version ranges with relative file: specifiers in package.json files.
168
169
```bash
170
lerna link convert
171
```
172
173
## Types
174
175
176
### LinkCommandOptions
177
178
```typescript { .api }
179
interface LinkCommandOptions extends CommandConfigOptions {
180
contents: string;
181
forceLocal: boolean;
182
}
183
```
184
185
### Dependencies
186
187
The package relies on several core Lerna types and utilities:
188
189
```typescript { .api }
190
// From @lerna/core
191
class Command<T extends CommandConfigOptions>;
192
interface CommandConfigOptions;
193
class Package;
194
class PackageGraph;
195
class PackageGraphNode;
196
function symlinkDependencies(
197
packages: Package[],
198
packageGraph: PackageGraph | undefined,
199
tracker: any
200
): Promise<any>;
201
class ValidationError;
202
```
203
204
## Error Handling
205
206
### PNPM Workspace Validation
207
208
The command throws a ValidationError when attempting to use with pnpm workspaces:
209
210
```typescript { .api }
211
class ValidationError extends Error {
212
constructor(code: string, message: string);
213
}
214
```
215
216
Specific error thrown:
217
- **Code**: "EWORKSPACES"
218
- **Message**: "Link is not supported with pnpm workspaces, since pnpm will automatically link dependencies during `pnpm install`. See the pnpm docs for details: https://pnpm.io/workspaces"
219
220
This error is thrown during the `initialize()` method when `this.options.npmClient === "pnpm"`.
221
222
## Behavior
223
224
### Package Discovery
225
226
The command analyzes all packages in the Lerna monorepo and identifies dependencies between them. It creates symbolic links only for packages that are listed as dependencies of other packages in the same monorepo.
227
228
### Symlink Creation
229
230
- Links package directories to `node_modules` folders of dependent packages
231
- Links executable files to `.bin` directories for CLI commands
232
- Supports custom source directories via `publishConfig.directory` in package.json
233
- Respects version range matching unless `--force-local` is used
234
235
### Version Range Handling
236
237
By default, symbolic links are only created when the dependency version range matches the local package version. The `--force-local` flag bypasses this check and creates links regardless of version compatibility.
238
239
### File Specification Conversion
240
241
The `convert` subcommand transforms the monorepo to use `file:` dependencies instead of symbolic links, making packages reference each other through relative file paths in their package.json files.
242
243
## Integration
244
245
### Lerna Command System
246
247
@lerna/link integrates with Lerna's command system and can be invoked through:
248
- Direct package usage: `require("@lerna/link")`
249
- Lerna CLI: `lerna link`
250
- Programmatic Lerna API
251
252
### Package Manager Compatibility
253
254
- **Supported**: npm, yarn
255
- **Not Supported**: pnpm (throws validation error due to pnpm's automatic workspace linking)
256
257
### Build Integration
258
259
Works with packages that use `publishConfig.directory` to specify build output directories, linking the built artifacts instead of source code.