angular: UMD bundle cannot be used for RxJS

I’m submitting a … (check one with “x”)

[x] bug report
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior I updated system-config.ts file to download umd file for rxjs I.e rxjs\bundles\Rx.umd.js. This worked. But I still see in dev tools a lot of individual JS being load like rxjs\observer.js

Expected/desired behavior When using UMD for rxjs it should not download individual files

Reproduction of the problem See this plunker when you riun in full screen mode observe the files being loaded in dev tools. http://plnkr.co/edit/TvjW2YK3NVJ7sDb7cHV4?p=preview

No community response on question: http://stackoverflow.com/questions/37881825/using-rxjs-umd-bundles

What is the expected behavior? When using UMD for rxjs it should not download individual files

What is the motivation / use case for changing the behavior? To reduce load request when angular app starting up

Please tell us about your environment:

  • Angular version: 2.0.0-rc.2
  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ] Tested only on chrome
  • Language: [all | TypeScript X.X | ES6/7 | ES5 | Dart] Tested with Typescript only

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 33
  • Comments: 111 (29 by maintainers)

Most upvoted comments

To fix this issue we need to generate Rx SystemJS bundle by ourselfs

const Builder = require("systemjs-builder");
// SystemJS build options.
var options = {
    normalize: true,
    runtime: false,
    sourceMaps: true,
    sourceMapContents: true,
    minify: false,
    mangle: false
};
var builder = new Builder('./');
builder.config({
    paths: {
        "n:*": "node_modules/*",
        "rxjs/*": "node_modules/rxjs/*.js",
    },
    map: {
        "rxjs": "n:rxjs",
    },
    packages: {
        "rxjs": {main: "Rx.js", defaultExtension: "js"},
    }
});

builder.bundle('rxjs', 'node_modules/.tmp/Rx.js', options),

This will generate bundle ready to consume by SystemJS.

Inject <script src="node_modules/.tmp/Rx.js"></script> to html

So, any rxjs/* import statements (e.g import rxjs/Observable) will not cause 50+ requests by SystemJS.

**Important**! In your `systemjs.config` should be nothing related to `rxjs`, if it will
For example:
```js
map = {
     "rxjs": "n:rxjs",
};
```
It will cause again 50+ requests...

After reading a lot of discussion, I’ve finally got a workable perfect solution, first use systemjs-builder to build a rxjs systemjs bundle:

    const Builder = require("systemjs-builder");
    var builder = new Builder('./');
    builder.config({
        paths: {"rxjs/*": "node_modules/rxjs/*.js"},
        map: {"rxjs": "node_modules/rxjs"},
        packages: { "rxjs": {main: 'Rx.js', defaultExtension: "js"} }
    });

    builder.bundle('rxjs', 'your-own-path/Rx.min.js', {
        sourceMaps: true,
        minify: true,
        mangle: true
    });

then in your system.config.js file remove everything related to rxjs, and then add a bundle like this

        bundles: {
            "your-own-path/Rx.min.js": [
                "rxjs/*",
                "rxjs/operator/*",
                "rxjs/observable/*",
                "rxjs/add/operator/*",
                "rxjs/add/observable/*",
                "rxjs/util/*"
            ]
        }

then no additional work to do and no need to include Rx.min.js to script tag in html, systemjs will automatically only load the Rx.min.js.

after this, my simpe app’s requests reduce from over 500 to only 86( over half of these are images and other scripts and css files). and the final Rx.min.js is only 258Kb.

this is close to a perfect solution so far. and thanks to @unlight and @damiandennis.

+1. I had the same issue

Best is switch to webpack

On Monday, 5 September 2016, karlhaas notifications@github.com wrote:

@bahodirk https://github.com/bahodirk I’m using the solution of @damiandennis https://github.com/damiandennis . We had to change imports from ‘rxjs’ to ‘rxjs/Rx’ in our project.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/angular/angular/issues/9359#issuecomment-244744673, or mute the thread https://github.com/notifications/unsubscribe-auth/AJ6mG8ykN0MQrPmZFtePaAFrjvny1KXOks5qnBaNgaJpZM4I5Yvv .

Cheers!

Before RC.6 I was using rxjs/bundles/rx.min.js in index.html to load 1 single file. With RC6 upgrade I do not see it any more. I just see rx.umd.js. If i use that I get bunch of 404 error. Even though i have suppressed rxjs in systemjs, it still attempts to load. It was working for me in .rc5

bundling rxjs myself using systemjs-builder mostly fixed my issue. still get ~ 40 request though not really sure why. Here is how I bundled using gulp and systemjs-builder

gulp.task('ng-bundle-rxjs', function(done) {

    var builder = new Builder('./', './systemjs.config.js');
    builder
        .bundle([
            'node_modules/rxjs/add/**/*.js',
            'node_modules/rxjs/observable/**/*.js',
            'node_modules/rxjs/operator/**/*.js',
            'node_modules/rxjs/scheduler/**/*.js',
            'node_modules/rxjs/symbol/**/*.js',
            'node_modules/rxjs/util/**/*.js',
            'node_modules/rxjs/*.js'
        ], 'bundles/rxjs.min.js', {
            minify: true,
            sourceMaps: true,
            mangle: false
        })
        .then(function() {
            console.log('Build complete');
            done();
        })
        .catch(function(err) {
            console.log('Build error');
            console.log(err);
            done();
        });
});

