2017-10-20 1 views
3

RxJS 5.5 macht eine große bahnbrechende Änderung und führt lettable operators ein, um im Grunde alle Operatoren zu ersetzen, die wir früher benutzt haben ("Patch" -Operatoren).Importieren von mietbaren RxJS-Operatoren

Dieser Artikel enthält eine Anmerkung:

Lettable operators can now be imported from rxjs/operators, but doing so without changing your build process will often result in a larger application bundle. This is because by default rxjs/operators will resolve to the CommonJS output of rxjs.

Diese Aussage ist einfach Beweis über die Praxis mit dem brandneuen AngularCLI generierte App.

Wenn wir eine Anwendung, die nichts von RxJS importieren ist:

import { Component, OnInit } from '@angular/core'; 
import { HttpClient } from "@angular/common/http"; 

@Component({ 
    selector: 'app-root', 
    templateUrl: './app.component.html', 
    styleUrls: ['./app.component.css'] 
}) 
export class AppComponent implements OnInit { 
    public title = 'app'; 

    constructor(private readonly http: HttpClient) { 
    } 

    public ngOnInit(): void { 
    this.http.get('https://api.github.com/users') 
     .subscribe(response => { 
     console.log(response); 
     }); 
    } 
} 

Wir können sehen, wie folgt:

ng build --prod 
chunk {0} polyfills.e1f97a0070e18e96a6be.bundle.js (polyfills) 61.4 kB {4} [initial] [rendered] 
chunk {1} main.b2b5d212102ca9d103e8.bundle.js (main) 4.92 kB {3} [initial] [rendered] 
chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes {4} [initial] [rendered] 
chunk {3} vendor.4b7be3dbe842aec3f0ab.bundle.js (vendor) 236 kB [initial] [rendered] 
chunk {4} inline.387c7023e5627ac04221.bundle.js (inline) 1.45 kB [entry] [rendered] 

Wenn wir einen RxJS Operator die „alte“ Art und Weise importieren und verwenden sie es:

import { Component, OnInit } from '@angular/core'; 
import { HttpClient } from "@angular/common/http"; 
import "rxjs/add/operator/map"; 

@Component({ 
    selector: 'app-root', 
    templateUrl: './app.component.html', 
    styleUrls: ['./app.component.css'] 
}) 
export class AppComponent implements OnInit { 
    public title = 'app'; 

    constructor(private readonly http: HttpClient) { 
    } 

    public ngOnInit(): void { 
    this.http.get('https://api.github.com/users') 
     .map((u: any) => 1) 
     .subscribe(response => { 
     console.log(response); 
     }); 
    } 
} 

Wir keinen Gewinn in der Größe von Bündeln sehen:

chunk {0} polyfills.e1f97a0070e18e96a6be.bundle.js (polyfills) 61.4 kB {4} [initial] [rendered] 
chunk {1} main.229ad10195bbb426b3e8.bundle.js (main) 4.96 kB {3} [initial] [rendered] 
chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes {4} [initial] [rendered] 
chunk {3} vendor.933334fc50e7008778fe.bundle.js (vendor) 236 kB [initial] [rendered] 
chunk {4} inline.6a52179d8b19cd3cc179.bundle.js (inline) 1.45 kB [entry] [rendered] 

Wenn wir versuchen, den vermietbaren Operator statt wie empfohlen zu importieren und zu verwenden, aber ohne den Build-Prozess zu ändern:

import { Component, OnInit } from '@angular/core'; 
import { HttpClient } from "@angular/common/http"; 
import { map } from "rxjs/operators"; 

@Component({ 
    selector: 'app-root', 
    templateUrl: './app.component.html', 
    styleUrls: ['./app.component.css'] 
}) 
export class AppComponent implements OnInit { 
    public title = 'app'; 

    constructor(private readonly http: HttpClient) { 
    } 

    public ngOnInit(): void { 
    this.http.get('https://api.github.com/users').pipe(
     map((u: any) => 1)) 
     .subscribe(response => { 
     console.log(response); 
     }); 
    } 
} 

Wir sehen, dass die Verkäufer Bündel 108 kB größer ist, die uns sagt, dass RxJS ‚hasn t wurde baum shaked:

chunk {0} polyfills.e1f97a0070e18e96a6be.bundle.js (polyfills) 61.4 kB {4} [initial] [rendered] 
chunk {1} main.450c741a106157402dcd.bundle.js (main) 4.97 kB {3} [initial] [rendered] 
chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes {4} [initial] [rendered] 
chunk {3} vendor.3f53f0e2283f4c44ec38.bundle.js (vendor) 344 kB [initial] [rendered] 
chunk {4} inline.2d973ef5a10aa806b082.bundle.js (inline) 1.45 kB [entry] [rendered] 

Wenn ich versuche, den vermietbaren Operator zu importieren, wie im No Control over Build Process Abschnitt des Artikels zu empfehlen:

import { map } from "rxjs/operators/map"; 

Ich bin ein Build-Fehler bekommen:

./src/app/app.component.ts 
Module not found: Error: Can't resolve 'rxjs/operators/map' in 'c:\Projects\Angular\src\app' 
@ ./src/app/app.component.ts 14:0-41 
@ ./src/app/app.module.ts 
@ ./src/main.ts 
@ multi webpack-dev-server/client?http://localhost:4200 ./src/main.ts 
  1. Was mache ich falsch?
  2. Wie können wir neue RxJS-Leetable-Operatoren in eine Angular CLI-App importieren, so dass RxJS immer noch "Tree-Shaked" ist?

UPDATE: Paketversionen (im Grunde sind alle aktuellen Versionen eines AngularCLI App im Moment "wollte"):

rxjs: 5.5.0 
@angular/cli: 1.4.9 
node: 8.6.0 
os: win32 x64 
@angular/animations: 4.4.6 
@angular/common: 4.4.6 
@angular/compiler: 4.4.6 
@angular/core: 4.4.6 
@angular/forms: 4.4.6 
@angular/http: 4.4.6 
@angular/platform-browser: 4.4.6 
@angular/platform-browser-dynamic: 4.4.6 
@angular/router: 4.4.6 
@angular/cli: 1.4.9 
@angular/compiler-cli: 4.4.6 
@angular/language-service: 4.4.6 
typescript: 2.3.4 
+0

Es könnte ziemlich überraschend sein, siehe https://github.com/webpack/webpack/issues/2867 – kemsky

+0

@ kemsky: Vielen Dank für die Info! Der Grund, warum es nicht von Bäumen gesäumt ist, wird in dem Artikel erklärt, den ich zur Verfügung gestellt habe. Die Frage ist im Grunde, wie es mit dem aktuellen AngularCLI Build-System umgehen kann? –

+0

Könnten Sie bitte die 'ng Version'-Ausgabe posten? Ich habe keinen Buildfehler mit @ angular/cli gefunden: 1.2.0, @angular/___: 4.4.6, [email protected] –

Antwort

2

Zur Vollständigkeit @ Winkel/cli @ 1.4.9 fügt im Anschluss an die in models/webpack-configs/common.js

// Read the tsconfig to determine if we should prefer ES2015 modules. 
// Load rxjs path aliases. 
// https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#build-and-treeshaking 
let alias = {}; 
try { 
    const rxjsPathMappingImport = 'rxjs/_esm5/path-mapping'; 
    const rxPaths = require_project_module_1.requireProjectModule(projectRoot, rxjsPathMappingImport); 
    alias = rxPaths(nodeModules); 
} 
catch (e) { } 

    resolve: { 
     extensions: ['.ts', '.js'], 
     modules: ['node_modules', nodeModules], 
     symlinks: !buildOptions.preserveSymlinks, 
     alias 
    }, 

und rxjs/_esm5/Pfad-mapping.js hat diese beiden Einträge

"rxjs/operators": path.resolve(PATH_REPLACEMENT, "rxjs/_esm5/operators/index.js"), 
... 
"rxjs/operators/map": path.resolve(PATH_REPLACEMENT, "rxjs/_esm5/operators/map.js"), 

Der wesentliche Bit der Fehlermeldung ist

aliased with mapping 'rxjs/operators': 
    'C:\Dev\Projects\rx55\node_modules\rxjs\_esm5\operators\index.js' to 
    'C:\Dev\Projects\rx55\node_modules\rxjs\_esm5\operators\index.js/map' 
... 
C:\Dev\Projects\rx55\node_modules\rxjs\_esm5\operators\index.js\map doesn't exist 

so dass die erste Abbildung mit dem zweiten stört.

Durch die Umkehrung der Reihenfolge der Zuordnungen funktioniert der Build, also liegt der Fehler meines Wissens nach bei rxjs v5.5.

Das heißt, Alexanders Work-Around ist der Weg bis zur Behebung.

1
  1. Stellen Sie sicher, Sie wirklich mindestens 5.5.0 mit . Ansonsten überprüfe, dass die Datei node_modules/rxjs/operators/map.js existiert, weil ich nicht weiß, wie es nicht geht. Auch die Verwendung import { map } from "rxjs/operators"; importiert die gleiche Datei darunter, so dass ich verdächtige etwas mit Ihrem Build-System falsch ist.

  2. Der richtige Weg zur Verwendung der Operatoren ist sie rxjs/operators/* (zum Beispiel, wie Sie mit import { map } from "rxjs/operators/map"; taten) zu importieren bilden.

    Wenn Sie von rxjs/operators importieren, ist es das gleiche wie von rxjs in RxJS importieren < 5.5.0, weil Sie tatsächlich rxjs/operators/index importieren, siehe https://github.com/ReactiveX/rxjs/blob/master/src/operators/index.ts.

    Deshalb wurde es nicht "Baum-erschüttert", es importierte alle Operatoren, die in index.ts aufgeführt sind.

+0

Ich überprüfte meine RxJS-Version, es ist 5.5.0. Die Datei existiert tatsächlich. In meiner Frage habe ich es auf der brandneuen von AngularCLI generierten App getestet - Sie können es leicht selbst überprüfen. Es ist kein Build-System-Problem. Dieser Artikel zeigt, dass das Importieren einer Importdatei wie 'import {map} von" rxjs/operators/map "; eine alternative Möglichkeit zum Importieren ist, falls Sie Ihren Buildprozess nicht modifizieren können, um das Plugin' ModuleConcatenationPlugin' hinzuzufügen Baumschüttelbare Betreiber. Ich bin mir nicht sicher, warum es etwas mit tiefen Importen nicht finden kann. Vielleicht hängt es mit den Build-Einstellungen von AngularCLI zusammen? –

1

Wie sich herausstellte (Kredite an @RichardMatsen), es ist ein Fehler in angular-cli 1.4.9.

Der Versuch, tief Importe (wie import { map } from "rxjs/operators/map";) mit angular-cli 1.4.8, gibt es keine Build-Fehler und Gebindegrößen sind:

chunk {0} polyfills.e1f97a0070e18e96a6be.bundle.js (polyfills) 61.4 kB {4} [initial] [rendered] 
chunk {1} main.d36cf6834f640163ff35.bundle.js (main) 4.97 kB {3} [initial] [rendered] 
chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 0 bytes {4} [initial] [rendered] 
chunk {3} vendor.658e9efd9845db281b29.bundle.js (vendor) 241 kB [initial] [rendered] 
chunk {4} inline.c9d245ca6c859aaeef69.bundle.js (inline) 1.45 kB [entry] [rendered] 

, die zeigt, nur 5 kB Gewinn im Vergleich zu der Version, die RxJS Betreiber gar nicht verwenden .

So jetzt haben wir mindestens eine Abhilfe: bleiben auf angular-cli 1.4.8 und Import vermietbare operatirs mit tiefen Importe wie:

import { map } from "rxjs/operators/map"; 
import { filter } from "rxjs/operators/filter";