aurelia / webpack-plugin

A plugin for webpack that enables bundling Aurelia applications.
MIT License
90 stars 36 forks source link

Aurelia causes full bailout from Webpack’s ModuleConcatenationPlugin #153

Closed rluba closed 6 years ago

rluba commented 6 years ago

I'm submitting a feature request

Please tell us about your environment:

Current behavior:

Using Webpack adds a huge overhead both in terms of bundle size and startup size to every application. Webpack 3 and 4 introduced ModuleConcatenationPlugin to mitigate most of this overhead.

But trying to use ModuleConcatenationPlugin with Aurelia has no effect because Aurelia’s way of bootstrapping the app and loading its dependencies causes ModuleConcatenationPlugin to bail out for every single file. (See Debugging Optimization Bailouts on how to see the bailout reasons for each file.)

Expected/desired behavior:

It would be great if Aurelia would retain at least some support for using ModuleConcatenationPlugin, especially since it encourages having lots of small modules – which magnifies the overhead created by Webpack.

I haven’t investigated Aurelias internal bootstrapping mechanisms enough to know how to achieve this, but I’d be willing to offer my help.

jods4 commented 6 years ago

This is inaccurate.

The bail out of ModuleConcatenationPlugin is by design for modules meant to be loaded by aurelia-loader, i.e. those found by PLATFORM.moduleName and friends. It's on purpose because otherwise Aurelia won't work.

Hoisting is possible for all other modules.

rluba commented 6 years ago

@jods4 You might be right, but I wouldn’t know how. Can you show me any example of Aurelia where using ModuleConcatenationPlugin results in an even marginally smaller bundle?

I can see that ModuleConcatenationPlugin bails out of every single file in my Aurelia application because every module can be traced down to the bootstrapping in main.js:

aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app')));

(…or another reference using PLATFORM.moduleName(…)).

Since the root of the application requires using PLATFORM.moduleName(…), every single file that’s used within the application bails from optimization because its usage is (either directly or indirectly) traced back to an unsupported reference.

ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./src/main.js (referenced with aurelia module)
rluba commented 6 years ago

It's on purpose because otherwise Aurelia won't work.

I know. But the question is: How could this be improved so that Aurelia is less toxic to optimization.

jods4 commented 6 years ago

Do you use includeAll: "src" or similar? It would do that.

Otherwise, regular ES imports are hoisted when it is possible and benefits the app. If you need proof: image

How could this be improved so that Aurelia is less toxic to optimization.

It is a fundamental change in the design of Aurelia. It means not using strings anymore, not relying on modules shapes, using import exclusively...

@bigopon has done some work in this area recently to create alternative API that are more tooling friendly, but you need to change your code to take advantage of them.

Plans for the next major version of Aurelia are to fully go this way. It will take some time though, don't hold your breath.

Final note: it's not nearly as bad as you're making it to be. Don't expect properly minimized builds to suddenly get 20% smaller because Aurelia modules are hoisted. The link you provided compares thousands of tiny modules. So yes if you just export trimLeft the overhead of webpack is significant. When using more realists ViewModels it's not that big.

rluba commented 6 years ago

@jods4 Thank you for the reply.

No, I don’t use includeAll. I manually import all dependencies and use PLATFORM.moduleName(…) where needed.

But your screenshot helped me find my problem! I tried running Webpack with and without adding new webpack.optimize.ModuleConcatenationPlugin() to the plugins – there was zero difference. But when I saw your screenshot, I remembered similar lines in my build. Some googling revealed that ModuleConcatenationPlugin is enabled by default in production in Webpack 4! That’s why I saw no difference – manually adding new webpack.optimize.ModuleConcatenationPlugin() is a no-op in production. Thank you.

@bigopon has done some work in this area recently to create alternative API that are more tooling friendly, but you need to change your code to take advantage of them.

That’s great to hear. I’m looking forward to it. @bigopon Let me know if I can be of help.

Don't expect properly minimized builds to suddenly get 20% smaller because Aurelia modules are hoisted.

I didn’t expect that. But we recently switched a (non-aurelia) project to Webpack and saw around 10% increase in minified bundle size – both non-gzipped and gzipped! So the overhead is large enough to be significant. (We couldn’t use ModuleConcatenationPlugin for that project because it doesn't use ES6 modules.)

jods4 commented 6 years ago

Out of curiosity, what were you bundling with before Webpack? 10% is significant and Webpack 4 builds -- for production -- are rather optimized.

I don't know what this project was made with, but you can use import in otherwise lower targets (ES5) and bundle it with Webpack (which removes all imports). This gives you access to many import optimizations (beyond hoisting) while still targeting old browsers. For example with Typescript this is easy to do as the target language and module system are two distinct options.

rluba commented 6 years ago

It was an ES5 project using AngularJS and a custom build process. Before we switched to Webpack it mostly relied on AngularJS’s builtin module system so the files were simply concatenated (with some pre-processing and template compilation) and then optimized.

I know that it’s possible to use import but it was a rather large codebase of many small files that we just retrofitted with Webpack to get rid of Bower. Rewriting everything to fit ES6 modules was not an option. Since there’s nothing for Webpack to optimize (apart from what the old build system already did, too), we were just left with Webpack’s overhead.

bigopon commented 6 years ago

@rluba Will do 👍