Berry: [Bug]

Created on 10 Apr 2020  路  4Comments  路  Source: yarnpkg/berry

  • [ ] I'd be willing to implement a fix

Describe the bug

When using workspaces, running a binary in workspace-b from workspace-a does not carry the resolution context of workspace-a with it. This means that if I have a tool that can require plugins, I have to specify them in the packageExtensions in .yarnrc.yml rather than as dependencies of workspace-a.

I suspect that this may be a similar issue to #1058

Background

To Reproduce

I have created a minimal example repository at https://github.com/andypalmer/yarn2_tool_plugin_issue

Environment if relevant (please complete the following information):

  • OS: OSX Darwin 18.7.0
  • Node version: 12.16.1
  • Yarn version: 2.0.0-rc.31 (via 1.22.4)

Additional context

I have custom formatters for eslint and jshint. The current jshint resolution logic requires us to specify custom formatters by relative path from the script execution context (e.g. --reporter node-modules/jshint-junit-formatter/reporter.js). I patched jshint to not force reporter to require relative paths, but when jshint is executed from my patched-jshint workspace, it can't see my formatter because it's defined as a devDependency of the app that I'm checking, not as a dependency of jshint.

eslint is able to access the custom formatters via PnP resolution, so it appears to only affect resolution when the binary doing the require is one of my workspaces.

While I could add the dependency to the jshint-patched workspace, this isn't really in keeping with either the idea of plugins, or in making the patches absolutely minimal.

bug not a bug

Most helpful comment

Two ways to fix that:

  1. You can make jshint require the formatter on behalf of the configuration (here, the command line's cwd). Practically, this means that instead of require(plugin), you'd instead do something similar to require(require.resolve(plugin, {paths: [cwd]})).

  2. You can create a file in your project that just contains module.exports = require(plugin). This would also allow you to avoid having to patch jshint, since you'd be using a relative path.

All 4 comments

Two ways to fix that:

  1. You can make jshint require the formatter on behalf of the configuration (here, the command line's cwd). Practically, this means that instead of require(plugin), you'd instead do something similar to require(require.resolve(plugin, {paths: [cwd]})).

  2. You can create a file in your project that just contains module.exports = require(plugin). This would also allow you to avoid having to patch jshint, since you'd be using a relative path.

Can you explain what you mean by the first option? I'm probably missing something, but isn't that going to recreate the same issue by forcing it to resolve relative to the cwd? (my reporter is a module in the yarn cache)

I did think about 2, but that's a workaround rather than fixing the problem (and I'd put forward that it's more reasonable for people to provide reporters as plugins via the registry than to expect everyone to always use relative paths)

One problem (and potentially a bug) is that the PnP resolution is different when jshint is included via a workspace vs when it is downloaded and accessed via the cache.
That is, if I've included both jshint and jshint-plugin as dependencies in app, then when I run yarn workspace app jshint --reporter jshint-plugin, the PnP resolution should be the same regardless of whether jshint is included via a workspace or from the cache.
My guess is that the jshint workspace is taking precedence over the app workspace, despite jshint being called from app.

I did look at the troubleshooting documentation. Your option 1 above seems to be the same as option 2 there, and what (I think) I'm trying to achieve is option 3.

I don't really understand the resolution semantics behind options 1 and 2 though. I think that there is a lot of tacit knowledge that I don't have the context for.

I thought I had understood option 1 (the paths isn't where to look for the modules, it's where to start resolution from), but it seems that it works if I do require(require.resolve(fp)) without the paths option. As long as I hit the resolver it works ok 馃し

Thanks for your quick response.
I think my confusion came about because eslint actually does use a resolver, but they set it up earlier and call the resolved path as require(formatterPath) which looked a lot like the naked require in jshint.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mormahr picture mormahr  路  3Comments

Santas picture Santas  路  3Comments

bradleyayers picture bradleyayers  路  3Comments

thealjey picture thealjey  路  4Comments

larixer picture larixer  路  4Comments