如何使用 systemjs 在最小的 Angular 2 应用程序中加载 RxJS?

Posted

技术标签:

【中文标题】如何使用 systemjs 在最小的 Angular 2 应用程序中加载 RxJS?【英文标题】:How to load RxJS in a minimal Angular 2 app using systemjs? 【发布时间】:2016-01-27 13:34:08 【问题描述】:

我无法使用 RxJS 获得最小的 Angular 2 应用程序。我正在使用 Typescript (tsc 1.6.2) 和 systemjs 进行模块加载。如何让 systemjs 正确加载 Rx 模块?我已经没有什么想法可以尝试了,如果我能指出我做错了什么,我将不胜感激。模块加载对我来说有点神奇。非常沮丧。

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Title</title>
    <script src="../node_modules/es6-shim/es6-shim.js"></script>
    <script src="../node_modules/systemjs/dist/system.src.js"></script>
    <script src="../node_modules/rx/dist/rx.lite.js"></script>
    <script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
</head>

<body>
    <app>App loading...</app>
    <script>
        System.config(
            packages:  'app':  defaultExtension: 'js'  
        );
        System.import('app/app');
    </script>
</body>
</html>

app.ts

/// <reference path="../../node_modules/rx/ts/rx.all.d.ts" />
import  bootstrap, Component, View  from 'angular2/angular2';
import * as Rx from 'rx';

@Component(
    selector: 'app'
)
@View(
        template: `Rx Test`
)
export class App 
    subject: Rx.Subject<any> = new Rx.Subject<any>();

bootstrap(App);

SystemJS 尝试加载一个不存在的文件:

只要我在上面的代码中注释掉 subject,一切都会运行良好,因为不会尝试加载不存在的文件(并且不会加载 rx)。 p>

【问题讨论】:

【参考方案1】:

更新 angular2 beta 0

Angular2 不再将 RxJS 捆绑在 Angular2 本身中。现在您必须单独导入运算符。这是我answered here 的重要突破性变化。因此,请参考该答案,因为该答案已过时且不再适用。

2015 年 12 月 11 日更新

Alpha46 正在使用 RxJS alpha 0.0.7(即将成为 0.0.8)。由于这个 ng2 alpha 版本您不再需要下面的解决方案,您现在可以直接从 angular2/angular 导入 ObservableSubject 等,因此可以丢弃原始答案

import Observable, Subject from 'angular2/angular2';

======================================

Angular2 不再使用旧的RxJS,他们移到了新的RxJS 5(又名 RxJS Next),所以它会与 Http 和 EventEmitter 发生冲突。

所以首先删除 rx.lite.js 的导入和脚本。

相反,您必须这样做(您的配置中不需要脚本或映射)

编辑

这一行是为了让它在 plnkr 中工作,但在我的项目中我只需要添加一些其他的东西

Plnkr 版本

import Subject from '@reactivex/rxjs/dist/cjs/Subject';

离线版

import * as Subject from '@reactivex/rxjs/dist/cjs/Subject';

离线版注意事项

如果您在本地项目中尝试第一种 plnkr 方法,您可能会收到此消息错误

TypeError: Subject_1.default is not a function

因此,对于您的本地(离线)版本,您应该使用第二种方法(使用星号)。

注意

Subject 中没有括号,this conversation 中对此进行了解释(我遇到了同样的问题,哈哈)

这是plnkr not failing。

我希望它有所帮助。如果我错过了什么,请告诉我;)

【讨论】:

埃里克,感谢您抽出宝贵时间回复!这为我解决了部分谜团。很抱歉花了这么长时间才回复你,我今天大部分时间都在试图让同一个项目离线工作(我必须说没有任何真正的成功)。我正在使用 VSC 和 Typescript 1.6.2,与您的示例中使用的转译器相同。在“在线”版本中从 app.ts 生成的代码有一个稍微不同的标头,这似乎产生了很大的不同(它调用System.register(...))。你有没有成功地用 VSC/tsc 在本地编译和运行它? 您是否遇到任何错误?事实上,在我的离线版本(我自己的项目)中,我有import * as Subject from '...'(与我的答案有点不同。你还有别的吗?你的在线版本和离线版本有多大不同? 所以您在运行时遇到错误?还是默默地失败了?您是否在使用诸如 JSPM、Webpack 之类的工具?你可以创建一个 repo 以便我可以克隆它并查看它吗? 没有错误,转译没问题,智能感知工作(为此,我在 npm_modules 中添加了@reactivex alpha 4,与角度使用相同)。它在运行时 (TypeError: Subject_1.default is not a function) 失败,因为它似乎没有加载 rx 模块/类型。我将 config.js 更改为加载“app.js”和默认分机“js”,并删除了 index.html 中对 typescript.js 的引用。这让我发疯了。 好吧,这很有趣。编译器会抱怨,但生成的输出与在线版本中生成的输出相同 - 并且它在运行时工作。因此,除了 tsc 输出 (src/app.ts(11,14): error TS2304: Cannot find name 'Subject'. src/app.ts(11,29): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.) 之外一切正常。非常感谢你的帮助。下一杯啤酒在我身上:)。【参考方案2】:

对于 angular2 alpha52 使用 rxjs 5alpha.14

<script>
System.config(
  map:  rxjs: 'node_modules/rxjs' ,
  packages: 
    rxjs:  defaultExtension: 'js' ,
    'app': defaultExtension: 'js'
  
);
System.import('app/app');
</script>

但您必须像此示例一样单独导入每个运算符

import  Subject  from 'rxjs/Subject';
import  Observable  from 'rxjs/Observable';

require('rxjs/add/operator/map');
require('rxjs/add/operator/scan');
require('rxjs/add/operator/mergemap');  //for flatmap
require('rxjs/add/operator/share');
require('rxjs/add/operator/combinelatest-static'); //for combinelatest

【讨论】:

【参考方案3】:

在 Angular 4 发布后发布此答案。尝试从 Rxjs 加载最低限度,因为即使使用 AOT 的 Angular prod build 也会达到 300kb

希望对你有帮助。

import  Injectable  from '@angular/core';
import Http from "@angular/http";
import Observable from "rxjs/Observable";
import 'rxjs/add/operator/map';// load this in main.ts

import AllUserData from "../../../shared/to/all-user-data";

@Injectable()
export class ThreadsService 

  constructor(private _http: Http)  

  loadAllUserData(): Observable<AllUserData> 
    return this._http.get('/api/threads')
      .map(res => res.json());
  


【讨论】:

以上是关于如何使用 systemjs 在最小的 Angular 2 应用程序中加载 RxJS?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将 Polyfills 添加到 SystemJS Angular 4 应用程序

我如何实际部署 Angular 2 + Typescript + systemjs 应用程序?

赛普拉斯与SystemJS

“systemjs-builder”:如何将 js 文件中的所有依赖项构建到一个 bundle.js 文件中

在 Angular 中使用 SystemJs 导入时找不到模块

如何将文档注入 systemjs-builder 以捆绑 Angular 4.0.0 应用程序?