2

Official Angular 4 plunk has a constant problem because it loads unbundled RxJS and often chokes on requests to unpkg.com

Can SystemJS configuration be modified to use bundled RxJS in bundled Angular modules?

  map: {
    ...
    'rxjs': 'npm:rxjs/bundles/Rx.js'
  },
  packages: {
    ...
    rxjs: {
      defaultExtension: 'js'
    }
  }

doesn't work well and results in 404 errors:

unpkg.com/rxjs@5.4.3/bundles/Rx.js/operator/share.js:1

GET https://unpkg.com/rxjs@5.4.3/bundles/Rx.js/operator/share.js 404 ()

because Angular bundled modules contain imports like:

import {Observable} from 'rxjs/Observable';
import {of } from 'rxjs/observable/of';
import {concatMap} from 'rxjs/operator/concatMap';
import {filter} from 'rxjs/operator/filter';
import {map} from 'rxjs/operator/map';
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Not sure what your problem with the template is. Chokes on request? When doing anything special? I've never had the problem myself, so it's hard to reproduce – Fredrik Lundin Aug 22 '17 at 13:15
  • 1
    There is a hundred requests or so to unpkg.com due to `rxjs` package, accidentally page loading stops on one of them (pending promise in SystemJS). This won't happen if RxJS is loaded entirely once as bundled module, I guess that would be a good way to address the problem. – Estus Flask Aug 22 '17 at 13:20

1 Answers1

1

One simple way is to remove rxjs from map and add it as rxjs* into path (I think you'll need to use absolute path here):

paths: {
  'rxjs*': 'https://unpkg.com/rxjs@5.4.3/bundles/Rx.min.js'
},

This however works only with SystemJS 0.19.* because since 0.20 the wildcard * is no longer supported, see: https://github.com/systemjs/systemjs/issues/1039

For Angular2: I'm not aware if there's any recommended way for SystemJS 0.20 but this has been discussed on RxJS GitHub page so you can read the entire thread https://github.com/ReactiveX/rxjs/issues/2458. In particular from my comment https://github.com/ReactiveX/rxjs/issues/2458#issuecomment-286706048 and then another comment where I create a custom AMD bundle which is pretty simple to do and works with SystemJS 0.20 as well https://github.com/ReactiveX/rxjs/issues/2458#issuecomment-287193937.

Edit: So apparently this now works only with Angular2 and not in Angular4: https://plnkr.co/edit/ddRnL2I4ps2U2pdoRo04?p=info

For Angular4 the easies way I found is to create a new file that polyfills missing exports (see commends bellow):

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import 'rxjs/add/observable/merge';

export function merge(...observables: Observable[]) {
  return Observable.merge(observables);
}

export function share(observable: Observable) {
  if (!observable) {
    return;
  }
  return observable.share();
}

And then load this file instead of the bundled RxJS:

paths: {
  'npm:': 'https://unpkg.com/',
  'rxjs/observable/merge': './src/rxjs-polyfill.ts',
  'rxjs/operator/share': './src/rxjs-polyfill.ts',
  'rxjs*': 'https://unpkg.com/rxjs@5.4.3/bundles/Rx.min.js'
},

Working demo with Angular4: http://plnkr.co/edit/tu561CX0n1I9f53iVv12

martin
  • 93,354
  • 25
  • 191
  • 226
  • 1
    Thanks, but I wish it was that easy! The errors appear in Angular bundled modules that actually use RxJS (http, common) : http://plnkr.co/edit/3WlBXM5O6le4tbP1dUd7?p=preview . Yes, since 0.20 is flawed, we have to stay with 0.19 indefinitely. – Estus Flask Aug 22 '17 at 13:58
  • Hmm, that's interesting I'm sure it did work a few months ago but now I'm not able to find any version of Angular where it works. – martin Aug 22 '17 at 14:28
  • Good to know it's [still applicable to A2](http://plnkr.co/edit/yxaS3fEfKUhEvnzxQJjM?p=preview). I guess this was changed in A4. I'm quite sure that operators were imported like `import 'rxjs/add/operator/map'` in 2, and they are `import {map} from 'rxjs/operator/map'` in 4. – Estus Flask Aug 22 '17 at 14:39
  • I already found where's the problem. The two operators are imported here https://github.com/angular/angular/blob/master/packages/core/src/application_ref.ts#L12 and then used as static methods https://github.com/angular/angular/blob/master/packages/core/src/application_ref.ts#L486. But if you look here `share` is never exported https://github.com/ReactiveX/rxjs/blob/master/src/Rx.ts. So that's why it works when you load single file but doesn't when you load it as a bundle. – martin Aug 22 '17 at 14:48
  • @estus Ok, I solved it, see my edit and http://plnkr.co/edit/tu561CX0n1I9f53iVv12 – martin Aug 22 '17 at 15:10
  • Nice, thanks, I wonder if SystemJS can hook `rxjs/operator/*` requests to Observable.prototype from `rxjs/Rx` somehow. – Estus Flask Aug 22 '17 at 15:22
  • I don't think SystemJS itself could do this but you can make another polyfill just like I did. Although, I'm not sure what this would be good for.. – martin Aug 22 '17 at 15:27
  • I mean it could use `Observable.prototype` instead of export object for each of `rxjs/operator/*` imports to transform exports by means of SystemJS hooks (I'm not sure if it's possible). I did a quick grep on A4 sources to get the list of operators: http://plnkr.co/edit/wPMIZRyntAkOIxOnzWhT?p=preview Guess that's the shortest way to do this with ES modules alone. Probably at this point it would be easier and safer to get the list from RxJS sources instead. – Estus Flask Aug 22 '17 at 15:53
  • @estus I think I understand but I don't think this is possible with just SystemJS. – martin Aug 23 '17 at 09:14
  • What a pity. Any way, thanks for the good idea, a plunk with reexported operators is lightning fast. – Estus Flask Aug 23 '17 at 11:50