and in systemjs.config.js

bundles: [
    "bundles/rxjs.min.js": ["rxjs/*"]
]

@damiandennis I can confirm that new Router v3.0.0-rc.1 breaks the path solution

"rxjs/*": "node_modules/rxjs/bundles/Rx.umd.min.js"

I get: TypeError: Cannot read property 'apply' of undefined

As a workaround, I use rxjs SystemJS bundle in a script tag. It seems to work. No individual rxjs files are loaded. Are there any disadvantages with this approach (as workaround until umd can be used)?

You should use individual operators import (deep import). This will reduce the requests to 70-80 ( depending upon how heavily you use RxJS) from 275 by bundle like import

One solution I came up with is that loading Rx.umd.js through script tag and removing all the entries related to RxJS from system-config. This could resolve your issue.

please guys, this doesn’t make any sense on a production build, you’ll always use a bundler to build all scripts with aot, and trust me, I’ve spent 4 days to try to figure out how to use webpack and systemjs together, and still there are some problems, and after turning to @angular/cli, it only takes me about 15mins to make a aot bundles.

and with angular 4.0, it seems systemjs way won’t work any more, I’ve tried with some different settings, and none of those works, and that take me a whole day, and with @angular/cli, it’s really about just few keystrokes, then everything is done, dev build with sourcemap and watch, and production build with aot, everything works like a charm.

please guys, don’t waste any more time on this, unless of course, you must stick to angular 2 version forever.

angular/cli is FAR MORE easier than this systemjs way.

Now in my setup, I use angular/cli to pack everything, and with systemjs to load any scripts dynamically, or just leave this work to angular/cli to pack a whole bunch of 3rd-party jquery plugins.

after move to angular/cli, my system.config.js only contains these

    SystemJS.config({
        // map tells the System loader where to look for things
        map: {
            jquery: 'assets/global/plugins/jquery.min.js'
        }
    });

@steve3d Fine, the only question is why the original Rx.min.js does not work by the same way.

I don’t think it is worth to use the umd bundle anyway. It seems Rxjs folks have broken down the components into smaller pieces, then you need to explicitly reference what you want to use. This have reduced the amount of files being downloaded a lot from previous versions.

At my company I switched to a different approach, where I copy all the .js files from the npm folder into a vendor folder using a gulp task:

const source = './node_modules/rxjs/**/*.js'; const dest = './wwwroot/vendor/rxjs'; module.exports.dep = function (gulp, plugins) { return function () { return plugins.del(dest); }; }; module.exports.task = function (gulp, plugins) { return function () { return gulp.src(source) .pipe(gulp.dest(dest)); }; };

And then map it using system.js.config: var map = { ... 'rxjs': './vendor/rxjs' ... }

At first I didn’t like the solution, but later it proved to be acceptable.

@jeshcalls: SystemJS is dead. Angular moved away from it long ago to webpack and angular-cli now

@jeshcalls … for re-bundled RxJS 5.5.x you should have the following if your systemjs.config.js, where assets/rxjs-bundle/Rx.min.js is the re-budled RxJS file:

bundles: {
        ...,
	"assets/rxjs-bundle/Rx.min.js": [
		"rxjs/*",
		"rxjs/operator/*",
		"rxjs/operators/*",
		"rxjs/observable/*",
		"rxjs/add/operator/*",
		"rxjs/operators/*",
		"rxjs/add/observable/*",
		"rxjs/scheduler/*",
		"rxjs/symbol/*",
		"rxjs/util/*"
	],
        ...
}

this is my system.config.js, works very well:

'use strict';

(function (global) {
    System.config({
        "defaultJSExtensions": true,
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'scripts',
            modules: 'scripts/modules',
            // angular bundles
            '@angular/core': 'assets/global/plugins/@angular/core/bundles/core.umd.min.js',
            '@angular/common': 'assets/global/plugins/@angular/common/bundles/common.umd.min.js',
            '@angular/compiler': 'assets/global/plugins/@angular/compiler/bundles/compiler.umd.min.js',
            '@angular/platform-browser': 'assets/global/plugins/@angular/platform-browser/bundles/platform-browser.umd.min.js',
            '@angular/platform-browser-dynamic': 'assets/global/plugins/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.min.js',
            '@angular/http': 'assets/global/plugins/@angular/http/bundles/http.umd.min.js',
            '@angular/router': 'assets/global/plugins/@angular/router/bundles/router.umd.min.js',
            '@angular/forms': 'assets/global/plugins/@angular/forms/bundles/forms.umd.min.js',
            'moment': "assets/global/plugins/moment.min.js"
        },
        bundles: {
            "assets/global/plugins/Rx.min.js": [
                "rxjs/*",
                "rxjs/operator/*",
                "rxjs/observable/*",
                "rxjs/add/operator/*",
                "rxjs/add/observable/*",
                "rxjs/util/*"
            ]
        }
    });
})(this);

