Install
npm install --save-dev @darkobits/clean-link
Then, use the clean-link-dir
script anywhere in your package scripts. See below for an example.
Use
npm link
is a handy utility for developing libraries / frameworks / tooling and ensuring they work with their dependents.
Given a hypothetical library, foo-lib, and a hypothetical dependent, bar-app, a common workflow involves something like the following:
- Run
npm link
from the foo-lib project folder. - Start foo-lib's build script in watch mode.
- Run
npm link foo-lib
from the bar-app project folder. - Make changes to foo-lib's source.
- Verify these changes didn't break anything in bar-app.
- ????
- Profit!!
💰
This nice workflow can get a little wonky under certain circumstances, however. Consider the following case:
- bar-app is compiled with Babel 6.x.
- foo-lib is compiled with Babel 7.x.
-
foo-lib is
npm link
-ed into bar-app.
If you try to run bar-app, you will get the following error:
Error: Requires Babel "^7.x.x", but was loaded with "6.x.x". If you are sure you
have a compatible version of @babel/core, it is likely that something in your
build process is loading the wrong version. Inspect the stack trace of this
error to look for the first entry that doesn't mention "@babel/core" or
"babel-core" to see what is calling Babel.
That's definitely a bad-time, mate. What's going on here? We don't need the files for foo-lib transpiled, they already have been!
This is happening because the copy of Babel in bar-app can see the .babelrc
file in foo-lib because NPM symlinks the entire project folder into bar-app's node_modules
. If we published foo-lib in its current state and npm install
-ed it in bar-app normally, we would not encounter this and similar kinds of errors.
And, because Babel has a bug with ignore
, we can't simply --ignore=node_modules
from bar-app. What we really want is to hide foo-lib's .babelrc
(and everything else that would not be included in a distribution) from bar-app, because developing in an environment that is as close as possible to production ===
That's what clean-link
does. Instead of symlink-ing your entire project, it only symlinks package.json
, node_modules
, and any bin
files your project may specify. Then, it returns the path to this nice, clean workspace which you can then write your build artifacts to. In practice, that might look something like this:
{
"name": "foo-lib",
"version": "1.0.0",
"files": [
"dist"
],
"main": "dist/index.js",
"scripts": {
// Our normal build script writes files to 'dist'.
"build": "babel src --out-dir=dist",
// 'npm run link' will write files to something like '/usr/local/lib/node_modules/foo-lib/dist'
// and update it when we make changes.
"link": "npm run build -- --out-dir=$(npx clean-link-dir)/dist --watch"
}
// etc...
}
Now, when we run npm link foo-lib
from bar-app, we only get the files we need, and everything is copacetic.
Debugging
This package respects the LOG_LEVEL
environment variable, and uses the standard NPM log levels. For more verbose output, try LOG_LEVEL=verbose npm run <script that uses clean-link-dir>
.