How to import `Observable` from `Rx` (not angular)
Asked Answered
G

5

7

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>
Grunt answered 18/2, 2017 at 11:22 Comment(4)
After your update, there is no reason why this code should not work. It would appear that you are able to load the module, seeing as how the import Rx from rxjs/Rs approach works. What does your JS look like after transpiling?Sainthood
FYI, this question no longer relates to RxJS, in that this problem can exist for any library you try to import. It may be worth updating the title and question to reflect this so you will get more systemjs/ecmascript-6 answers.Sainthood
This seems to be a known issue with commonjs + systemjs. github.com/systemjs/systemjs/issues/334Sainthood
I think this has an answer here: https://mcmap.net/q/1624975/-how-to-load-named-exports-with-systemjsChud
U
3

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';
Unlawful answered 18/2, 2017 at 11:32 Comment(2)
I've tried your solution too, but the Observable is always undefined. I've pushed my setup to this github repo. Hope you have a change to have a look. thnxGrunt
The problem is that the Observable itself not being imported properly by SystemJSArbitral
R
1

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.

Rockfish answered 20/2, 2017 at 9:54 Comment(1)
Thanks for the help. I've tried this but still without success. I've setup a small repo github here with my config and javascript/html files. I must be doing something stupid, because Observable is always undefinedGrunt
C
1

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.

Cankerworm answered 9/10, 2017 at 8:44 Comment(0)
G
0

I run into a similar problem, and managed to get unblocked changing my tsconfig.json module from "system" to "commonjs", and Rx lib files are being transpiled without getters.

Grilse answered 16/10, 2017 at 17:29 Comment(0)
S
0

This appears to be a known issue.

https://github.com/systemjs/systemjs/issues/334

From the documentation ocumentation:

Any module type can be loaded from any other type with full support.

When loading CommonJS, AMD or Global modules from within ES6, the full module is available at the default export which can be loaded with the default import syntax.

For convenience, named exports are also auto-populated but may not be correctly bound as expected, so use these carefully.

./app/es6-loading-commonjs:

// entire underscore instance
import _ from './underscore.js';

// unbound named export
import {map} from './underscore.js';

https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#inter-format-dependencies

Sainthood answered 16/10, 2017 at 18:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.