-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
"Parsing error" when using Yarn 2.0's Plug 'n' Play #1592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
From the stack trace, it looks like this is an error in yarn. Would you be able to produce a small repro repo to help look into it? |
Certainly! |
This does not repro on my system using your example repo. |
Thanks for checking. I'll see if I can get some non-Windows coworkers to try... |
Hmm, windows 10 - I tried on macos. If yes, then this is definitely a yarn2 problem. |
It did not fix it (here are debug logs from before and after monkey-patching the .zip in the yarn cache: https://gist.github.com/jstaro/c73b02664993c931a30c705e9cddde03). |
It was a long shot! Just thought I'd put it out there, as another user using yarn 2 suggested that change to fix yarn 2 with our packages. |
@bradzacher i will check this in few hours when i get back from work |
Found the culprit. This happens because So it is the perfect storm of the three interacting. |
we lowercase the paths on case insensitive OS because TS does the same under the hood. If we don't sync with TS's implementation, then we can have cache misses, and falsely report files as not found. so this is a bug in yarn then? Probably worth raising it with them. |
I'm not sure there's anything we can do on our side - this kind of normalization goes against the very purpose of Yarn which is to ensure a deterministic behaviour as much as possible, even across platforms. If the PnP API was to be case-insensitive, it could lead to working Windows programs that would fail on Linux (unless we switched the API to be case-insensitive everywhere, which won't happen 😄). Imo if you really want the normalization (which is reasonable), lowercasing the path should be done when computing the cache key, but not for the actual file manipulation. This would make both tools work. Does that make sense? Basically, something like this: const getCached = p => {
const cacheKey = getCanonicalFileName(p);
cache[cacheKey] = cache[cacheKey] || loadFile(p);
}; Instead of something like: const getCached = p => {
p = getCanonicalFileName(p);
cache[p] = cache[p] || loadFile(p);
}; Note that I don't have any knowledge of your codebase except for what's mentioned in this thread so I might be very wrong - feel free to correct me if you think this isn't possible. |
Which is why it should be contextually case sensitive right? If the OS is case sensitive, shouldn't yarn also follow suit, so that the experience is predictable?
It's not our cache, it's typescript's cache. When we step back out of the internals, then we instead use the filepath as written: typescript-eslint/packages/typescript-estree/src/create-program/createProjectProgram.ts Lines 32 to 46 in 2ccd66b
|
Not really. If a project is configured to use PnP, then there is no reason to make it compatible with non-PnP setups - otherwise it'd be a bit like saying that Jest and Mocha should have the same configuration file for predictable usage. By contrast, the OS will vary from a contributor to the other, and even during deployments (even people developing on Windows will most likely deploy on Linux). We must have a consistent behavior by following the strictest common denominator.
Hm. I think I'll need to try it out myself to better understand if there's something we could do 🤔 |
@arcanis How about using I know PnP patches
|
Does anyone has a quick and dirty fix for now? |
I have created a quick and dirty solution for now. const origStr = ` function findPackageLocator(location) {
let relativeLocation = normalizePath(fslib_2.ppath.relative(runtimeState.basePath, location));`;
const fixedStr = ` function findPackageLocator(location) {
let basePath = runtimeState.basePath;
if (location && process.platform === 'win32' && location.length >= runtimeState.basePath.length) {
const lowerCaseBasePath = runtimeState.basePath.toLowerCase();
if (location.startsWith(lowerCaseBasePath)){
basePath = lowerCaseBasePath;
}
}
let relativeLocation = normalizePath(fslib_2.ppath.relative(basePath, location));`;
module.exports = {
name: `plugin-pnp`,
factory: (require) => ({
hooks: {
afterAllInstalled(project) {
const fs = require('@yarnpkg/fslib');
const pnpFile = fs.ppath.join(project.cwd, `.pnp.js`);
const pnpContent = fs.xfs.readFileSync(pnpFile, `utf-8`);
const fixed = pnpContent.replace(origStr, fixedStr);
fs.xfs.writeFileSync(pnpFile, fixed, `utf-8`);
},
},
}),
}; and then add to your plugins:
- path: plugin-pnp.js The plugin will make sure your |
@clemyan do you have a way to pinpoint to the location that needs to be patched in typescript? I can verify your fix and maybe make a PR to yarn... |
@bradzacher my CI works perfectly on windows machines using yarn 2 and typescript, and the only thing failing is eslint, which means that yarn 2 is working well with typescript on windows machines. Doesn't that forces us to come to a conclusion that the issue stems from your library and not typescript/yarn2? |
Yarn2 works with typescript, because (from my understanding) it patches your typescript package so that it works with typescript (https://github.com/yarnpkg/berry/blob/9076e9bf68e1a74f01b8184749f258ce8741d324/packages/plugin-compat/sources/patches/typescript.patch.ts). You're welcome to have a look at our source code - the only thing we do to file paths is: ensure they're absolute, and ensure they match TS's casing. Why? Because we have to ensure that ESLint interops with typescript. ESLint provides no guarantee about the casing of the file paths, nor does it guarantee that a path is absolute or relative. TS on the other hand guarantees that all paths given to us from the program host's callback functions are both absolute, and normalised in casing. Thus, we must ensure that ESLint's paths match TS's paths by normalising their casing and ensuring they're absolute. In this regard, our package follows typescript's internal implementation. This is the function we use to normalise the casing of paths: This is typescript's function to do the same thing: They're exactly the same - relying upon I don't have a windows dev box, nor do I use yarn 2. This mirrors the majority of our userbase right now. For these reasons, I won't be looking into it myself in the near future - as a volunteer maintainer there are more pressing issues for me to focus on. We're a community maintained project. We rely upon contributions from the community to help move the project forward. As such, you're welcome to dig into the thin layer to investigate where the potential incompatibility with yarn2 might be. Here is a quick rundown on how the parser interops with TS: The entrypoint to a parse triggered by ESLint is here: If you do not have If you have
If there is a program, it does some basic caching using TS's normalised filenames - this saves us having to do an expensive lookup in the program unless we have to. If there are no programs for a project, it calls If for some reason there are no programs containing the given file, then |
No, my comment above is just throwing some ideas out here. However, as far as I can see, the only blocker is the fact that If I need to use |
From my understanding, there are two ways this issue could be fixed:
I'll apply a change in microsoft/TypeScript#35206 to implement his second option, I'll appreciate if some of you can then test it in your projects. |
@arcanis thanks that will be perfect! Once you implement it I will gladly verify it. @clemyan thanks for your response, it seems that @arcanis will try to make a fix. In the mean while I posted here a quick fix that you can already use @bradzacher I'm sorry if it seems like I came too strong in my comment. That was not my intention. I'm an open source maintainer my self and truly appreciate all your work! I was just trying to figure out how to fix the issue properly and I appreciate all the info you provided. Let's see if @arcanis can fix the issue and move forward from there. |
@regevbr I've opened a PR, check the instruction inside it: yarnpkg/berry#1205 (comment) |
PR confirmed and merged; I've tested myself, and the repository set up by @jstaro doesn't exhibit the problem anymore starting from Yarn master. I think this issue can be closed! 🙂 |
Thanks @arcanis! I also confirmed on my windows machine that it works great with ts 3.8 |
Thanks for looking into and fixing this! |
Uh oh!
There was an error while loading. Please reload this page.
I just migrated to Yarn 2.0 and enabled PnP. Got our webpack + babel + TypeScript pipeline up and running. Eslint, however, both when run through the CLI and as part of Webpack, throws OOM errors. Running eslint with --debug, I could see that something in the plugin chain throws an error and if you get enough of them, a generic OOM triggers. Basically all files being checked throw this error.
What did you expect to happen?
Being able to run eslint w/
@typescript-eslint/plugin
on our TypeScript code base.What actually happened?
I cannot tell if this is a bug in the parser, the plugin, or in the PnP API, or Yarn's bundled patched TypeScript compiler, or a combination. However, disabling
@typescript-eslint/parser
and running the same setup on a.js
file works fine., so hence why I'm posting it here. I've also disabled all other eslint plugins with no change, so any of those shouldn't be the culprit either.Versions
@typescript-eslint/parser
2.19.2
TypeScript
3.7.5
*babel
7.8.4
ESLint
6.8.0
node
10.16.3
yarn
2.0.0-rc28
The text was updated successfully, but these errors were encountered: