yarn icon indicating copy to clipboard operation
yarn copied to clipboard

Using link in package.json dependencies gives an error

Open rightaway opened this issue 7 years ago β€’ 10 comments

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

rightaway avatar Sep 14 '18 06:09 rightaway

Thanks! πŸ‘

arcanis avatar Sep 14 '18 07:09 arcanis

@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?

probil avatar Sep 25 '18 20:09 probil

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 avatar Sep 25 '18 20:09 arcanis

@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 πŸ˜…

mbeaudru avatar Dec 21 '18 13:12 mbeaudru

https://github.com/yarnpkg/rfcs/blob/master/implemented/0000-link-dependency-type.md

arcanis avatar Dec 21 '18 13:12 arcanis

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?

rightaway avatar Feb 15 '19 20:02 rightaway

After updating react-scripts to v2.1.5, link it's not woking anymore. It's like peer dependecies weren't isntalled.

mhidalgop avatar Feb 19 '19 08:02 mhidalgop

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/",
    ...

dmitryrn avatar Mar 02 '19 11:03 dmitryrn

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

buns-li avatar Feb 05 '21 01:02 buns-li

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/
  • main is 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 format is not esm, then .cjs/.d.cts are created β†’ update "exports"/"types" accordingly.
  • Engines: Make sure Node versions are compatible (plugin "engines" vs consumer Node).

CyberT33N avatar Sep 05 '25 13:09 CyberT33N