Skip to content
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

Webpack bundle.js size #874

Open
Jucesr opened this issue Dec 1, 2017 · 19 comments
Open

Webpack bundle.js size #874

Jucesr opened this issue Dec 1, 2017 · 19 comments
Labels

Comments

@Jucesr
Copy link

Jucesr commented Dec 1, 2017

I am using react-dates in my app. I am trying to reduce the size of my bundle.js generated by webpack. I used the "webpack-bundle-analyzer" and I noticed React-dates module is including components I am not using in my app.

I only imported SingleDatePicker and RangeDatePicker but I am getting all the components in bundle. I tried to use the webpack.IgnorePlugin but I was not able to get this done.

To import I used
import { SingleDatePicker } from 'react-dates';

@majapw
Copy link
Collaborator

majapw commented Dec 1, 2017 via email

@ljharb ljharb added the question label Dec 1, 2017
@Jucesr
Copy link
Author

Jucesr commented Dec 1, 2017

Hi @majapw I tried but still it's kind of big. It's around 350kb. My bundle has other files such as DarPicker.js, CalendarMonth.js . I think they are used by SingleDataPicker that is why webpack is adding them.

Correct me if I am wrong please.

@ljharb
Copy link
Member

ljharb commented Dec 1, 2017

Perhaps this is the only thing adding moment? Moment can be large in webpack because i believe it grabs up all locales by default.

@majapw
Copy link
Collaborator

majapw commented Dec 1, 2017

SingleDatePicker does use a number of other components under the hood... it's a fairly complex component. moment is also quite a big package.

@lencioni might have some more thoughts on optimization.

@lencioni
Copy link
Contributor

lencioni commented Dec 1, 2017

Indeed, Moment can easily blow up your bundle size, especially if you aren't being really careful about what it brings in. I think they have a plan to make it easier to do the right thing, but I'm not sure if it has landed yet.

In #791 we added an /esm build that you will want to hook up via a webpack alias, if you are on a new enough version of webpack (2+ IIRC). https://webpack.js.org/configuration/resolve/#resolve-alias That should give you smaller modules for react-dates and allow tree shaking to actually work for the react-dates code.

Beyond that, I think it would be impactful to have a way to be able to code split parts of react-dates, so you only bring in the parts that are needed for the initial render for your parent bundle, and then async load the rest as needed. I opened an issue for this here: #839 However, I am expecting a baby at any moment so it is unlikely that I'll be able to do any work on that any time soon. If you are looking for a way to contribute and help solve this problem for everyone, that would be a great issue to dig into.

@jeznag
Copy link

jeznag commented Dec 18, 2017

@lencioni could you provide more details on how to use /esm with webpack alias?

@lencioni
Copy link
Contributor

lencioni commented Jan 26, 2018

@jeznag I think you would need to add something like this to your webpack's resolve.alias configuration:

'react-dates/lib': 'react-dates/esm',

More info: https://webpack.js.org/configuration/resolve/#resolve-alias

@jorgecuesta
Copy link

Hi @lencioni I do what you suggest about alias and get same result about big size on bundle on react-moment-proptypes. I try using both lib and esm for import DayPickerSingleDateController from 'react-dates/lib/components/DayPickerSingleDateController'; and get same size result.
Something else I can try to reduce the biggest size?

@jbfm
Copy link

jbfm commented Jan 31, 2018

@jorgecuesta I've worked around your exact issue. The problem is react-moment-proptypes depends on an old version of moment, so in your bundle you'll get both the peer dependecy from react-dates, which you've installed, and the old version from react-moment-proptypes, giving you an insane bundle size.

I solved this by simply aliasing moment in my webpack config to the later version. This could cause issues with react-moment-proptype, but I haven't noticed anything yet, been running it in production for a few weeks.

So something like this would probably help you

resolve: {
	alias: {
		moment: path.resolve(__dirname, 'node_modules/moment')
	},
},

@majapw
Copy link
Collaborator

majapw commented Jan 31, 2018

Hmm, react-moment-proptypes has moment as both a peer dep and a direct dep (and it's acceptable range is open, it's like >=1.6.0) so whatever you provide should satisfy both react-dates and react-moment-proptypes's requirements. I wonder if there's something weird in the deduping process. @ljharb

@ljharb
Copy link
Member

ljharb commented Feb 1, 2018

I'd try running npm dedupe and see if that resolves your issues.

@jbfm
Copy link

jbfm commented Feb 1, 2018

Alright, @ljharb @majapw, I checked out an old commit and dug into what caused my issue a bit more. At the time I had this issue I had moment installed as ~2.18.0 due to some other dependency, this seems to cause an issue with Yarn since react-dates now had an unmet peer dependency, and in turn making it think react-moment-proptypes had an unmet depenecy as well, not really sure why it goes that way, using NPM instead of Yarn didn't give this issue.

warning " > react-dates@16.0.1" has unmet peer dependency "moment@^2.18.1".
warning "react-dates > react-moment-proptypes@1.5.0" has unmet peer dependency "moment@>=1.6.0".

And from there Yarn installed a duplicate moment within react-moment-proptypes

Not sure if this helps @jorgecuesta... :)

@jorgecuesta
Copy link

Thanks guys @majapw @ljharb and @jbfm to take time to see this.
I have this dependencies: "react-dates": "16.2.1"
and finding moment get this result:

├─ moment@2.11.1
├─ react-moment-proptypes@1.5.0
│  └─ moment@2.20.1

I use Yarn all the time, maybe I need install same moment version that used by moment-prop-types

I will try using npm instead and check updating version. I will let you know if something of that reduce bundle size in relation to react-dates

@jeznag
Copy link

jeznag commented Feb 4, 2018

Thanks for the tip. Using the alias seems to save 2kb gzipped. Hopefully further size savings will be available down the line. Particularly keen to reduce size of moment.

@pedroabreu
Copy link
Contributor

Running into the same issue while just importing the util toMomentObject.

Importing it like import { toMomentObject } from "react-dates" I get the following in the bundle-analyzer

screen shot 2018-05-23 at 22 50 40

I'm now looking at another app, where I use the DatePickerRangeController and I also suspect it's bundling the entire react-dates. I would expect that not to be the case on a single component import, not at least for the entire package (a big chunk of it perhaps).

I will try the suggested deep importing

@mjmonline
Copy link

for moment optimizations try this plugin to strip redundant locales https://github.com/iamakulov/moment-locales-webpack-plugin

@Marvin1003
Copy link

@mjmonline you can pretty much achieve the same using webpacks Context Replacement Plugin

plugins: [
  new webpack.ContextReplacementPlugin(
    /moment[\/\\]locale$/,
    /de|fr|hu/
  )
]

https://webpack.js.org/plugins/context-replacement-plugin/

@jondavidjohn
Copy link

I built a tool to help you analyze webpack bundles for size regressions, and report them directly to GitHub PRs. It's free for open source, so it might be worth checking out and helpful in this scenario.

https://packtracker.io

image

@thibaudcolas
Copy link

I think another optimisation that would greatly reduce the bundle size for Webpack users is to use the sideEffects flag in the package.json to mark which files contain side effects.

At the moment, without it being set, even when using react-dates/esm, Webpack will bundle the whole library instead of just the selected imports. The workaround for this is to import components directly from the file where they are defined as #874 (comment) suggests, but is dependent on implementation details which are prone to breakage.

Additionally I think it would also make sense to declare the module field in package.json pointing at ./esm/index.js, since as far as I can see it’s indeed compiled with the same Babel config as the CJS build except for modules: false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests