nx-plus icon indicating copy to clipboard operation
nx-plus copied to clipboard

Production build isn't tree shaking buildable libraries

Open gregveres opened this issue 3 years ago • 9 comments
trafficstars

Current Behavior

I have produced a reproduction repo. The repo contains one application and one library. In the library are two components: HelloWorld and GoodByeWorld. HelloWorld is used by app.vue but GoodByeWorld isn't used by anything in the application. As a result, I would have expected GoodByeWorld to be removed from the bundle by webpack's tree shaking.

The current behaviour is that the app.js created by the production build still contains GoodByeWorld.vue. Here is the image from Bundle Analyzer: image

And when I bring app.js into the editor and search for GoodByeWorld, I find:

...
,_=[],j=n["a"].extend({name:"GoodByeWorld"})
...

This indicates that GoodByeWorld is indeed in the bundle.

Expected Behavior

I expect GoodByeWorld to be removed from the bundle because it isn't referenced anywhere. I have been converting a fairly large project over to NX and when I was finished I realized that tree shaking wasn't happening and my bundles were much bigger and contained much different content than I had expected.

Steps to Reproduce

Here is a github reproduction: https://github.com/gregveres/nx-plus-vue-tree-shaking

clone this repo, and then run the production build with: nx build main --prod --mode="production"

This will launch bundle analyzer immediately. Just look at the app.js bundle (uncheck others).

Failure Logs

There are no failure logs

Environment

I am bulding a Vue 2 application

Plugin name and version: nx-plus/[email protected]

06-16 18:22:37 11> nx report

 >  NX   Report complete - copy this into the issue template

   Node : 16.13.2
   OS   : win32 x64
   npm  : 8.1.2
   
   nx : 14.3.6
   @nrwl/angular : Not Found
   @nrwl/cypress : 14.3.6
   @nrwl/detox : Not Found
   @nrwl/devkit : 14.3.6
   @nrwl/eslint-plugin-nx : 14.3.6
   @nrwl/express : Not Found
   @nrwl/jest : 14.3.6
   @nrwl/js : Not Found
   @nrwl/linter : 14.3.6
   @nrwl/nest : Not Found
   @nrwl/next : Not Found
   @nrwl/node : Not Found
   @nrwl/nx-cloud : Not Found
   @nrwl/nx-plugin : Not Found
   @nrwl/react : Not Found
   @nrwl/react-native : Not Found
   @nrwl/schematics : Not Found
   @nrwl/storybook : Not Found
   @nrwl/web : Not Found
   @nrwl/workspace : 14.3.6
   typescript : 4.7.3
   ---------------------------------------
   Community plugins:
         @nx-plus/vue: 14.0.0

gregveres avatar Jun 16 '22 22:06 gregveres

Is there a way to extract the configuration for webpack?

gregveres avatar Jun 16 '22 22:06 gregveres

I figured out what is missing. I had to add "sideEffects": false to all of my library's package.json files. Once I did that webpack started to work as expected. Here is the issue on the Nx main project site that pointed me in the right direction. Apparently this is a common issue. Webpack 5 is supposed to be better at doing the right thing automatically, but you can achieve it with webpack 4 with the use of the sideEffects: false entry.

I dropped over 200KB from my main app.js bundle size and 2MB from the total of my javascript files.

I am not sure if the plugin should be adding "sideEffects": false to the library's package.json file when it is created. I can see the argument that sideEffects: false might be promising something that might not be true for some libraries. But I always operate under the premiss that defaults should work for 90% of the use cases and I think that sideEffects: false definitely falls into that category.

gregveres avatar Jun 17 '22 13:06 gregveres

This can also be changed from a bug to a feature request.

gregveres avatar Jun 17 '22 13:06 gregveres

Unfortunately, I have figured out that every vue file that uses styles has a sideeffect and that is that the compiled JS file needs to be accompanied by the compiled .css file. Once I switched all my libs to sideEffects: false and did the production build, I realized that none of the component style files were being loaded.

I am still searching for the solution that allows me to have tree shaking (because it makes a huge difference) and loading of the component style files.

gregveres avatar Jun 17 '22 14:06 gregveres

I think I have found the proper solution as mentioned here..

For the libraries that contain vue files, I have changed sideEffects: false to sideEffects: ["*.vue"]. This tells webpack that vue files still have side effects and this causes webpack to properly include the .css files that correspond to the vue files.

I believe this new version of the sideEffect can be used for libs that don't have .vue files without problem. So, to amend my question above, should the libs have this sideEffect: ["*.vue"] by default?

gregveres avatar Jun 17 '22 15:06 gregveres

I've run into a very similar problem with nx + Angular in the past. Just to clarify, are you building the libs and then consuming them in your app or relying on Typescript aliases. From your repro it looks like the former, I'd be curious about tree-shaking when it comes to just relying on the aliases.

I think it makes sense to add the sideEffect to the generated packge.json for buildable libs if you're interested in contributing.

ZachJW34 avatar Jun 17 '22 17:06 ZachJW34

I am using buildable libs. I suspect that with non buildable line you would write the code to just reach into the lib directory and pull out the file you need. This would be more like not using no and I tree shaking would work automatically.

I will look at a PR.

I see you guys have added a vite plug-in. Are you moving to vue 3 and vite from vue 2 and webpack?

On Jun 17, 2022, at 1:29 PM, Zachary Williams @.***> wrote:

 I've run into a very similar problem with nx + Angular in the past. Just to clarify, are you building the libs and then consuming them in your app or relying on Typescript aliases. From your repro it looks like the former, I'd be curious about tree-shaking when it comes to just relying on the aliases.

I think it makes sense to add the sideEffect to the generated packge.json for buildable libs if you're interested in contributing.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.

gregveres avatar Jun 17 '22 17:06 gregveres

@gregveres as long as vue-cli is popular I plan on supporting it. I added the vite plugin cause it was fun to do

ZachJW34 avatar Jun 25 '22 22:06 ZachJW34

I have the same problem

hackmajoris avatar Nov 04 '22 09:11 hackmajoris