Skip to content
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

Very slow parsing #186

Closed
4 tasks done
shirotech opened this issue Jul 11, 2022 · 13 comments
Closed
4 tasks done

Very slow parsing #186

shirotech opened this issue Jul 11, 2022 · 13 comments

Comments

@shirotech
Copy link

shirotech commented Jul 11, 2022

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I'm using eslint-plugin-svelte.
    (*.svelte file linting does not work with the parser alone. You should also use eslint-plugin-svelte with it.)
  • I'm sure the problem is a parser problem. (If you are not sure, search for the issue in eslint-plugin-svelte repo and open the issue in eslint-plugin-svelte repo if there is no solution.
  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.

What version of ESLint are you using?

8.19.0

What version of eslint-plugin-svelte and svelte-eslint-parser are you using?

latest

What did you do?

I'm using a very minimal configuration, only extending plugin:svelte/base which only contains 2 rules: svelte/comment-directive and svelte/system

I've run a benchmark on a substantially large project with hundreds of svelte files.

% time TIMING=1 eslint --ext .svelte,.js,.ts,.cjs 'src/**/*.svelte'
Rule                     | Time (ms) | Relative
:------------------------|----------:|--------:
svelte/comment-directive |     4.085 |    66.7%
svelte/system            |     2.041 |    33.3%

TIMING=1 eslint --ext .svelte,.js,.ts,.cjs 'src/**/*.svelte'  141.41s user 1.09s system 104% cpu 2:16.41 total

As you can see, those rules only added 6ms, but it took over 140 seconds to parse these files.

What did you expect to happen?

eslint should have finished within 2 seconds

What actually happened?

eslint finished over 140 seconds

Link to Minimal Reproducible Example

Because the project is proprietary, I cannot share it in a reproduction repo. But I'm confident it can be replicable on any large project.

Additional comments

No response

@shirotech
Copy link
Author

shirotech commented Jul 11, 2022

Actually, I've narrowed it down to this specific filesize, here is a sample svelte file that will take over 111 seconds!! Yes, for a single file: https://paste.ofcode.org/CZPqC28RdBCrkiipQwBuiy

% time TIMING=1 eslint --ext .svelte,.js,.ts,.cjs 'src/ssr/Head.svelte'
Rule                     | Time (ms) | Relative
:------------------------|----------:|--------:
svelte/system            |     0.177 |    52.1%
svelte/comment-directive |     0.163 |    47.9%
TIMING=1 eslint --ext .svelte,.js,.ts,.cjs 'src/ssr/Head.svelte'  111.59s user 0.46s system 100% cpu 1:51.91 total

Also, I have tested to make sure it is not the svelte parser itself.

import fs from 'fs';
import {parse} from 'svelte/compiler';

parse(fs.readFileSync('src/ssr/Head.svelte', 'utf8'));

Using this code, it ran and finished instantly.

@ota-meshi
Copy link
Member

Thank you for this issue.
I have debugged it, but if it replace the style content with whitespace , 'svelte/compiler' will be very slow.

import fs from "fs";
import { parse } from "svelte/compiler";

const fixture = fs
  .readFileSync("src/ssr/Head.svelte", "utf8")
  .replace(/(<style.*?>)([\s\S]*?)(<\/style>)/u, (_, p, c, s) => {
    return p + c.replace(/\S/gu, " ") + s;
  });

parse(fixture);

This parser causes this problem because it parses CSS content by replacing it with whitespace.
The reason for doing it is that svelte itself cannot parse SCSS etc.

I will consider a workaround when I have time, but it could be a problem with svelte itself.

@ota-meshi
Copy link
Member

I found a problematic regex in svelte. This regex consumes most of the time it takes.

https://github.com/sveltejs/svelte/blob/ccbf10c16326cffb1b38e721e2f74aad4b85dbf2/src/compiler/parse/index.ts#L37

@ota-meshi
Copy link
Member

I opened a issue in the Svelte repository.
sveltejs/svelte#7675

@shirotech
Copy link
Author

shirotech commented Jul 11, 2022

I found a problematic regex in svelte. This regex consumes most of the time it takes.

Nice one! 👍

However, one thing I don't understand is that if I run this code:

import fs from 'fs';
import {parse} from 'svelte/compiler';

parse(fs.readFileSync('src/ssr/Head.svelte', 'utf8'));

directly using svelte parse(), it doesn't have any slowness?

@shirotech
Copy link
Author

import fs from "fs";
import { parse } from "svelte/compiler";

const fixture = fs
  .readFileSync("src/ssr/Head.svelte", "utf8")
  .replace(/(<style.*?>)([\s\S]*?)(<\/style>)/u, (_, p, c, s) => {
    return p + c.replace(/\S/gu, " ") + s;
  });

parse(fixture);

Is regex part of svelte-eslint-parser? if so can we do something like this? Removing the contents, rather than replacing it with whitespace?

import fs from "fs";
import { parse } from "svelte/compiler";

const fixture = fs
  .readFileSync("src/ssr/Head.svelte", "utf8")
  .replace(/(<style.*?>)([\s\S]*?)(<\/style>)/u, '$1$3');

parse(fixture);

@ota-meshi
Copy link
Member

When we remove the content, we need to recalculate the correct location of the node and token. If we use whitespace, we don't need it.

@shirotech
Copy link
Author

shirotech commented Jul 11, 2022

@ota-meshi Okay I see, fully understand the problem now.

  1. Seems that we need an efficient way to disable styles, svelte3 plugin seems to have a similar feature https://github.com/sveltejs/eslint-plugin-svelte3/blob/00e24a4474dae29dd9d06c467cbe5f2c61c60b82/src/preprocess.js#L39 looks like it is more selective on the attributes. I guess if we replace it with any characters other than whitespace it might work? For example, underscores?
  2. The root of the issue is from https://github.com/sveltejs/svelte/blob/ccbf10c16326cffb1b38e721e2f74aad4b85dbf2/src/compiler/parse/index.ts#L37 as you've mentioned, and according to the git history it's been there for half a decade, it might be unlikely they are going to fix it. If it comes down to it, I might have to use pnpm/yarn patching features https://pnpm.io/next/package_json#pnpmpatcheddependencies

@ota-meshi
Copy link
Member

I opened PR in the svelte repository.

sveltejs/svelte#7706

@shirotech
Copy link
Author

@ota-meshi it seems won't be merged any time soon, can I suggest we replace the style content with null (\0) instead of space? I think that will resolve the issue, what do you think?

@ota-meshi
Copy link
Member

No workaround needed once the PR is merged. I will not spend more time on this issue.

@JounQin
Copy link
Collaborator

JounQin commented Aug 9, 2022

No workaround needed once the PR is merged. I will not spend more time on this issue.

Or maybe @shirotech can just raise a PR to fix that issue instead on our side?

@ota-meshi
Copy link
Member

ota-meshi commented Sep 2, 2022

Now that the latest version of Svelte has been released, so I close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants