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

perf problems with require.context #13636

Open
alexander-akait opened this issue Jun 25, 2021 · 12 comments
Open

perf problems with require.context #13636

alexander-akait opened this issue Jun 25, 2021 · 12 comments

Comments

@alexander-akait
Copy link
Member

@sokra this issue is very much alive in webpack5 and also affects dynamic require() and import() calls. I created another repro, although probably @ericpitcher's is just as good: https://github.com/tmeasday-shopify/webpack-require-context-repro

We are very interested about this for Storybook in large code bases because we rely on require.context() or some other globbing mechanism to import story files.

Would you like me to open a new ticket or can this ticket be reopened?

Originally posted by @tmeasday in #6093 (comment)

@alexander-akait
Copy link
Member Author

alexander-akait commented Jun 25, 2021

@tmeasday yep, I think we have critical perf bug here

@tmeasday
Copy link
Contributor

tmeasday commented Jun 26, 2021

Thanks @alexander-akait. Happy to help with a solution once the path forward is known. Naively it feels like perhaps there are opportunities to avoid scanning the require.context() when the event that triggers the update is a single file modification (and so is already known to match or not match the context).

@vidal7
Copy link

vidal7 commented Oct 13, 2021

@alexander-akait, with the help of @tmeasday, I found a workaround.

See storybookjs/storybook#14894 (comment)

@alexander-akait
Copy link
Member Author

@vidal7 Can you provide example?

@vidal7
Copy link

vidal7 commented Oct 13, 2021

@alexander-akait, sure instead of doing

module.exports = {
    stories: [
        './src/**/*.stories.ts',
    ]
};

I am doing something like this. I oversimplified my code just for this example.

const { sync } = require('glob');

module.exports = {
    stories: sync('./src/**/*.stories.ts')
};

@kaelig
Copy link

kaelig commented Oct 13, 2021

I believe there's a developer experience caveat – In my tests, the technique described above has an undesirable side effect: the glob function generates an array of files at start time, and after that, it won't dynamically index newly added/renamed files.

This means developers need to restart Storybook whenever they add a new <filename>.stories.ts file, as the newly glob-generated array will then contain this new file.

Ideally, we'd have something fast, with the same "dynamic globbing" as before.

@vidal7
Copy link

vidal7 commented Oct 14, 2021

@kaelig, yes you are right. I have this caveat too. I didn't realized that by doing this, storybook on webpack rebuild does not scan new stories files. I don't have a better solution for now. Guess this issue will have to be resolved if you want new stories files to be indexed. I am sorry.

@alexander-akait
Copy link
Member Author

In theory you can create entry.js file and apply loader, inside loader run glob and create imports like:

import oneStory from "./one-story/index.js";
import twoStory from "./two-story/index.js";

inside loader, use glob-parent (i.e. extract src directory) and use this.addContextDependency https://webpack.js.org/api/loaders/#thisaddcontextdependency, it can be some
slow on initial run, but will be fast for incremental builds, also it will tract all changes inside src directory, i.e. we just generate entry file based on glob.

But why do not use https://webpack.js.org/configuration/experiments/#experimentslazycompilation with import()? All stories can be loaded using import(). If you need to add new story just add new lines to your source file with stories. This is actually very close to how it works in browser, even more it can work in browser without bundlers (in theory). WE don't have glob/require.context in browser and we should migrate from these hacky workarounds.

@tmeasday
Copy link
Contributor

tmeasday commented Oct 15, 2021

@alexander-akait - are you suggesting that they write a big file full of import() functions?

That is definitely possible, but for a development-time tool like Storybook which prioritizes DX over "correctness" in this way, we'd like to figure out a way to make it possible for users to provide a glob but still have good performance.

One idea I've been looking at is to have storybook generate that file of imports, in a similar way to your first suggestion, see this thread: https://webpack.slack.com/archives/C1LUX2DS9/p1633338458009500?thread_ts=1633265679.007900&cid=C1LUX2DS9


All this aside, I'm still not sure what webpack is doing that leads to the poor performance in the first place. When I use watchpack alone and make a change to a single file in a big directory full of stuff, it is fast. My guess is that webpack is re-scanning the glob every time watchpack detects a (set of?) change(s). I'm not sure why it would need to do that, but if there is a good reason I am very interested to know why.

Theoretically there is no reason to re-scan the glob after the initial scan and a stream of changes, especially if those changes are small.

@alexander-akait
Copy link
Member Author

Yes, problems in that we need scan whole directory (include nested) for each build, otherwise we can't catch new/deleted files...

@irudoy
Copy link

irudoy commented Oct 15, 2021

Yes, problems in that we need scan whole directory (include nested) for each build, otherwise we can't catch new/deleted files...

This problem was already solved several years ago in the Jest, and jest-haste-map was made especially for this. It would be great to use it for such cases, but the problem is that it is not well documented.

@alexander-akait
Copy link
Member Author

Yes, hope somebody found time to help us here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Priority - Low
Development

No branches or pull requests

6 participants