Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/privatenumber/link
🔗 A better `npm link`
https://github.com/privatenumber/link
Last synced: 4 days ago
JSON representation
🔗 A better `npm link`
- Host: GitHub
- URL: https://github.com/privatenumber/link
- Owner: privatenumber
- Created: 2022-04-15T20:02:18.000Z (over 2 years ago)
- Default Branch: develop
- Last Pushed: 2024-08-08T02:34:13.000Z (3 months ago)
- Last Synced: 2024-10-19T01:11:33.590Z (16 days ago)
- Language: TypeScript
- Homepage:
- Size: 5.19 MB
- Stars: 197
- Watchers: 5
- Forks: 8
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
npx link
A safer and enhanced version of [`npm link`](https://docs.npmjs.com/cli/v8/commands/npm-link).
Why is `npm link` unsafe? Read the [blog post](https://hirok.io/posts/avoid-npm-link).
### Features
- 🔗 Link dependencies without removing previous links
- 🛡 Only resolves to local paths
- 🔥 Config file quickly linking multiple packages
- 💫 Deep linking for quickling linking multilple packages
Already a sponsor? Join the discussion in the Development repo!
## 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
### Linking a package
From the _Consuming package_ directory, link the _Dependency package_:
```sh
npx link
```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.
Here's an example
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.
_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
```This sets up the same `node_modules` tree used in a production environment.
2. Link the _Dependency package_
```sh
npx link publish
```This creates hard links in `node_modules/dependency` to the specific publish assets of the _Dependency package_.
Why hard links instead of symbolic links?
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_.
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 ` to create new hard links.
### Configuration fileCreate 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_.
Example _link.config.json_:
```json5
{
"packages": [
"/path/to/dependency-path-a",
"../dependency-path-b"
]
}
```The configuration has the following type schema:
```ts
type LinkConfig = {// Whether to run `npx link` on dependency packages with link.config.json
deepLink?: boolean// List of dependency packages to link
packages?: string[]
}
```> **Note:** It's not recommended to commit this file to source control since this is for local development with local paths.
To link the dependencies defined in `link.config.json`, run:
```sh
npx link
```### Deep linking
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 dependency that has a `link.config.json` file.
Enable with the `--deep` flag or `deepLink` property in `link.config.json`.
```sh
npx link --deep
```## FAQ
### 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 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`?
You must use npx v7 or higher. Check the version with `npx -v`.
In the obsolete npx v6, local binaries take precedence over npm modules so `npx link` can point to the native `link`/`ln` command:
```
$ npx link
usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]
ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir
link source_file target_file
```To work around this, install `link` globally first:
```sh
$ npm i -g link
$ npx link
```## Related
- [`npx ci`](https://github.com/privatenumber/ci) - A better `npm ci`.
## Sponsors