RxJS - scanオペレータとreduceオペレータ

scanオペレータが気になって試しました。scanオペレータはreduceオペレータと似ています。比較しながら確認したコードを残しておきます。

違いその1

  • scanは都度nextコールバックが呼ばれる
  • reduceは(completeする前に)1回だけnextコールバックが呼ばれる

違いその2

  • scanはcompleteしなくてもnextコールバックが呼ばれる
  • reduceはcompleteしない限りnextコールバックが呼ばれない

ASP.NET CoreでTypeScriptとwebpackとRxJS

前回の続きでもう少しします。ASP.NET Core + TypeScript + webpackの環境にRxJSを導入してみます。

ichiroku11.hatenablog.jp

実のところ前回のエントリはTypeScriptでRxJSを試したくなったのがきっかけで、今回が本当の目的だったりします。

npmでRxJSをインストール

まずnpmを使ってRxJSをインストールしましょう。package.json@reactivex/rxjsをインストールするように指定します。

{
    "version": "1.0.0",
    "name": "asp.net",
    "private": true,
    "dependencies": {
        "@reactivex/rxjs": "5.5.6"
    },
    "devDependencies": {
        "webpack": "3.10.0",
        "typescript": "2.6.2",
        "ts-loader": "3.2.0"
    }
}

app.tsを書き換える

app.tsでRx.ObservableクラスをインポートしてRxJSを試すコードを書きます。

// app.ts
// Rx.Observableをインポート
import { Observable } from "@reactivex/rxjs";
// lib.tsのGreeterクラスをインポート
import { Greeter } from "./lib";

// あいさつする
Observable.of("world")
    .subscribe(message => alert(Greeter.greet(message)));

モジュールをインポートするには、モジュール名だけを指定する方法とパスを指定する方法があるみたいです。

tsconfig.jsを修正する

このままではビルドエラーになるので、tsconfig.jsを修正しましょう。コンパイラがnode_modulesフォルダ内のライブラリを参照できるように、"moduleResolution": "node"を追記しています。またRxJSがES2015の機能を使っているようなので、"lib": [ "es5", "es2015", "dom" ]も追記しています。

{
    "compileOnSave": true,
    "compilerOptions": {
        "noImplicitAny": false,
        "noEmitOnError": true,
        "removeComments": false,
        "sourceMap": true,
        "target": "es5",
        "module": "es2015",
        // コンパイラが"node_modules"フォルダを参照するみたい
        "moduleResolution": "node",
        // RxJSで"es2015"を利用しているみたい
        "lib": [
            "es5",
            "es2015",
            "dom"
        ]
    },
    "exclude": [
        "node_modules",
        "wwwroot"
    ]
}

これでビルドが通るはず。デバッグ実行して世界にあいさつしましょう。まだまだわからないことばかりですが、とりあえずRxJSを試せる環境になったので目標達成です。

ASP.NET CoreでTypeScriptとwebpack

Visual Studio 2017でASP.NET Core + TypeScript + webpackを試せる環境を作るまでのメモです。

まずは試した環境から。

いつものようにASP.NET Coreの空のテンプレートから始めたいと思います。

プロジェクトを作成する

ASP.NET Core Web アプリケーションのプロジェクトを選択してプロジェクトを作ります。

Startupクラスを設定する

Razor Pagesと静的ファイルを扱うために、Startupクラスを次のように修正します。

public class Startup {
    // 使用するサービスを設定
    public void ConfigureServices(IServiceCollection services) {
        // MVCを追加
        services.AddMvc();
    }

    // ミドルウェアを設定
    public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
        if (env.IsDevelopment()) {
            app.UseDeveloperExceptionPage();
        }

        // MVC(Razor Pages)を使う
        app.UseMvc();

        // 静的なファイルを使う
        app.UseStaticFiles();
    }
}

TypeScriptを実行するcshtmlを準備する

TypeScriptを実行するcshtmlを作りましょう。プロジェクトの直下にPagesフォルダを作って、その中にIndex.cshtmlを作ります。

Pages/
   └─ Index.cshtml

Index.cshtmlではこれから作るJavaScriptを指定します。指定している~/js/bundle.jsを、このあとwebpackで出力するようにしていきたいと思います。

