polished icon indicating copy to clipboard operation
polished copied to clipboard

Tree shaking

Open sayjeyhi opened this issue 5 years ago • 21 comments

Hi there,

I was analyzing my packages and figure out that all of polished function did imported and impact my bundle size. I just used darken and lighten functions. here is bundlephobia which tell all single function has same size as all package : https://bundlephobia.com/[email protected] see Exports Analysis part

sayjeyhi avatar Feb 29 '20 07:02 sayjeyhi

@sayjeyhi polished is fully tree-shakeable and has been for a couple years now. FWIW I don't think Bundlephobia is evidence that something isn't properly tree-shakeable. Here is another example where it is incorrect with styled-components: https://bundlephobia.com/[email protected].

We will need more information about your setup to provide any help on why it isn't working in your particular instance:

  • Version of polished you are using.
  • Example of how you are using/importing the functions.
  • Which bundler and version you are using.
  • Config for said bundler.

Our docs also link to how to set this up in webpack and rollup: https://github.com/styled-components/polished#usage

bhough avatar Mar 01 '20 13:03 bhough

so you say this is just for lighten and darken functions : Screen Shot 1398-12-14 at 11 29 37 PM

I am using webpack 4.41.2 , and I did import polished in es module way(import {foo} from 'bar') and my polished version is 3.4.2

sayjeyhi avatar Mar 04 '20 20:03 sayjeyhi

Screen Shot 1398-12-15 at 10 14 21 AM

I import lighten by adding full path and bundle size gets better result.

import lighten from 'polished/lib/color/lighten';

sayjeyhi avatar Mar 05 '20 06:03 sayjeyhi

@bhough I'm aware of sub-module imports. But we can't really classify that as a solution can we? Tree shaking is designed to work on re-exported modules at the root level. There has to be a reason for it to break only on this library.

avin-kavish avatar Apr 19 '20 16:04 avin-kavish

@avin-kavish This is still an open issue @sayjeyhi is just suggesting an interim solution. We've been unable to recreate this yet. If you'd like to provide the info we asked the OP for, we can continue to dig into it.

One thing that usually catches people is they are running their bundle analyzer on a development build vs the production bundle. In development, you will see the entire library. When you use the method described above, you will see just this file imported into the development build directly, which is not the same thing as the tree-shaking going on in the production build.

bhough avatar Apr 19 '20 16:04 bhough

@bhough maybe I could work around it this weekend and come with a PR...

sayjeyhi avatar Apr 19 '20 21:04 sayjeyhi

@sayjeyhi All we really need is a link to a repo we can fork that shows where it isn't tree-shaking and can take it from there.

bhough avatar Apr 19 '20 21:04 bhough

image

@sayjeyhi the screenshot is lighten and darken using a basic CRA app out of the box. The first difference I see is your build is pulling from lib where mine is pulling from dist, so that is likely a good place for us to start.

bhough avatar Apr 19 '20 22:04 bhough

Yeah, it works with minimal code, trouble happens when there's a complex tree of dependencies.

polished
|-grommet (another npm package)
   |-Layout A
   |  |-Page A
   |-Layout B
      |-Page B

So I created a tree like this in Next.js (which is where I am having the trouble) but I can't get an accurate size because of module concatenation. I will keep experimenting...

Edit: With module concat turned off, it's only adding 2.5kB so no go once again.

avin-kavish avatar Apr 20 '20 06:04 avin-kavish

Edit: With module concat turned off, it's only adding 2.5kB so no go once again.

Not sure what you mean by 'no go once again'? The fact that it is only adding 2.5kB should mean it is working correctly. Keep in mind color modules are relatively heavy given their dependencies.

bhough avatar Apr 20 '20 11:04 bhough

I was trying to create a reproduction of the issue in a code base separate from the one I'm having the issue in. I can't share the original as it is not open source. What I mean is that the issue is likely due to some weird interaction between dependencies etc in much larger/complex code.

avin-kavish avatar Apr 20 '20 12:04 avin-kavish

K @avin-kavish We will keep this up for the time being to see if we can get a recreation. Only issue we've seen is folks pulling in the non-es-module version from the main field and thus not getting tree-shaking. We are going to do a bit of work to make that less impactful when it happens.

bhough avatar Apr 20 '20 13:04 bhough

I see. I don't think that's happened in my case based on the screenshot below. It seems that polished.es.js is imported. Maybe the following info could be helpful?

yarn why polished

=> Found "[email protected]"
info Reasons this module exists
   - "grommet" depends on it
   - Hoisted from "grommet#polished"
info Disk size without dependencies: "3.49MB"
info Disk size with unique dependencies: "4.17MB"
info Disk size with transitive dependencies: "4.21MB"
info Number of shared dependencies: 2

Bundle Analyzer

Full Bundle with Polished: 432kb. Full Bundle without Polished: 422kb.

How did I remove only polished if my project depends on grommet, a 3rd party library which depends on polished?

I created my own fork of grommet and removed all references to polished. Luckily, on the rgba function was imported 3 times in the whole project. No other functions were imported. Their use case was trivial enough to replace with strings. In one situation, I broke a certain component, but since I don't use that component in my project, it's no issue for me.

avin-kavish avatar Apr 20 '20 17:04 avin-kavish

@avin-kavish That's good context. The fact that it is being pulled in from another dep could be significant. Could be something grommet is doing in their implementation that keeps it from being tree-shaken. Will explore this further.

bhough avatar Apr 20 '20 17:04 bhough

Could it be this?

exports.__esModule = true;

var _components = require("./components");

Object.keys(_components).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  exports[key] = _components[key];
});

Their exports seems to be dynamically defined.

avin-kavish avatar Apr 22 '20 10:04 avin-kavish

I'm running into this issue as well, import { darken, lighten } from 'polished'; is causing the whole package to be bundled with a basic webpack config. I'm on version 3.6.6.

twdrake-ap avatar Sep 09 '20 21:09 twdrake-ap

☝️ same issue as @twdrake-ap. On a basic Gatsby project, using import { transparentize } from 'polished, I get 100 modules concatenated together with the main package module.

langri-sha avatar Dec 11 '20 04:12 langri-sha

Same issue. 🤔 If using direct import with full path works fine.

Simple workaround. before: Снимок экрана 2021-02-25 в 18 52 56

after: Снимок экрана 2021-02-25 в 18 51 34

Armanio avatar Feb 25 '21 16:02 Armanio

Wild shot in the dark: Everyone in this thread is including source maps it some way

With devtool: 'source-map'

CleanShot 2021-10-11 at 13 54 21

With devtool: false

CleanShot 2021-10-11 at 13 54 02

hipstersmoothie avatar Oct 11 '21 20:10 hipstersmoothie

@hipstersmoothie disabling source-maps is a no go for me because they're needed for debugging errors in production

sbdchd avatar Jan 01 '22 01:01 sbdchd

export default in every module is causing this issue when you import some function with import { fn } from "polished";. Avoiding of using default exports will solve this issue.

Profesor08 avatar Mar 28 '22 09:03 Profesor08