Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import `Observable` from `Rx` (not angular)

I'm using SystemJS to load my es2015 project into the browser.

This is what I did

import {Observable} from 'rxjs/Rx';

const button = document.querySelector('button');
const start$ = Observable.fromEvent(button, 'click');

In this case Observable is undefined. So I tried

import Observable from 'rxjs/Observable';

In which case Observable is an object but Observable.fromEvent is undefined (it seems to be an empty object)

Finally I did

import Rx from 'rxjs/Rx' // Rx.Observable

which did work. Any ideas why the other two didn't work? I have seen code in which they used these. What would be the preferred way to import Observable?

UPDATE: As stated below its all described in the README. However if I do that

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';

const start$ = Observable.fromEvent(startButton, 'click');

I get Observable is undefined. And if I do

import Observable from 'rxjs/Observable';

the Observable is an empty object again. The fromEvent is not added.

I'm using RxJs 5.1.1 and here is my index.html/systemjs part:

 <script src="./node_modules/systemjs/dist/system.js"></script>
  <script>
      SystemJS.config({
          baseURL: 'node_modules',
          packages: {
              '.': {
                  defaultJSExtensions: 'js'
              }
          },
          map: {
              'plugin-babel': 'systemjs-plugin-babel/plugin-babel.js',
              'systemjs-babel-build': 'systemjs-plugin-babel/systemjs-babel-browser.js'
          },
          transpiler: 'plugin-babel'
      });

      SystemJS.import('/js/main.js');
  </script>
like image 783
Jeanluca Scaljeri Avatar asked Feb 18 '17 11:02

Jeanluca Scaljeri


Video Answer


3 Answers

As it notes in the README, you can use import { Observable } from 'rxjs/Observable';:

To import only what you need by patching (this is useful for size-sensitive bundling)

This gives you a very minimal Observable, to which you need to explicitly add any extra functionality you plan to use; in your case, follow it with:

import 'rxjs/add/observable/fromEvent';
like image 67
jonrsharpe Avatar answered Oct 17 '22 19:10

jonrsharpe


I was having exactly the same issue when transpiling from TypeScript. Then I switched to using just the compiled scripts with exactly the same options and it worked so I'm suspicious it has something to do with transpiling your script. The bad things is there's probably no easy way to check what code it generated.

Anyway, the different types of imports are as follows:

  1. import {Observable} from 'rxjs/Rx'

    Since you're using baseURL option this will look for file node_modules/rxjs/Rx.js. This is the entry point of RxJS that requires all Observables, Subjects, operator, so on... (about 300 files) and you'll import only Observable class.

  2. import Observable from 'rxjs/Observable'

    This imports only node_modules/rxjs/Observable.js file and its dependencies (about 20 files).

  3. import Rx from 'rxjs/Rx'

    This shouldn't work at all. RxJS doesn't export any Rx. You can see for yourself at src/Rx.ts

If you're loading single files you can use similar config as this:

System.config({
  packages: {
    'src': {
      defaultExtension: 'js'
    },
    'rxjs': {
      defaultExtension: 'js'
    }
  },
  paths: {
    'npm:': 'node_modules/',
    'main': 'src/index'
  },
  map: {
    'rxjs': 'npm:rxjs'
  }
});

Then all imports are loaded as single files. For example rxjs/util/isFunction = /node_modules/rxjs/util/isFunction.js.

This isn't very useful in the browser because it'll be very slow. You can however load the bundled version with wildcard *. Note that this works only in SystemJS 0.19.*:

System.config({
  packages: {
    'src': {
      defaultExtension: 'js'
    },
    'rxjs': {
      defaultExtension: 'js'
    }
  },
  paths: {
    'npm:': 'node_modules/',
    'main': 'src/index',
    'rxjs*': 'node_modules/rxjs/bundles/Rx.min.js'
  }

In SystemJS 0.20.* the wildcard * doesn't work any more (https://github.com/systemjs/systemjs/issues/1039)

With this config you can use all:

import {Observable} from 'rxjs';
import {Observable} from 'rxjs/Observable';
import {Observable} from 'rxjs/Rx';

Note that the situation in node environment is different because you can always use just import {Observable} from 'rxjs' thanks to main option in its composer.json.

like image 27
martin Avatar answered Oct 17 '22 17:10

martin


As I have the same issue on a project of mine, I've been trying to debug systemJs to understand.

Now I can tell that systemJS basically works like this: It transpile module files into setters and executes. setters load dependencies and inject them into IIFE variables. execute runs the module codes when the setters are all set. Those are what you wrote before transpile.

(function(System, SystemJS) {System.register(["node_modules/rxjs/Subject.js"], function (_export, _context) {
    "use strict";

    var Subject;
    return {
        setters: [function (_node_modulesRxjsSubjectJs) {
            Subject = _node_modulesRxjsSubjectJs.Subject;
        }],
        execute: function () {
            class PetriNode {
                constructor(name) {
                    this.from = [];
                    this.to = [];

... ...

I found out that systemJS loads modules with this project

within this line: line 612, the RxJs kinds of stuff and all load up fine.

      err = dynamicExecute(link.execute, require, moduleObj.default, module);

After executing, the module.exports and moduleObj.__useDefault is loaded perfectly fine. All the Rx Classes and outputs are there.

But All The Defaults are FAILED to get COPIED into moduleObj as after this: load default into moduleObj

And then, when the setter is called, the inputted argument is moduleObj, which has a .default property has all the proper output, but setter failed to call them from but moduleObj itself. load.module has no exported definitions. It's the load.module.default has them.

The importerSetters is called the first time when all the Rx is done and begin to deal with my ECMA2015 modules. It's skipped every time when there is no import but requires.

I don't understand how should I handle commonJS default with .d.ts with import. I've seen that systemJS could deal with commonJS and ECMA2015 before. I've done it independently but not together.

like image 1
AiShiguang Avatar answered Oct 17 '22 19:10

AiShiguang