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

Large size difference between v5 and v6 in webpack output #3765

Closed
WhitWaldo opened this issue May 31, 2018 · 17 comments

Comments

@WhitWaldo
Copy link

commented May 31, 2018

RxJS version:
6.2.0

Code to reproduce:
Can't provide

Expected behavior:
Expect the output file size to be the same size as v5 or smaller.

Actual behavior:
Output rxjs is about 4x larger

Additional information:
I have a TypeScript project that I build with webpack, emitting ES5 ultimately, and performs ES6 tree shaking via Babel. It currently uses v5 of RXJS, utilizing AsyncSubject, Observable, ReplaySubject, BehaviorSubject and several operators like bufferTime, filter, and others.

When looking at the output from the webpack-bundle-analyzer, below, I see that the parsed size of my output is 27.13 KB. I updated my project to utilize rxjs6 without using the compatibility library and re-built it with the same build pipeline. This time I got an output size of 116.43 KB, which is more than 4x larger. This primarily looks like it's because of whatever is in this _esm5 directory, but this alone preempts my adoption of v6.

What can be done to shrink this directory (or better, eliminate it so I can achieve sizes as small as what I got with v5)?

Thanks!

rxjs5
rxjsv5

rxjs6
rxjsv6

@kwonoj

This comment has been minimized.

Copy link
Member

commented May 31, 2018

This seemingly looks like related with configuration / how to import modules around, but we can't figure out without reproducible code (or config and other environment surroundings). Curious if you already applied all suggestions at https://github.com/ReactiveX/rxjs/blob/d231053616ab4e5d2541818314110df626e6bf5a/doc/pipeable-operators.md#build-and-treeshaking .

@WhitWaldo

This comment has been minimized.

Copy link
Author

commented May 31, 2018

@kwonoj I didn't see that document originally when I was reading through the documentation. I'll work through the suggestions there and get back to you.

@jcampalo

This comment has been minimized.

Copy link

commented Jul 9, 2018

@kwonoj I checked your solutions but none of them seems to work as I expected, bundle size keeps almost the same. I don't know why Rxjs 6 drops the support for something like:

import { switchMap } from 'rxjs/operators/switchMap';

This solution is flexible and adds control over your dependencies.

Even if use rxjs-compat package to allow me to do that, the bundle size almost equal in size.

@DougWoodCDS

This comment has been minimized.

Copy link

commented Jul 28, 2018

agreed , seeing same issues. this is thie biggest bundle size in my vendor chunk.
All I am using is these

import { mergeMap, delay, map, catchError } from 'rxjs/operators';
import { of, concat } from 'rxjs';
import {
  ActionsObservable,
  StateObservable,
  ofType,
  combineEpics,
} from 'redux-observable';

"redux-observable": "1.0.0",
"rxjs": "6.2.2",

and i have a bundle size of 167 KB parsed size, from rxjs lib alone. every operator is in the bundle

@ghost

This comment has been minimized.

Copy link

commented Jul 30, 2018

Using version 6.2.2 and seeing the same issue myself. I've tried following the documentation on tree shaking as linked to above but it has made no difference.

When seen through bundle analyzer, I also see every single operator included in the bundle when only importing a single operator from 'rxjs/operators' and nothing else, as a trivial test case.

Example code:

index.js

import {filter} from 'rxjs/operators';

webpack.config.js

const config = {
    entry:  './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, '../../dist')
    },
    mode: 'production',
    resolve: {
        alias: rxPaths()
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader'
            }
        ]
    },
    plugins: [
        new webpack.optimize.ModuleConcatenationPlugin()
    ]
};

Bundle analyzer visualisation looks exactly like the OP's screenshot. Adding the rxPaths() alias, ModuleConcatenationPlugin() seems to make no different to what's included or the bundle size.

@kwonoj

This comment has been minimized.

Copy link
Member

commented Jul 30, 2018

@patrickkunkadazn I tried your snippet and created https://github.com/kwonoj/rxjs-webpack-test , npm run build do wepback and output is
image

image

8kb in total. Rxjs is 6.2.2, as same as you mentioned: https://github.com/kwonoj/rxjs-webpack-test/blob/master/package.json#L15

@ghost

This comment has been minimized.

Copy link

commented Jul 30, 2018

Hmm interesting my output is 292kb / 99kb minified. Thanks for creating the repo - I will scan for differences now.

@kwonoj

This comment has been minimized.

Copy link
Member

commented Jul 30, 2018

@patrickkunkadazn worth to share your repo as well, so anyone can try and dig differences.

@ghost

This comment has been minimized.

Copy link

commented Jul 30, 2018

So it looks like this is caused by the presence of the babel-preset-env package:

https://github.com/patrickkunkadazn/rxjs-webpack-test

I've added the package, and also a .babelrc file. Now the entirety of RxJS 6 is included when built. Perhaps this is the expected behaviour, but it would be good to understand why.

@ghost

This comment has been minimized.

Copy link

commented Aug 2, 2018

@kwonoj would you like me to open a separate issue for this?

@ghost

This comment has been minimized.

Copy link

commented Aug 9, 2018

I had a look through every babel plugin that was being included with preset-env that could be breaking treeshaking, and eventually narrowed it down to this one:

https://www.npmjs.com/package/babel-plugin-transform-es2015-modules-commonjs

Without this plugin present, tree shaking works, but with it present, we end up including the whole library.

@kwonoj

This comment has been minimized.

Copy link
Member

commented Aug 9, 2018

I think that's expected, if import syntax is transpiled into cjs require, there's no way to make tree shaking work.

@ghost

This comment has been minimized.

Copy link

commented Aug 9, 2018

OK - I assumed as much. Considering using babel-preset-env is part of the standard workflow of someone writing in modern javascript and transpiling to ES5 or similar for production, should this be flagged in the documentation somewhere?

From what I understand, and from my testing, we can simply remove this plugin from preset-env, and

  1. tree-shaking will then work
  2. Webpack is still able to parse ESM import statements and convert to an ES5-compatible bundle anyway

I'm assuming this is the root cause of the issues described by the other commenters in this issue, so probably worth flagging?

@kwonoj

This comment has been minimized.

Copy link
Member

commented Aug 9, 2018

If all others in this issue experiences same due to config, I think it's worth to write up document. Probably need confirmation.

@ghost

This comment has been minimized.

Copy link

commented Aug 9, 2018

Cool, in the mean time – here's the fix:

.babelrc

{
    "presets": [
        ["env", {
            "modules": false
        }]
    ]
}

In TypeScript, the equivalent would be to set compilerOptions.module to 'esnext', so that webpack can see the import statements.

@kwonoj

This comment has been minimized.

Copy link
Member

commented Sep 25, 2018

I'm going to close this as it's answered for some aspect and do not have additional cases other then configuration issue. We may update documentation for precaution later.

@kwonoj kwonoj closed this Sep 25, 2018

@wldcordeiro

This comment has been minimized.

Copy link

commented Sep 30, 2018

I've been running into this issue and the suggestions above with setting modules: false in Babel configs don't seem to work in the Babel 7.x world.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 30, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
5 participants
You can’t perform that action at this time.