@page
@model WebApp.Pages.IndexModel
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
   <meta name="viewport" content="width=device-width" />
   <title>Index</title>
</head>
<body>
    <h1>Hello!</h1>
    @* これから作るjsファイルを指定しておく *@
    <script src="~/js/bundle.js"></script>
</body>
</html>

まだJavaScriptは作っていませんが、これでデバッグ実行できるようになりました。実行してあいさつをすませておきましょう。

ちなみにここまでは以前の記事とほぼ同じです・・・。

実行するTypeScriptファイルを準備する

プロジェクト直下にScriptsフォルダを作って、その中にapp.ts、lib.tsを作ります。

Scripts/
   ├─ app.ts
   └─ lib.ts

app.tsでは、lib.tsでエクスポートしたクラスをインポートするようにしています。

// lib.ts
// あいさつ文を作るクラスをエクスポート
export class Greeter {
    public static greet(message): string {
        return `Hello, ${message}!`;
    }
}

// app.ts
// lib.tsのGreeterクラスをインポート
import { Greeter } from "lib";

// あいさつする
alert(Greeter.greet("world"));

モジュールというやつですね。TypeScriptでは問題ないのですが、JavaScriptでモジュールのインポートをどうすればいいのかわからず苦労しました。今回はwebpackを使いましたが、他にもいい方法があるような気も。

TypeScriptのモジュールの説明はこちら。

TypeScriptの構成ファイルを準備する

TypeScript JSON 構成ファイル(tsconfig.json)を作ります。

{
    "compileOnSave": true,
    "compilerOptions": {
        "noImplicitAny": false,
        "noEmitOnError": true,
        "removeComments": false,
        "sourceMap": true,
        "target": "es5",
        "module": "es2015"
    },
    "exclude": [
        "node_modules",
        "wwwroot"
    ]
}

npmでwebpackをインストールする

npmでwebpackとtypescript、ts-loaderをインストールします。typescriptとts-loaderは、webpackがTypeScriptを処理するために必要なものです。具体的にはnpm 構成ファイル(package.json)を次のようにします。

{
    "version": "1.0.0",
    "name": "asp.net",
    "private": true,
    "devDependencies": {
        "webpack": "3.10.0",
        "typescript": "2.6.2",
        "ts-loader": "3.2.0"
    }
}

webpackの構成ファイルを準備する

プロジェクト直下にwebpack.config.jsを作ります。Scriptsフォルダにあるapp.tsとインポートしているib.tsをまとめて、wwwroot/js/bundle.jsを作成するように指定します。

const path = require("path");

const config = {
    devtool: "inline-source-map",
    // webpackがバンドルの構築を開始するエントリポイント
    entry: path.resolve(__dirname, "scripts/app.ts"),
    output: {
        // 出力するファイル名
        filename: "bundle.js",
        // 出力フォルダ
        path: path.resolve(__dirname, "wwwroot/js")
    },
    module: {
        rules: [
            // TypeScriptを処理するローダー
            { test: /\.ts$/, loader: "ts-loader" }
        ]
    },
    resolve: {
        extensions: [".ts", ".js"],
        // モジュールを探すフォルダ(node_modulesとscriptsフォルダを対象にする)
        modules: [
            "node_modules",
            path.resolve(__dirname, "scripts")
        ]
    }
};

module.exports = config;

webpackやTypeScriptのドキュメントを参考にしながら手探りで書きました。

WebPack Task Runnerをインストールする

Visual StudioにWebPack Task Runnerをインストールしておきます。インストールすると、タスク ランナー エクスプローラでwebpackを実行できるようになります。

webpackでバンドルする

タスク ランナー エクスプローラにあるRun - DevelopmentWatch Developmentをダブルクリックしてwebpackを実行すると、wwwroot/jsフォルダにbundle.jsファイルが作成されます。

デバッグ実行してアラートであいさつができれば今回の目標クリアです。

ASP.NET CoreでTypeScriptを使う(続き・改)

前回のTypeScriptでjQueryを使うの別パターンです。

ichiroku11.hatenablog.jp

前回はjQueryを取得するのにBowerを使いましたが、npm+Gulpでできないかなと思ったので試してみました。まずは前回の続きからbower.jsonとwwwroot/libフォルダを削除しておきましょう。

