Help us understand the problem. What is going on with this article?

RxJS v5を小さくバンドルする方法。import文の書き方で容量が変わる(v6の書き方も紹介)

More than 1 year has passed since last update.

RxJS 5はES Modulesの import の書き方で容量が変わる。
利便性と容量のトレードオフの関係⚖

※注意:この記事はRxJS 5について言及したものだ。RxJS 5では import 文の書き方で容量が変わるが、RxJS 6ではツリーシェイキングが可能な構造になっているので、一般的な書き方で容量がコンパクトになる。RxJS 6についてもこの記事の末尾で検証結果を記載している。

公式ReadMeにも書かれていることだが、バンドルツールで検証したので数値結果とともに4通りの記述方法を示す。

image.png

1. 全部まるっとimport

import * as Rx from 'rxjs';

Rx.Observable.interval(200)
    .take(9)
    .map(x => x + '!!!')
    .bufferCount(2)
    .subscribe(value => console.log(value));

結果、953KB。RxJS全部が出力ファイルに格納される。

👉出力結果のファイルはこちら

2. Observable だけimport

import {Observable} from 'rxjs';

Observable.interval(200)
    .take(9)
    .map(x => x + '!!!')
    .bufferCount(2)
    .subscribe(value => console.log(value));

結果、953KB。RxJS全部が出力ファイルに格納される。
Rxという接頭語を書く必要が無くなる。

👉出力結果のファイルはこちら

3. 個別import

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/bufferCount';

Observable.interval(200)
    .take(9)
    .map(x => x + '!!!')
    .bufferCount(2)
    .subscribe(value => console.log(value));

結果、85KB。使っているものだけが import されるので容量が小さく収まる。

👉出力結果のファイルはこちら

ただし、import {Observable} from 'rxjs/Observable'; だけだとオペレーターが入らないので個別にオペレーターを含める必要がある。これは個人的には好かない。

import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/bufferCount';

バインドオペレーターを使うと少し改善されるかもしれないが、ES2017時点で入っていない機能なので上記の記法は仕方がないと諦める。

4. Pipeable Operatorsでのimportを使う

RxJS 5.5 (平成29年10月)からの機能だが、pipe()メソッドがある。この方法だと、いい感じにかける。詳しくは公式リポジトリの「rxjs/pipeable-operators.md at master · ReactiveX/rxjs」を参考にして欲しい。

import {interval} from 'rxjs/observable/interval';
import {bufferCount} from 'rxjs/operators/bufferCount';
import {map} from 'rxjs/operators/map';
import {take} from 'rxjs/operators/take';

interval(200)
    .pipe(
        take(9),
        map(x => x + '!!!'),
        bufferCount(2),
    )
    .subscribe(value => console.log(value));

結果、78KB。使っているものだけが import されるので容量が小さく収まる。

👉出力結果のファイルはこちら

ただし、import文の書き方は細かくかかなければならない。まとめてimport文を書こうとすると容量が膨らんでしまう。

誤り(容量が膨らむ)

import {interval} from 'rxjs/observable/interval';
import {bufferCount, map, take} from 'rxjs/operators';

ベストプラクティス(容量が小さくなる)

import {interval} from 'rxjs/observable/interval';
import {bufferCount} from 'rxjs/operators/bufferCount';
import {map} from 'rxjs/operators/map';
import {take} from 'rxjs/operators/take';

RxJS 6ではpipe式だけになる

ちなみにRxJS 6(平成30年4月25日リリース)では、pipe式を使う方法になっている。次に示すのはRxJS 6のコードだ。このコードをwebpackでビルドすると、容量は83KBとなった。

import {interval} from 'rxjs';
import {bufferCount, map, take} from 'rxjs/operators';

interval(200)
  .pipe(
    take(9),
    map(x => x + '!!!'),
    bufferCount(2)
  )
  .subscribe(value => console.log(value));

考察(重要)

利便性を考慮すると全部まるっとimportするほうが手間がかからない。しかし、Too Fatな設計を避けるため個別importするほうが望ましい。

補足だが、Angular-CLIで作ったプロジェクトだとtslintによって、rxjsrxjs/Rxとしてimport文を書くことをブラックリストとして定義されている。RxJSの個別importは許可されているが、まるっとimportはLint Errorとなる。

"import-blacklist": [
  true,
  "rxjs",
  "rxjs/Rx"
],

https://github.com/angular/devkit/blob/master/packages/schematics/angular/application/files/tslint.json#L19-L23

これは、rxjs とまるっとimportすると容量が膨らむことを示唆しての禁止事項だと思う。

Angular-CLIは開発環境のお手本がくまなく定義されており学ぶべきものが多い

検証サンプル

今回の検証サンプルはGitHubにアップ済み。TypeScriptとECMAScript 2017の両方を用意している。

webpack 4でバンドルしているが、webpackの使い方は記事「最新版で学ぶwebpack入門 - ICS MEDIA」を参照してほしい。Tree Shakingが有効になるようにproductionモードを使っているが、上記の容量に関してはUglifyJSの影響を少なくするために敢えて optimization.minimize : trueを設定している。

clockmaker
ウェブ制作会社ICSの代表および ics.media 編集長をやっています。得意分野はプログラミングアート、インタラクティブ表現の制作。詳しくはリンク先を御覧ください。 https://ics.media/entry/author/ikeda
http://clockmaker.jp/labs/
ics
インタラクションデザイン専門のプロダクション。最先端のウェブテクノロジーを駆使し、オンスクリーンメディアの表現分野で活動しています。最新のウェブ技術を発信するサイト「ICS MEDIA」を運営。
https://ics.media/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした