Using link in package.json dependencies gives an error
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
As discussed with @arcanis in https://github.com/yarnpkg/rfcs/pull/101#issuecomment-421172456, I've come across an issue where using link: in package.json dependencies doesn't work for me.
I get a error Couldn't find a package.json file in /workspace/packages/project-a/src/one and error Couldn't find a package.json file in /workspace/packages/project-b/src/subdir1/subdir2/two.
If the current behavior is a bug, please provide the steps to reproduce.
workspace
- package.json
- packages
- project-a
- package.json
- src
- one
- file1.js
- subdir1
- subdir2
- two
- file2.js
In workspace/packages/project-a/package.json I've linked them so that I can do require relative to one of a number of given root paths, which greatly simplifies writing require statements and makes refactoring code easier.
"dependencies": {
"one": "link:./src/one",
"two": "link:./src/subdir1/subdir2/two"
}
In workspace/package.json I have
{
"private": true,
"workspaces": [
"packages/*"
]
}
What is the expected behavior?
I'd should be able to do require('one/file1.js') and require('two/file2.js') in the code.
Please mention your node.js, yarn and operating system version.
Node: 10.9.0 yarn: 1.9.4 OS: archlinux
Thanks! π
@arcanis According to npm docs there should be file:./ instead of link:./. E.g.:
"dependencies": {
"one": "file:./src/one",
"two": "file:./src/subdir1/subdir2/two"
}
Could you please check that?
No. NPM decided to change the behavior of file: dependencies some time ago to become symlinks, but we decided against that. Instead, link: dependencies are the recommended way to create symlinks (workspaces are still a better choice if possible).
@arcanis Is there any docs about using "link:" instead of "file:" ? I looked for it in yarnpkg.com without success, I could make a PR for that unless it's already in some place I've missed π
https://github.com/yarnpkg/rfcs/blob/master/implemented/0000-link-dependency-type.md
Just wondering whether link: is working for anyone and it's not working in my case because of something specific to my project, or isn't working at all?
After updating react-scripts to v2.1.5, link it's not woking anymore. It's like peer dependecies weren't isntalled.
Same. It is not possible right now to install deps/build react with npm, only with yarn, because it has following:
...
"eslint-plugin-react-internal": "link:./scripts/eslint-rules/",
...
I tried to use file: then the target package will be directly copied to the node_modules of the current package, and then replace file: with link: to find that it succeeded directly, and there is no redundant copy of node_modules, it has been directly converted into link form
Hereβs the full 1:1 translation into English:
eslint-plugin-test: Cheat-Sheet (local development with link)
TSUP Build (in the plugin)
-
Goal: ESM artifacts for Node 20+ with DTS
-
Core settings:
- clean: true
- entry: ['src/index.ts']
-
format: ['esm'] β produces
dist/index.js -
dts: { resolve: true, compilerOptions: { composite: false } } β produces
dist/index.d.ts - sourcemap: true
- treeshake: true
- tsconfig: 'tsconfig.json'
import { defineConfig } from 'tsup'
export default defineConfig({
clean: true,
entry: ['src/index.ts'],
format: ['esm'],
dts: { resolve: true, compilerOptions: { composite: false } },
sourcemap: true,
treeshake: true,
tsconfig: 'tsconfig.json'
})
package.json (in the plugin)
-
ESM + Exports + Types point to the built artifacts in
dist/ -
mainis optional, can point to the same ESM entry
{
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./package.json": "./package.json"
},
"files": [
"dist/",
"LICENSE",
"README.md",
"!dist/**/*.map",
"!**/*.test.*",
"!**/*.spec.*",
"!**/__tests__/"
],
"scripts": {
"build": "tsup",
"dev": "tsup --watch --config tsup.config.ts",
"preinstall": "npx only-allow pnpm",
"prepare": "husky",
"pack:dry": "npm pack --dry-run"
}
}
package.json (in the consumer)
- Local link to the plugin repo
{
"devDependencies": {
"eslint-plugin-test": "link:C:/Projects/programming-languages/typescript/linting/eslint-plugin-test"
}
}
Usage in consumer (eslint.config.ts)
- Import and use the Flat Config preset
import { enterprisePlugin } from 'eslint-plugin-test'
// β¦
enterprisePlugin.configs.all,
Commands (dev loop)
- Build/watch the plugin:
pnpm -C "C:\Projects\programming-languages\typescript\linting\eslint-plugin-test" dev
# or once:
pnpm -C "C:\Projects\programming-languages\typescript\linting\eslint-plugin-test" build
-
When using dev mode, the files in the consumer project under node_modules update automatically.
-
Update consumer:
pnpm -C "C:\git\test\test-synchronizer" install --force
- Afterwards, restart TS server/IDE if necessary.
Important pitfalls
-
Exports β Build:
"exports"/"types"must match the built files exactly (dist/index.js,dist/index.d.ts). -
CJS vs ESM: If
formatis notesm, then.cjs/.d.ctsare created β update"exports"/"types"accordingly. -
Engines: Make sure Node versions are compatible (plugin
"engines"vs consumer Node).