npmでjQueryを取得

npmを使ってjQueryを取得します。具体的にはnpm 構成ファイル(package.json)に以下を追加します。

"dependencies": {
    "jquery": "3.2.1",
},

package.jsonは次のようになります。

{
    "version": "1.0.0",
    "name": "asp.net",
    "private": true,
    "dependencies": {
        "jquery": "3.2.1"
    },
    "devDependencies": {
        "@types/jquery": "3.2.16",
        "gulp": "3.9.1"
    }
}

ファイルを保存して少し待つとnode_modules/jqueryフォルダができると思います。

GulpでjQueryをコピー

Gulp 構成ファイル(gulpfile.js)を次のように修正します。publishタスクでnode_modules/jquery/distにあるjQueryファイルをwwwroot/lib/jquery/distにコピーするようにしています。

const gulp = require("gulp");

// publishタスク
gulp.task("publish", () => {
    // jQueryのjsとかをまるっとwwwroot/libにコピーする
    gulp.src(["node_modules/jquery/dist/*", ])
        .pipe(gulp.dest("wwwroot/lib/jquery/dist"));

    // Scriptsフォルダ内のts、jsファイルをwwwroot/jsフォルダにコピーする
    gulp.src(["scripts/**/*.ts", "scripts/**/*.js", "scripts/**/*.map"])
        .pipe(gulp.dest("wwwroot/js"));
});

// detaultタスク
gulp.task("default", () => {
    // Scriptsフォルダ内のjsファイルの変更を監視して、"publish"タスクを実行する
    gulp.watch("scripts/**/*.js", ["publish"]);
});

スクランナーエクスプローラーでpublishタスクを実行しましょう。Index.cshtmlを変更する必要はなく、そのままデバッグ実行するとalertが表示されるはずです。

こんな感じでいいのかなと。

ASP.NET CoreでTypeScriptを使う(続き)

前回の続きでもうちょっとします。

ichiroku11.hatenablog.jp

今回はjQueryを導入して、TypeScriptで次のコードを実行できるようにします。

// app.ts
$(event => {
    alert("Hello!");
});

app.tsを上記コードに書き換えてもjQueryを読み込んでいないので動きません。そのまえにエラーも出ていると思います。これらを解消していきます。

Bower構成ファイルを準備する

Bowerを使ってjQueryをプロジェクトにインストールします。npmではできないの?という気もしますし、webpack?Parcel?というツールも耳にしますが正直わからないのでおとなしくBowerを使うことにします。

まずBower 構成ファイル(bower.json)を作りましょう。中身はこんな感じです。

{
    "name": "asp.net",
    "private": true,
    "dependencies": {
        "jquery": "3.2.1"
    }
}

ファイルを保存して少し待つと、wwwrootフォルダの中にlib/jquery/フォルダができます。フォルダの中にたくさんファイルがありますが、jQueryのjsファイルはここにあります。

wwwroot/lib/jquery/dist/jquery.js

Index.cshtmlでjQueryを読み込む

Index.cshtmlにscript要素を追加して、src属性でjquery.jsを指定しましょう。<script src="~/lib/jquery/dist/jquery.js"></script>の部分ですね。

@page
@model WebApp.Pages.IndexModel
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
   <meta name="viewport" content="width=device-width" />
   <title>Index</title>
</head>
<body>
    <h1>Hello!</h1>
    @* jQueryを読み込む *@
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/js/app.js"></script>
</body>
</html>

TypeScriptの定義ファイルを使う

app.tsのエラーを回避するためにTypeScriptの定義ファイルを使います。npmを使ってインストールするといいみたいです。package.json"@types/jquery": "3.2.16"を足します。

{
    "version": "1.0.0",
    "name": "asp.net",
    "private": true,
    "devDependencies": {
        "@types/jquery": "3.2.16",
        "gulp": "3.9.1"
    }
}

ファイルを保存して少し待つと、node_modulesフォルダにインストールされます。TypeScriptのエラーも消えるはずです。消えない場合はソリューションを開き直すといいかもしれません。

デバッグ実行するとalertが表示されます。

目標クリア。

参考