-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
RFC: Webpack Performance Budgets #3216
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
I like the idea very much. And I would like to stress that depending on the situation the performance budget could be 500KB or maybe just 100KB. This way people can set their perfomance budget and they will be notified as soon as they come close to the limit. Maybe already notify them when they are at about 80% of the budget. |
Love it! Just wanted to note a nitpick: I'm red-green colorblind, and have a really hard time seeing the difference between the green and the yellow above. Would be great to have some more-different colors there! |
More than happy for us to figure out an alternative color scheme :) Also, glad you like the proposal! |
Great work @addyosmani (and your team)! @rryter I can imagine people setting 5MB perf budget, this just doesn't change anything from what it's now. People just assume "this is okay". Performance is the same for everyone and we should be hard about pointing into it, instead of allowing incremental escapes: "Oh, I'll add another 100KB budget because I need this lib right now." -- three months later -- "Oh, it's 3MB bundle know 😱". |
Great initiative! A few thoughts. Ideally I would like to get feedback on my bundle sizes when in development mode, but like Addy stated - most of us probably don't really do development in production mode. For e.g. I don't use a minifier when in development mode, because it does slow down builds and I like them to be as fast as possible. But a minfier can shed a lot of code off your bundle, especially with webpack 2 tree-shaking feature. AFAIK webpack creates dead code, that's removed during the minfication process. So if I wan't to get an accurate idea of what my bundle size is, I need to minify my code. Oh and there's gzip too... |
👍 This is awesome. I would love to see more optimization warnings like this, things like how much savings you're getting from tree shaking and how much more you could save, so that devs would have a path for reducing those bundle sizes. Projected production metrics while in dev mode would be dope too. |
Lots of excellent ideas here and I'm excited for the possibilities. I just want to remind everyone that for the 1% of people who have super-advanced configs, and the 19% of people who have done the config themselves, there's a much more important 80% of people who hardly think about webpack at all and are shipping apps with the default settings they found in some blog post. Tree-shaking and code-splitting might eventually help them, but they have other work to do first. I would therefore ponder what are the simplest, easiest-to-get-wrong things we could warn them about. These are probably things people remotely familiar with webpack would never do, and so they likely aren't on the top of our minds. Some examples:
Unlike tree-shaking and code-splitting, which may require difficult code changes to work well, these are very simple changes anyone can make and get an immediately benefit. And helping non-experts get easy wins ("Wow, I paid attention to this and reduced my load time by half!") might be a great way to get them excited about worrying about performance more regularly. (I can see a future where, after webpack sees them respond to these initial problems and get a win, it links them to lighthouse or some other tool where they can learn more about performance practices.) A lot of the biggest-impact checks should only run in a production build. Which raises another question: since production builds may only run in CI or on a build server, where people rarely look at the logs, should obvious problems like this return an exit code? It could prompt the developer to either fix the problem or modify their performance options to accept the issue. |
@NekR It depends on what the target audience is. Also if you want to achieve a goal lower than the 250KB, let's say 100KB, that should be configurable. Having a 250KB performance budget or no budget at all isn't going to cut it. I do agree that this is a solid default value though. |
While download time is important, most of the problems is executing/parsing the script which is used in a full size regardless how hard you compress it with gzip. But yeah, I agree to it should be measured against production builds but somehow visible in dev builds too.. @asolove that sounds good, but problem is that it's hard to know if it's a production build or not, i.e. I rarely see people use |
Any tips for configuring/integrating with popular routing solutions like |
Hi great idea and discussion started here. Does it sound like and idea to try and get prod and Dev configs into a single file?
Where Dev and production match node_env? These configs could still be split into separate files to help readability if needed. Just an idea of the top of my head to try and solve the 'webpack is unaware of pros vs Dev bike config' problem. |
It may be good to add a "How to implement PRPL Pattern in Webpack 2" guide in the webpack docs. Mostly so that those messages from oversized chunks can link to it. |
@kennetpostigo, we are in need of, and would openly welcome any PR's on our new docs repo for an article like this. |
👍 Love the idea Addy, especially the ability to opt-out, but I can imagine most performance junkies would want every bit of info to get them "chunking" in the right direction. |
You can already achieve that using an external solution. I wrote webpack-merge to cover that need and you can find a plenty of other flavors with a bit of digging. I'm not sure if something like this belongs to webpack core, though. Maybe better leave to user space. 👍 |
If the goal here is to create tooling for making it easier for developers to understand when they affect the end-user in a negative way, I'd say it would help and be informative to clearly display when a chunk will be (and therefor should be) cache busted. This would hopefully make developers think one moment extra before pulling that nice to have lib into the vendor bundle. |
@jouni-kantola I believe that indicate warnings when a vendors chunk hash has changed its actually a great idea. Secondary to the aforementioned. But extrenely beneficial in my opinion. |
@kostasmanionis There are a few ideas we could tease out here. During production, once tree-shaking/minification/other optimizations have been applied, I think that’s a good point to enforce a performance budget and provide insight into chunk and bundle sizes. (I’ve seen few folks use -p however so we might want to think about dev some more) During dev is a good time to be reminded if you’re on the right path, but I imagine we would want to do this in a way that’s useful but not annoying. E.g we could inform you if you’re not code-splitting, but could also just do it once or provide a way to dismiss the tip if it’s intentional. What did you think of the idea of informing users about bundle sizes and trying to think about getting them smaller?
For sure. I think you’re right that for the long tail there’s going to be a complexity trade-off to consider and lower hanging fruit is always good. I would love for us to consider code-splitting be mentioned in warnings just to increase awareness as it is pretty core to the slowness problems we’re seeing (even if they do look at inline source maps and uglify in prod builds earlier on, which are great things to call out). Maybe we could come up with some nice UX that presents suggestions in terms of effort? e.g [easy, medium, hard].
Imo, defaulting to an exit code with perhaps an option to switch off would be flexible enough for folks?
I tried walking through Webpack perf patterns with React router in part 2 of this PWA series, but there’s been lots of write-ups about code-splitting with React Router by others. With respect to performance insights with Webpack + the router, I haven’t personally seen anything like that just yet. I’ve had to use a source map analyzer to get useful insights on that in the past. |
I am planning a new project to separate the source code and build environment to keep optimization strategy ongoing. |
Trying out some of the idea expressed here as a plugin - https://github.com/vigneshshanmugam/perf-hints-plugin/... Just set it up, but would be easy to get to integrate lighthouse and suggest all the endless possibilities in Performance tuning. |
Great suggestion from @addyosmani 👍 In my experience developers rarely do production builds. These production build are typically done on the CI server where developers don't look at the log unless there is an issue. So I would enable this for all builds even though for development builds the artifacts will be larger. Maybe the threshold should be increased there before producing warnings. In a production build on the CI server I would like this by default fail the build. If we just print a warning to the log this will mostly go unobserved. |
I'm a bit concerned a few people are saying This does highlight use cases though. Using webpack to :
I wouldn't like to see these hints on dev code, unless they are accurately adjusted to take the dev vs prod config into account. But, I can't see how this could be accurately achieved; and if it is not accurate, it will get ignored. (e.g. is the budget on dev is 1.2mb instead of 200k??) How do we want webpack to behave:
Considering writing hints against dev code will be an inaccurate comparison for prod, I think we can ignore non-prod setup. All webpack can do is highlight in the docs how important testing prod code is and how great So tl;dr: Ignore dev-builds and only use the hint config for production ( |
While I agree with @peter-mouland that developers should test locally against production build I am afraid that this is not the reality for quite a number of developers. Yes there are plenty of developers doing the right thing. They have CI servers set up and think about these things. However with the Angular CLI, Create-React-App and similar you will see plenty of developers using Webpack who are not as good and don't follow best practices. IMHO these are far more common and are the category that need far more guidance. Personally I would consider these developers as a far more important audience for a automatic performance budget. |
This is spectacular! Looking forward to giving it a spin. 🙌 Just as food for thought, I see performance in two ways:
I'm thinking developers should also be able get insight into build speed performance. E.g.
I understand that some of this can be obtained with a bit more digging, but now that we're talking... 😉 |
I think all of us see the value that this feature is trying to bring to the table and will find it very useful for production configurations. Although, it would be much better if it was opt in, instead of opt out. Really I think what the community is shouting about, is our concern for the cleanliness of the output of webpack. Some of us have very strong feelings about manner in which webpack outputs information by default. It is after all, our most important tool in our tool chains. Many of us believe that the only thing that should be spit out by default, is clean, legible, statistics only. These types of tools are already crowded enough as it is. We just want to reason over clean output… that’s all. Can you imagine if we were the only bundler who managed to get that right?! The current incarnation of this feature takes up the bottom of the output where far more relevant information could be given to the developer. If we were to treat the developer as a user, the user experience is poor in it's current incarnation. We should remember that defaults only exist to accommodate for an overwhelmingly commonly used scenario. Just look at the issues related to this topic... The community is making it clear, that in many cases, this is simply unwanted spam. Fortunately, the solution is simple from here. Turn it off by default. If proponents of this feature are so concerned about advocating this particular max size… they should submit a pull request that implements a complete and robust tree-shaker instead. The truth is that they are not understanding the larger nature of the problem we are trying to solve. It might be worth taking into consideration that this recommendation will become irrelevant as the industry progresses. Computational power will inevitably progress. Why would we ever want to bake all of this irrelevant spam into this magnificent tool by default? History will remember us. But that’s just our opinion ^_^ |
For those that don't realize how nasty the current incarnation of this feature can get... please note that the following only has one offending bundle that goes over the presumptuous max size. It seems that chunks that come after the offending bundle, cascade a whole bunch more warnings for some reason. We are really not making things up when we say this is spammy. Our company is so sad that this is how our favorite tool behaves by default... >,<
|
@ZenSoftware we listened as you can see we have turned it off by default. #3604 But as an aside, those warnings are not coming up for no reason. I do not know your business case or user base or device or load time requirements, and I am not responsible for your apps page speed, but FWIW, shipping 3MB of JavaScript is massive and should probably be addressed anyways (if possible). Keep in mind that we originally intended to show these values unminified because it's the parse and eval cost of 3MB (after decompressed) that causes slowdown just as much as download and network speed when it comes to web perf cost, and should be taken seriously. But as you all have made a great point: none of this is our business and we should be better at making it easy for these things to appear when "you want them to" regardless of the potential impact. That being said the long term goal is to enable this feature by default in prod (if we can eventually determine this) so we would love great ideas and input on how to implement. For now the only default feature you will see is Ref: #3611 |
Alright!!! We are so happy to see that the project is molding itself for the betterment of the community. @TheLarkInn Yes, it really is an enormous vendor bundle isn’t it? We are effectively trying to build what is an operating system, that runs in a web browser. So you could say we need a couple of 3rd party libraries, haha. When no tree-shaking is done, that’s what ends up happening. It’s really not unique to my project. We all know what's going on here, it's not a secret. The industry has been struggling with this problem since the inception. So that's why we find it strange that the warning is so... obtrusive. On a side note, can you imagine if GCC v0.9 output something like:
It would be so weird if that’s what the original developer of this famous compiler chose to spit out by default. It would make using this legacy compiler… feel dirty. All we are saying is that we are just concerned about the long-term quality of webpack, that’s all. We are so happy that it is moving in the right direction again. |
Okay that is not only a great point but pretty funny as well. We will keep this thread open for now in case additional feedback is given. Thank you for the support and feedback. |
Would it also be useful to have a warning for HTML files larger than 14Kb? |
Hi, @TheLarkInn ! I see your code about the target checking for Actually now in my If I was not wrong, should we add the target checking back to I'd like to make a PR if it needed. Just want to make sure which way is right at first. |
is it minified size or compressed size ? Can I configure it to compressed size like gzip ? |
@TheLarkInn @addyosmani meanwhile, the two smaller bundles that we had crept on from 350 to 600kb and had no error (because: < 1.5mb) |
@nilanjansiromani Give Gimbal a try: https://github.com/ModusCreateOrg/gimbal/ |
This didn't age well for Flipkart and Housing.com :) |
@addyosmani I'm using the built-in plugin
The size of update: I also made a detailed feedback on the current problem of this "warning". See #3486 (comment). |
This comment was marked as resolved.
This comment was marked as resolved.
We are working together with Github supports with this problem, so don't worry about it |
Webpack version:
1.10.x and 2.x
Please tell us about your environment:
OSX 10.x / Linux / Windows 10 [all]
Expected/desired behavior:
Highlight at build-time any JavaScript chunks or bundles that are over a size threshold and can negatively impact web performance load times, parse/compile and interactivity. A default performance budget could indicate if total chunk sizes for a page are over a limit (e.g 250KB).
I'd love to see if we could make this a default and offer a config option for opting out 🏃♀️ Concern with an opt-in is the folks with the worst perf issues may not know to enable it or use this via a plugin if this suggestion was deferred to one. These folks may also not be testing on mobile devices.
Optionally, highlight where better performance patterns might be helpful:
Current behaviour:
Many of the apps bundled with Webpack that we trace ship a large, single bundle that ends up pegging the main thread and taking longer that it should for webapps to be interactive:
This isn't Webpack's fault, just the culture around shipping large monolithic bundles. This situation gets particularly bad on mobile when trying these apps out on real devices.
If we could fix this, it would also make it way more feasible for the Webpack + React (or Angular) stacks to be good candidates for building fast web apps and Progressive Web Apps 🔥
What is the motivation / use case for changing the behavior?
I recently dove into profiling a large set (180+) React apps in the wild, based on 470 responses we got from a developer survey. This included a mix of small to large scale apps.
I noted a few common characteristics:
Table 1: Summary of time-to-interactive scoring (individual TTI was computed by Lighthouse)
We generally believe that splitting up your work into smaller chunks can get you closer to being interactive sooner, in particular when using HTTP/2. Only serving down the code a user needs for a route is just one pattern here (e.g PRPL) that we’ve seen helps a great deal.
Examples of this include the great work done by Housing.com and Flipkart.com. They use Webpack and are getting those real nice numbers in the last column thanks to diligence with perf budgets and code-splitting 👍.
What impacts a user's ability to interact with an app?
A slow time to being interactive can be attributed to a few things:
If we looked at tools like performancebudget.io, targeting loading in RAIL’s <3s on 3G would place our total JS budget at a far more conservative 106KB once you factor in other resources a typical page might include (like stylesheets and images). The less conservative number of 250KB is an upper bound estimate.
Code-splitting and confusion
A surprising 58%+ of responders said they were using code-splitting. We also profiled just this subset and found that their average time to being interactive was 12.3 seconds (remember that overall, the average TTI we saw was 12.4 with or without splitting). So, what happened?
Digging into this data further, we discovered two things.
CommonsChunkPlugin
to 'split' vendor code from main chunks was code-splitting?) 🤔Keep in mind: it's entirely possible to ship fast apps using JS that are interactive quickly with Webpack - if Flipkart can hit it in under 5 seconds, we can definitely bring this number down for the average Webpack user too.
Note: if you absolutely need a large bundle of JS for a route/page to be useful at all, our advice is to just serve it in one bundle rather than code-split. At an engine level this is cheaper to parse. In most cases, devs aren't going to need all that JS for just one page/view/route so splitting helps.
What device was used in our lab profiling?
A Nexus 5X with a real network connection. We also ran tests on emulated setups with throttled CPU and network (2G, 3G, 4G, Wifi). One key thing to note is if this proposal was implemented, it could benefit load times for webapps on all hardware, regardless of whether it's Android or iOS. Fewer bytes shipped down the line = a little more ❤️ for users data plans.
The time-to-interactive definition we use in Lighthouse is the moment after
DOMContentLoaded
where the main thread is available enough to handle user input ✋. We look for the first 500ms window where estimated input latency is <50ms at the 90th percentile.Suppressing the feature
Users could opt-out of the feature through their Webpack configuration (we can 🚲 🏠 over that). If a problem is that most devs don't run their dev configs optimized for production, it may be worth considering this feature be enabled when the -p production flag is enabled, however I'm unsure how often that is used. Right now it's unclear if we just want to define a top-level
performanceHints
config vs aperformance
object:Optional additions to proposal
Going further, we could also consider informing you if:
require.ensure()
orSystem.import()
). This could be expanded to also provide suggestions on other perf plugins (likeCommonChunksPlugin
)System.import()
orrequire.ensure()
? The minimum config is just the minimum requirements aka the entry ouput today.Thanks to Sean Larkin, Shubhie Panicker, Gray Norton and Rob Wormald for reviewing this RFC before I submitted it.
The text was updated successfully, but these errors were encountered: