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を導入してみます。
実のところ前回のエントリは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を試せる環境を作るまでのメモです。
まずは試した環境から。
- Visual Studio 2017
- ASP.NET Core 2.0 + Razor Pages
- TypeScript 2.6
- webpack 3.10
いつものように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 - DevelopmentやWatch Developmentをダブルクリックしてwebpackを実行すると、wwwroot/jsフォルダにbundle.jsファイルが作成されます。
デバッグ実行してアラートであいさつができれば今回の目標クリアです。
ASP.NET CoreでTypeScriptを使う(続き・改)
前回のTypeScriptでjQueryを使うの別パターンです。
前回は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を使う(続き)
前回の続きでもうちょっとします。
今回は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が表示されます。
目標クリア。