This repository has been archived by the owner on Feb 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 213
Implement Yarn 2 support #1630
Closed
Closed
Implement Yarn 2 support #1630
Changes from 7 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
b752d2f
Use only PnP compatible versions of Jest
constgen f1fe44d
Add PnP middleware
constgen 4052136
Use PnP middleware in presets
constgen 4096203
Add compatibility of PnP in Jest preset aliases
constgen bb9c7e1
Merge branch 'master' into pnp
constgen 9aa579d
Revert Jest peer dependency
constgen 6b79b04
Add utility to alias eslint plugins
constgen a0aa2da
Add utility to alias eslint import resolvers
constgen a922481
Support Yarn 2 in ESLint configuration of all presets
constgen 816197d
Make Webpack optional dependency for ESLint preset
constgen d031f29
Remove usage of PnP API
constgen c4f46a2
Merge branch 'master' into pnp
constgen 128029d
Create new instancies of PnP plugin every time
constgen 86fe991
Correctly test Vue ESlint config dynamic values
constgen 53e6b6b
Fix Prettier violations
constgen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
const moduleAlias = require('module-alias'); | ||
const pnpApi = process.versions.pnp ? require('pnpapi') : null; // eslint-disable-line import/no-unresolved | ||
|
||
function toFullName(pluginName) { | ||
const ESLINT_PREFIX = 'eslint-plugin-'; | ||
const ORGANIZATION_EXPRESSION = /^(@[\d.A-z-]+)\/(.+)$/; | ||
const nameIsFull = pluginName.indexOf(ESLINT_PREFIX) === 0; | ||
const nameIsOrganization = ORGANIZATION_EXPRESSION.test(pluginName); | ||
|
||
if (nameIsOrganization) { | ||
const [, organizationName, name] = pluginName.match( | ||
ORGANIZATION_EXPRESSION, | ||
); | ||
|
||
return `${organizationName}/${toFullName(name)}`; | ||
} | ||
|
||
return nameIsFull ? pluginName : `${ESLINT_PREFIX}${pluginName}`; | ||
} | ||
|
||
function aliasModuleFrom(relativeFilename = __filename) { | ||
return function aliasPlugin(pluginName) { | ||
let resolvedPluginPath; | ||
|
||
if (pnpApi) { | ||
resolvedPluginPath = pnpApi.resolveRequest(pluginName, relativeFilename); | ||
} else { | ||
resolvedPluginPath = require.resolve(pluginName, { | ||
paths: [relativeFilename], | ||
}); | ||
} | ||
|
||
moduleAlias.addAlias(pluginName, resolvedPluginPath); | ||
}; | ||
} | ||
|
||
module.exports = function aliasPlugins(eslintConfig, relativeFilename) { | ||
const { plugins = [] } = eslintConfig; | ||
|
||
plugins.map(toFullName).forEach(aliasModuleFrom(relativeFilename)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/test/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Neutrino Plug'n'Play Middleware | ||
|
||
`@neutrinojs/pnp` is Neutrino middleware for Plug'n'Play support. | ||
|
||
[![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] | ||
|
||
## Requirements | ||
|
||
- Node.js 10+ | ||
- Yarn v1.2.1+, or npm v5.4+ | ||
- Neutrino 9 | ||
- Webpack 4 | ||
|
||
## Installation | ||
|
||
`@neutrinojs/pnp` can be installed via the Yarn or npm clients. | ||
|
||
#### Yarn | ||
|
||
```bash | ||
❯ yarn add --dev @neutrinojs/pnp | ||
``` | ||
|
||
#### npm | ||
|
||
```bash | ||
❯ npm install --save-dev @neutrinojs/pnp | ||
``` | ||
|
||
## Usage | ||
|
||
`@neutrinojs/pnp` can be consumed from the Neutrino API, middleware, or presets. | ||
Require this package and plug it into Neutrino: | ||
|
||
```js | ||
const pnp = require('@neutrinojs/pnp'); | ||
|
||
// Use with default options | ||
neutrino.use(pnp()); | ||
|
||
// Usage shows the default values of this middleware: | ||
neutrino.use(pnp({ pluginId: 'pnp' })); | ||
``` | ||
|
||
```js | ||
// Using in .neutrinorc.js | ||
const pnp = require('@neutrinojs/pnp'); | ||
|
||
// Use with default options | ||
module.exports = { | ||
use: [pnp()], | ||
}; | ||
|
||
// Usage shows the default values of this middleware: | ||
module.exports = { | ||
use: [pnp({ pluginId: 'pnp' })], | ||
}; | ||
``` | ||
|
||
- `pluginId`: The plugin identifier. Override this to add an additional copy | ||
plugin instance. | ||
|
||
## Customization | ||
|
||
`@neutrinojs/pnp` creates some conventions to make overriding the configuration | ||
easier once you are ready to make changes. | ||
|
||
### Plugins | ||
|
||
The following is a list of plugins and their identifiers which can be | ||
overridden: | ||
|
||
| Name | Description | NODE_ENV | | ||
| ----- | --------------------------------------------------------- | -------- | | ||
| `pnp` | Resolve modules considering Plug and Play feature of Yarn | all | | ||
|
||
## Contributing | ||
|
||
This middleware is part of the | ||
[neutrino](https://github.com/neutrinojs/neutrino) repository, a monorepo | ||
containing all resources for developing Neutrino and its core presets and | ||
middleware. Follow the | ||
[contributing guide](https://neutrinojs.org/contributing/) for details. | ||
|
||
[npm-image]: https://img.shields.io/npm/v/@neutrinojs/pnp.svg | ||
[npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/pnp.svg | ||
[npm-url]: https://www.npmjs.com/package/@neutrinojs/pnp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
const moduleAlias = require('module-alias'); | ||
|
||
module.exports = function pnp(settings = {}) { | ||
return function pnpMiddleware(neutrino) { | ||
const { pluginId = 'pnp' } = settings; | ||
const projectPath = process.cwd(); | ||
const environmentIsPnP = Boolean(process.versions.pnp); | ||
|
||
if (environmentIsPnP) { | ||
// solve the issue with the linked middleware outside of the project root | ||
// https://github.com/yarnpkg/berry/issues/693 | ||
moduleAlias.addAlias( | ||
'pnpapi', | ||
require.resolve('pnpapi', { paths: [projectPath] }), | ||
); | ||
} | ||
|
||
// eslint-disable-next-line global-require -- Have to import this after `require` alias is applied | ||
const PnpWebpackPlugin = require(`pnp-webpack-plugin`); | ||
|
||
function PnpPlugin() { | ||
return PnpWebpackPlugin; | ||
} | ||
function PnpLoaderPlugin() { | ||
return PnpWebpackPlugin.moduleLoader(module); | ||
} | ||
|
||
/* eslint-disable prettier/prettier */ | ||
neutrino.config | ||
.resolve | ||
.plugin(pluginId) | ||
.use(PnpPlugin) | ||
.end() | ||
.end() | ||
.resolveLoader | ||
.plugin(pluginId) | ||
.use(PnpLoaderPlugin) | ||
.end() | ||
.end(); | ||
}; | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should just use
require.resolve
you almost never need to use the pnpapi directly, this is one of those casesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know. But unfortunately
__filename
gives a virtual File System path in Yarn 2 which can't work correctly inpaths
options ofrequire.resolve
. Module will be not found with an exception. Struggled with this 2 days.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a reproduction for that? We have tests making sure it works. I could see that happening if you have
enableGlobalCache: true
but that will be fixed in yarnpkg/berry#2068There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any place of your code in Yarn 2 environment try this
console.log(require.resolve('any-of-your-dependency', { paths: [__filename] }))
. It will not find your module even if it is relative from the current file. The same code works without any problems in regular NPM environmentThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will and it does. As I said we have tests that cover this, but just for fun I did try exactly what you said and it works, if you have a reproduction I'd love to take a look at it
Some tests that check this:
https://github.com/yarnpkg/berry/blob/f8344493b5cf3948e71211697b50a268b756d8fc/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js#L1714
https://github.com/yarnpkg/berry/blob/f8344493b5cf3948e71211697b50a268b756d8fc/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js#L609-L612
https://github.com/yarnpkg/berry/blob/f8344493b5cf3948e71211697b50a268b756d8fc/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js#L647-L651
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized that the mentioned test case works in the Yarn 2 project itself. But in the linked module it fails with not found dependency. As you understand I use linked packages for local environments. Such modules are defined as
yarn install
is called to setup all links in.yarn/cache
and.pnp.js
And after that I can run local script
"lint": "eslint ./src --ext .js,.jsx",
to run the code and test the caseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that makes more sense. I'm fairly certain the issue you're running into was fixed in yarnpkg/berry#2068, could you try with
yarn set version from sources
or by downloading thebundle
here https://github.com/yarnpkg/berry/actions/runs/346381133?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before: Yarn version
v2.2.2
After: Yarn version
2.3.3-git.20201112.f5ca1c57
Result is the same in the linked package: works when
require.resolve('babel-eslint')
and fails whenrequire.resolve('babel-eslint', { paths: [__filename] })
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you try using
__dirname
instead?Again, if you could provide a reproduction I'll be able to look into it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update:
After removing
.yarn/cache
and reinstalling dependenciesrequire.resolve('babel-eslint', { paths: [__filename] })
started to work. It was the version2.3.3-git.20201112.f5ca1c57
.Than I upgraded Yarn to the latest
2.4.0
and reinstalled dependencies again. And it still works. So I removed usage of PnP API as you asked