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

2019-01-18 07:12发布

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>

5条回答
Juvenile、少年°
2楼-- · 2019-01-18 07:27

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';
查看更多
别忘想泡老子
3楼-- · 2019-01-18 07:27

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.

查看更多
神经病院院长
4楼-- · 2019-01-18 07:35

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

查看更多
地球回转人心会变
5楼-- · 2019-01-18 07:36

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.

查看更多
劳资没心,怎么记你
6楼-- · 2019-01-18 07:44

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.

查看更多
登录 后发表回答