webpack-contrib / terser-webpack-plugin

Terser Plugin
MIT License
1.95k stars 157 forks source link

Minify modules instead of chunks #104

Closed filipesilva closed 4 years ago

filipesilva commented 5 years ago

Feature Proposal

terser-webpack-plugin operates on webpack chunks directly via the optimizeChunkAssets compilation hook. At this point individual chunks exist, each containing a collection of modules wrapped in the Webpack module loader. A single chunk can contain many modules.

Terser does not understand the indirection provided by the Webpack module loader and will end up optimizing each module individually. Providing a whole chunk to terser will yield the same optimizations as providing the individual modules contained in that chunk.

It's still important to optimize modules as late as possible because Webpack will concatenate modules. In fact, this concatenation is what enables most of the savings with Terser, since that allows Terser to analyse more code in a single module.

So a better place to execute terser would could be one of the hooks below, optimizing the individual modules:

I don't know which one is better. But all of them seem to provide modules and are around the time optimizeChunkAssets runs as well.

Feature Use Case

On large builds, individual chunks might be very large and require a lot of memory and CPU to process. In https://github.com/angular/angular-cli/issues/13734#issuecomment-500849058 I benchmark the peak memory usage of several projects and saw that the parallel terser processing can greatly contribute to it.

A concrete example is of a project that used around 1gb memory most of the , and when it spawned processes for terser it had to process several small chunks plus one or two large chunks. The small chunks used between 15 and 80mb memory, but the large chunks used up to 400mb and took much longer to process. By processing a large quantity or smaller modules, worker processes can use less host machine resources on average and spread the load more evenly.

filipesilva commented 4 years ago

@cjlarose yeah I didn't think the 2.3.3 changes would affect the problem this issue was opened to address. If I understood the changes in 2.3.3 correctly, they help reduce the terser-webpack-plugin overhead when organizing code to be ran by terser. But the "run terser once per chunk" strategy didn't change.

This part of what you said is not really obvious to me:

So if, during the lifetime of your program, at least 2400MB are allocated, peak memory usage will be around 2400MB.

I don't think that's accurate, IIRC there are also periodic GC. For instance, if you are running webpack builds on watch mode, you are continuously allocating new chunks of memory. But if you look at the memory usage of the process, it will be going up and down. So under that model, 2.3.3 should also bring some memory savings if there's a GC pass.

alexander-akait commented 4 years ago

I want to close this issue, but we potential can revisit it in future, main idea - uglify modules and whole files, we need support from terser comments like /* UGLIFIED */code, so terser will not compress already compressed files, it can potential reduce memory usage, but I am afraid it is not easy as sound, anyway if somebody have more ideas feel free to feedback