-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
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
Performance - Reduce build time and memory usage #4765
Comments
For anyone interested, we added the ability to customize the jsLoader here #4766 This gives the opportunity to replace babel by esbuild, and you can add this in your config: webpack: {
jsLoader: (isServer) => ({
loader: require.resolve('esbuild-loader'),
options: {
loader: 'tsx',
format: isServer ? 'cjs' : undefined,
target: isServer ? 'node12' : 'es2017',
},
}),
}, We don't document it yet (apart here). Important notes:
|
came from #4785 (comment). Just wondering, is this issue aiming to reduce build time for entire site generator (including md/mdx parser, or Docs), or just jsx react pages? |
@adventure-yunfei md docs are compiled to React components with MDX, and the alternative js loader like esbuild also process the output of the MDX compiler, so this applies to documentation as well. Check the mdx playground to test the mdx compiler: https://mdxjs.com/playground/ If you have 10k docs you basically need to transpile 10k react components |
@slorber perfect! we're also trying to use esbuild to boost build time (for application project). I'll have a try on this. BTW I've created a similar large doc site here from our internal project. Update:
|
This gave a nice performance boost, although I think there are still more to be desired. Out of curiosity, what is actually going on that is taking so much time behind the scenes? In our case (a site with around 2,000 .md(x) files) most of the time spent seems to be before and after the "Compiling Client/Compiling Server" progress bars appear and complete. As it stands, building the site takes around 20 minutes with esbuild, and was closer to 40 minutes before. Then out of curiosity, I just tested to add four versions to our site, and building it. Before using esbuild, the process took just shy of 13 hours(!). Using esbuild it was down to just shy of 8 hours. (Still way too long to be acceptable). So while it was a big improvement, it still seems to be very slow. In the second case, it reported:
What was going on for the remaining 5 hours? Is this normal behavior, or did we configure something incredibly wrong? And why does it take much longer than four times the amount of time with four versions added? |
@alphaleonis it's hard to say without further analysis, but the MDX compiler is transforming each md doc to a React component, that is later processed by babel (or esbuild). The MDX compiler might be a bottleneck, this is why I'd like to provide an alternate MD parser for cases where MDX is not really needed. Webpack might also be a bottleneck. Using esbuild is not enough. Also when using esbuild as a webpack loader, we are not really leveraging the full speed benefits of esbuild. Unfortunately we can't replace replace Webpack by esbuild easily, it's part of our plugin lifecycle API and Webpack is more featured than esbuild (we use various things like file-loader, svgr loader...)
We have enabled Webpack 5 has persistent caching, and rebuild times are much faster. You need to persist
It's hard to tell without measuring on your system. Your system may have not enough memory for Webpack to do its job efficiently, leading to more garbage collection or whatever. |
@slorber Thanks for the explanation. We did try the persistent caching, and it seems to help a lot with the time spent during the "Build server/client" phase (which I assume is Webpack). The machine in question had 16GB memory, and the same was specified as Is there any way we can do some further analysis, such as enabling some verbose logging to get some more details perhaps? Or is this kind of the expected build time for sites of that size? (If so I guess we will have to find another solution for versioning, such as building/deploying each version separately. |
This is true - but there's still a speed benefit to take advantage of. It's also pretty plug and play to make use of. See my post here: |
This is a Webpack-based app, and the plugin system enables you to tweak the Webpack config to your needs ( I'm not an expert in Webpack performance debugging so I can't help you much on how to configure webpack and what to measure exactly, you'll have to figure out yourself for now.
It's hard to have meaningful benchmarks. Number of docs is one factor but also the size of docs obviously matter so one site is not strictly comparable to another. 40min build time for 2000 mdx docs with babel seems expected when comparing with other sites. Obviously it's too much and we should aim to reduce that build time, but it's probably not an easy thing to do.
For large sites, it's definitively the way to go, and is something I'd like to document/encourage more in the future. We have made it possible to include "after items" in the version dropdown, so that you can include external links to older versions, and we use it on the Docusaurus site itself: I also want to have a "docusaurus archive" command to support this workflow better, giving the ability to publish a standalone version of an existing site and then remove that version. |
Saddly the process costs a very large memory. |
It is unexpected that beta.2 is faster than beta.0, maybe you didn't clear your cache?
What do you mean by the "emitting phase"? I didn't take much time to investigate all this so any info can be useful. |
I'm using the esbuild-loader config from the docusaurus website example. So it should be esbuild making build faster.
This may not be accurate. The process memory was 7G most times. About 20 minutes later memory jumped to 20.2G while the console showing Client "emitting". After client build finished, the memory dropped down to 7G. (The Server was still building) |
Trying to test I have added the following to the top level of my
I have added the following to my dependencies in
The install of |
Seems like it was one of the good ol' corporate proxy issues giving me the install troubles.. I'll try and test the |
Tested yesterday with production build, took about 3 hours compared to 6 hours before ( So about half the time with the
I witnessed the same thing where the memory usage would suddenly spike up to take 25+ gb. |
Thanks for highlighting that, we'll try to figure out why it takes so much memory suddenly |
Not 100% related but I expect this PR to improve perf (smaller output) and reduce build time for sites with very large sidebars: #5136 (can't really tell by how much though, it's site specific so please let me know if you see a significant improvement) |
Tested my application with latest dev version.
Seems not working for my case. Update:
|
I've made another test, using plugin to override // inside docusaurus.config.js
{
// ...
plugins: [
function myPlugin() {
return {
configureWebpack() {
return {
module: {
rules: [
{
test: /\.mdx?$/,
include: /.*/,
use: {
loader: require('path').resolve(__dirname, './scripts/my-md-loader.js')
}
}
]
}
}
}
};
}
],
} // scripts/my-md-loader.js
module.exports = function myPlugin() {
const callback = this.async();
return callback && callback(null, 'empty...');
}; And then run doc builder again.
So I'm afraid it's the code of page wrapper (e.g. top bar, side navigation, ...) that causes the max memory usage. Switching mdx-loader to another one may won't help. |
@adventure-yunfei it's not clear to me how to do those measures, can you explain? If you allow Docusaurus to take up to 20go, it may end up taking 20go. And it may take more if you give it more. The question is, how much can you reduce the
Proving a memory issue is not the mdx-loader does not mean it's the "page wrapper". There is much more involved than the React server-side rendering here. I suspect there are optimizations that can be done in this webpack plugin's fork we use: https://github.com/slorber/static-site-generator-webpack-plugin/blob/master/index.js Gatsby used it initially and replaced it with some task queueing system. |
That's true. By saying "page wrapper" I mean any other code outside the md page content itself. Just trying to provide more perf information to help identify the problem. More info: |
Use `esbuild-loader` to reduce build times. This is currently not documented on Docusaurus' official docs. With this change my build times went from 117s to 82s (30% faster). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ref: facebook/docusaurus#4765
@societymartingale do you have an example for how this was done with docusarus? |
@johnnyreilly I've just literally found it minutes before you posted, tried and unfortunately for me, it doesn't seem to end up with faster builds... I'm building 3 different docs sites in one build, on a mac M3 pro.
To skip anything that isn't pure building. On top of that, I've also discovered that it's pretty important to exclude on macOs the build / project folders from spotlight if you don't want to spend most of the CPU time indexing them during the build... Summary:
Paper trailWithout
|
YOu can also get a decent performance improvement by not processing |
Tips on how to get this done? Are you referring to this |
I'm also curious to know what you mean, maybe you are right but my intuition is that it does not have a significant impact since in both cases content is going to be compiled to React components. Note, I'm actively working on perf optimizations for Docusaurus v3.2. There are no breaking changes in the 3.x branch yet so if you can run a canary version of Docusaurus and let me know how it improves, I'd be curious to know how faster it is on your site. The last remaining bottleneck remains the Webpack compilation time, I'll look into that soon. |
@damageboy, I added the following to package.json:
And added following to docusaurus.config.js:
As indicated above, I also disabled the last update author/time feature, as it wasn't scaling well. This saved another minute or two.
|
This major perf issue is fixed in canary (#9890) and will be released in v3.2 |
3.2 for us has seen a major improvement in build times (thanks @slorber !). Running on Github actions, 4 core 16gb linux runner, we have the following 3.1 build time - 35 mins 3.2 build time - 23 mins |
Why not ditch webpack for esbuild like vite? It's faster and better in every possible way. |
@Steveantor it's easier said than done. First of all, our plugin system has a I'm likely to adopt an incremental migration path thanks to unplugin, which is a more portable abstraction for bundler plugins that would probably be good enough for most Docusaurus plugins that only need a loader. Also, Vite is only using esbuild in some parts, and uses Rollup for bundling (v4 is based on SWC). And they are also working on Rolldown, a Rust port of Rollup. Due to how Docusaurus works, and our plugin system, it does not look like a good idea to use different bundling in dev/build modes. Afaik esbuild supports live reloading but has no official for hot reloading. We don't want to refresh the browser when you edit JS or MD, this would make your page lose its state. There's also Rspack which aims to be 100% retro-compatible with Webpack and according to this Bun benchmark, it's already quite faster than Webpack. https://bun.sh/blog/bun-bundler Vercel is also actively working on Turbopack, which also aims to be "mostly" compatible with Webpack, but less than Webpack. So Rspack is for me the most suitable candidate in the short term, due to the constraints we have, and until other solutions become more mature. I'm likely to introduce "future flags" in Docusaurus and let you swap Webpack with Rspack. It might not work for all third-party plugins (yet), but it should improve over time as Rspack fills the gap. Note that bundling is a major bottleneck (mostly for "cold builds" with an empty Webpack cache, less for rebuilds) but is not the only performance issue we have in Docusaurus. I fixed some in v3.2 but I have ideas to improve other parts as well. Notably, I'm not sure the high memory consumption is related to the bundling phase, but rather the SSG phase. |
FYI in v3.2 I added some site build perf logging (#9975). This is considered an internal API for now, but if you are curious to see what takes time on your site you can run your site with |
You can try running with |
I would love to use docusaurus with rspack, we had many legacy CRA projects and we successfully migrated all of them to rspack without much efforts. with rspack 1.0 around the corner, i am hoping this will be an option soon |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
FYI Docusaurus v3.6 is entirely focused on performance - see the Docusaurus Faster project The "faster" option is opt-in. It's a breaking change only if you turn it on, although most sites should be able to adopt it relatively easily. Activating this option should have a significant impact on build time and memory consumption. You can try a Docusaurus canary right now and let me know how fast it is. It is relatively stable and ready to release, I'm just polishing the last details and writing docs before tagging v3.6. |
Docusaurus v3.6 is out with the Docusaurus Faster options 🥳 🎉 |
💥 Proposal
With Webpack 5 support, re-build times are now faster.
But we still need to improve the time for the first build which is not so good currently.
Some tools to explore:
It will be hard to decouple Docusaurus totally from Webpack at this point.
But we should at least provide a way for users to use an alternative (non-Babel) JS loader that could be faster and good enough. Docusaurus core should be able to provide a few alternate loaders that would work by default using the theme classic, by just switching a config flag.
If successful and faster, we could make one of those alternate loader the default loader for new sites (when no custom babel config is found in the project).
Existing PR by @SamChou19815 for esbuild: #4532
The text was updated successfully, but these errors were encountered: