Comparing version 2.0.0 to 2.1.0
{ | ||
"name": "link", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "A better npm link", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
124
README.md
# npx link | ||
A safer version of [`npm link`](https://docs.npmjs.com/cli/v8/commands/npm-link). | ||
A safer and enhanced version of [`npm link`](https://docs.npmjs.com/cli/v8/commands/npm-link). | ||
@@ -25,17 +25,103 @@ Why is `npm link` unsafe? Read the [blog post](https://hirok.io/posts/avoid-npm-link). | ||
## Terminology | ||
- **Dependency package** | ||
The package getting linked. This is usually a library. | ||
- **Consuming package** | ||
The project you want to link the _Dependency package_ as a dependency of. This is usually an application. | ||
`consuming-package/node_modules/dependency-package` → `dependency-package` | ||
## Usage | ||
`npx link` simply symlinks the target package as a dependency in the current project. | ||
### Linking a package | ||
Unlike `npm link`, it doesn't install the target package globally or re-install project dependencies. | ||
From the _Consuming package_ directory, link the _Dependency package_: | ||
From the project you want to link a package to: | ||
```sh | ||
npx link <package-path> | ||
npx link <dependency-package-path> | ||
``` | ||
This creates a symbolic link inside the `node_modules` of _Consuming package_, referencing the _Dependency package_. | ||
> **🛡️ Secure linking** | ||
> | ||
> Unlike `npm link`, it doesn't install the _Dependency package_ globally or re-install project dependencies. | ||
### Publish mode | ||
Using symbolic links may not replicate the exact environment you get from a standard `npm install`. This discrepancy primarily arises from symlinked packages retaining their development `node_modules` directory. This can lead to issues, especially when multiple packages depend on the same library. | ||
<details> | ||
<summary>Here's an example</summary> | ||
<br> | ||
In a production environment, `npm install` detects common dependencies and installs only one instance of a shared dependency. However, when there's a symbolic link to the development directory of a dependency, separate copies of those dependencies are resolved from the development `node_modules`. | ||
Let's say there's an _App A_ with a dependency on _Package B_, and they both depend on _Library C_: | ||
- Production environment | ||
`npm install` detects that both _App A_ and _Package B_ depends on _Library C_, and only installs one copy of _Library C_ for them to share. | ||
- Symbolic link environment | ||
_App A_ has its copy of _Library C_, and _Package B_ also has its development copy of _Library C_—possibly with different versions. Consequently, when you run the application, it will load two different versions of _Library C_, leading to unexpected outcomes. | ||
</details> | ||
_Publish mode_ helps replicate the production environment in your development setup. | ||
#### Setup instructions | ||
1. In the _Dependency package_, run `npm pack` to create a tarball: | ||
```sh | ||
cd dependency-package-path | ||
npm pack | ||
``` | ||
This generates a tarball (`.tgz`) file in the current directory. Installing from this simulates the conditions of a published package without actually publishing it. | ||
> **Tip:** You can skip this step if this dependency is already installed from npm and there are no changes to the dependency's `package.json` | ||
2. In the _Consuming package_ | ||
1. Install the Dependency tarball from _Step 1_ | ||
```sh | ||
npm install --no-save <dependency-tarball-path> | ||
``` | ||
This sets up the same `node_modules` tree used in a production environment. | ||
2. Link the _Dependency package_ | ||
```sh | ||
npx link publish <dependency-package-path> | ||
``` | ||
This creates hard links in `node_modules/dependency` to the specific publish assets of the _Dependency package_. | ||
<details> | ||
<summary><em>Why hard links instead of symbolic links?</em></summary> | ||
<br> | ||
Another issue with the symlink approach is that Node.js, and popular bundlers, looks up the `node_module` directory relative to a module's realpath rather than the import path (symlink path). By using hard links, we can prevent this behavior and ensure that the `node_modules` directory is resolved using the production tree we set up in _Step 2_. | ||
</details> | ||
4. Start developing! | ||
Any changes you make to the _Dependency package_ will be reflected in the `node_modules` directory of the _Consuming package_. | ||
> **Note:** If the _Dependency package_ emits new files, you'll need to re-run `npx link publish <dependency-package-path>` to create new hard links. | ||
### Configuration file | ||
Create a `link.config.json` (or `link.config.js`) configuration file at the root of your npm project to automatically setup links to multiple packages. | ||
Create a `link.config.json` (or `link.config.js`) configuration file at the root of the _Consuming package_ to automatically setup links to multiple _Dependency packages_. | ||
@@ -46,4 +132,4 @@ Example _link.config.json_: | ||
"packages": [ | ||
"/path/to/package-path-a", | ||
"../package-path-b" | ||
"/path/to/dependency-path-a", | ||
"../dependency-path-b" | ||
] | ||
@@ -57,6 +143,6 @@ } | ||
// Whether to run link on linked packages with link.config.json | ||
// Whether to run `npx link` on dependency packages with link.config.json | ||
deepLink?: boolean | ||
// List of packages to link | ||
// List of dependency packages to link | ||
packages?: string[] | ||
@@ -66,3 +152,3 @@ } | ||
> Note: It's not recommended to commit this file to source control since this is for local development with local paths. | ||
> **Note:** It's not recommended to commit this file to source control since this is for local development with local paths. | ||
@@ -77,5 +163,5 @@ | ||
By default, `npx link` only links packages in the current project. However, there are cases where the linked packages also needs linking setup. | ||
By default, `npx link` only links packages in the _Consuming package_. However, there are cases where the _Dependency packages_ also needs linking setup. | ||
Deep linking recursively runs link on every linked package that has a `link.config.json` file. | ||
Deep linking recursively runs link on every linked dependency that has a `link.config.json` file. | ||
@@ -102,8 +188,10 @@ Enable with the `--deep` flag or `deepLink` property in `link.config.json`. | ||
### Why should I use this over `npm link`? | ||
Because `npm link` has [footguns that make it dangerous to use](https://hirok.io/posts/avoid-npm-link). | ||
### Why should I use `npx link` over `npm link`? | ||
Because `npm link` [is complicated and dangerous to use](https://hirok.io/posts/avoid-npm-link). And `npx link` offers more features such as _Publish mode_. | ||
### How do I remove the symlinks? | ||
Run `npm install` (or the equivalent in your preferred package manager) and it should remove them. | ||
### How do I remove the links? | ||
Run `npm install` and it should remove them. | ||
`npm install` enforces the integrity of `node_modules` by making sure all packages are correctly installed. Reverting the links is a side effect of this. | ||
### Why does `npx link` point to `ln`? | ||
@@ -110,0 +198,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
87114
383
238
8