if it’s not work for you, then, I’m pretty sure the problem is yours only. and try to update rxjs to rc.4, few things have changed after beta.12.

here is my spec: angular 2.3.1 rxjs 5.0.rc4 systemjs 0.19.38 systemjs-builder 0.15.34

I wonder if it is possible to configure system builder or another tool to yield a bundle like this:

  • System bundle format
  • With the entry point modules exposed as system modules, so that it can actually work
  • But with all the numerous other internal modules squashed into a blob with rollup or similar, so as to not be any larger than necessary

It seems to me that such a thing would be the ideal way to distribute RxJS as a bundle, for use in cases where application level bundling is not suitable.

closing this, as there’s a number of useful solutions, and this issue isn’t something that angular can fix. thanks for helping out @unlight @damiandennis @steve3d 👍

@mh-dev Here it is (version “5.0.0-beta.12”). I used only “minify” (377 kB) and not “mangle” (originally 223 kB) so maybe this is the difference. Rx.zip

having the same (or similar) issue. been using rxjs through the systemjs config up to RC5 and it was working fine. In RC5, had to change for a script tag in index.html to include Rx.min.js. now that I upgraded to RC7 (and now 2.0.0), the index.html include doesn’t work anymore. I reverted to the systemjs config file with:

paths: { 'rxjs/*': 'node/rxjs/Rx.min.js', },

but now I get errors in the router:

core.umd.min.js:21 Error: Uncaught (in promise): TypeError: Cannot read property ‘call’ of undefined at l (zone.min.js:1) at l (zone.min.js:1) at eval (zone.min.js:1) at e.invokeTask (zone.min.js:1) at Object.onInvokeTask (core.umd.min.js:29) at e.invokeTask (zone.min.js:1) at n.runTask (zone.min.js:1) at a (zone.min.js:1) at XMLHttpRequest.invoke (zone.min.js:1)ErrorHandler.handleError @ core.umd.min.js:21next @ core.umd.min.js:29generatorOrNext.object.schedulerFn @ […] zone.min.js:1 Unhandled Promise rejection: Cannot read property ‘call’ of undefined ; Zone: angular ; Task: Promise.then ; Value: TypeError: Cannot read property ‘call’ of undefined(…) TypeError: Cannot read property ‘call’ of undefined at ApplyRedirects.expandSegmentGroup (http://localhost:5000/node/angular2/router/router.umd.min.js:20:8956) at ApplyRedirects.apply (http://localhost:5000/node/angular2/router/router.umd.min.js:20:7499) at applyRedirects (http://localhost:5000/node/angular2/router/router.umd.min.js:6:7976) at eval (http://localhost:5000/node/angular2/router/router.umd.min.js:20:29638) at new e (http://localhost:5000/node/zone/zone.min.js:1:18127) at Router.runNavigate (http://localhost:5000/node/angular2/router/router.umd.min.js:20:29443) at eval (http://localhost:5000/node/angular2/router/router.umd.min.js:20:28999) at e.invoke (http://localhost:5000/node/zone/zone.min.js:1:15913) at Object.onInvoke (http://localhost:5000/node/angular2/core/core.umd.min.js:29:16609) at e.invoke (http://localhost:5000/node/zone/zone.min.js:1:15864)

this is completely blocking us and is a serious problem.

due to our development model, we do not want to change for webpack any time soon. Systemjs with transpiling in the browser is perfect for us in development. in prod, we simply change to the compiled js. Squeezing every single bit of performance is not an issue for us internally.

thanks

edit: just replaced the Rx.min.js bundle with the full package, pointing to Rx.js instead and it works now, so the problems is definitely caused by Rx.min.js bundle. Current solution is really not ideal, because it adds almost 50 calls to the load time. how can we use the bundle in 2.0.0?

@woppa684 Visual Studio works very well for A2 development - we train people using that regularly. However, it doesn’t have all the things it needs on its own. You will end up needing, 99% likely, to run the needed Node-based tooling inside your Visual Studio environment. New Visual Studio versions make this increasingly easy.

(Using A2 with no Node involved in the build tooling at all - that could be tough.)

There seems to be a problem with the new router v3 and rxjs, used to have below in “path” and it used to work:

 "rxjs/*": "node_modules/rxjs/bundles/Rx.umd.min.js"

The including via script tag only works if you are not importing rxjs yourself.

I don’t think it is worth to use the umd bundle anyway. It seems Rxjs folks have broken down the components into smaller pieces, then you need to explicitly reference what you want to use. This have reduced the amount of files being downloaded a lot from previous versions.

Agreed. Loading individual files are only a problem in development mode with SystemJS loader. For production we bundle them into a single file for fast loading. But even if we get this to work (Rx UMD) we still have yet hundreds of files to deal with (on-the-fly typescript). So I believe the definitive answer for all of this is migration to webpack and angular-cli (I hope so).

TLDR: rxjs UMD is not helpful

Is there something new related to the problem with using RxJS bundle?