ASP.NET CoreでTypeScriptを使う

Visual Studio 2017でASP.NET Core Web アプリケーションプロジェクトからTypeScriptを試せる環境を作るまでのメモです。

ASP.NET Coreもそうですが、npmもgulpもbowerもわからない状況だったので、空のプロジェクトから始めると理解できるかなと。色々やってみて少しわかってきたので書き残しておきます。(個人的にこんなにツールを使わないといけないの?感があります・・・。)

まず参考にしたのはこちらのドキュメントです。

ASP.NET Core · TypeScript

+αでRazor Pages(やっぱりhtmlよりcshtmlの方がいいので)やgulp.watchも試しました。

ASP.NET CoreでTypeScript

ASP.NET Coreの空のプロジェクトからはじめて、次のTypeScriptのコードが実行できるまでを目指します。

// 実行したいコード
document.addEventListener("DOMContentLoaded", event => {
    alert("Hello!");
});

手順はこんな感じです。

  1. プロジェクトを作成する
  2. Startupクラスを設定する
  3. TypeScriptを実行するcshtmlを準備する
  4. TypeScriptの構成ファイルを準備する
  5. 実行するTypeScriptファイルを準備する
  6. npm構成ファイルを準備する
  7. Gulp構成ファイルを準備する

順番に見ていきましょう。

プロジェクトを作成する

ASP.NET Core Web アプリケーションのプロジェクトを選択してプロジェクトを作ります。上記ドキュメントと同じなので端折ります。

Startupクラスを設定する

プロジェクトで静的なファイルを扱えるようにして、Razor Pagesも動くようにします。具体的にはStartupクラス(Startup.cs)を次のようにします。

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

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

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

        // MVCを扱う(Razor Pagesを使う場合もこれ)
        app.UseMvc();
    }
}

Configureメソッドは、HTTPリクエストを処理する方法を指定するといった感じかなと。

詳しくはこのあたり。

ASP.NET Core でのアプリケーションの起動 | Microsoft Docs

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

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

Pages/
   └─ Index.cshtml

ソリューションエクスプローラーでPagesフォルダを選択してポップアップメニューの追加 > Razor ページから作るといい気がします。

Index.cshtmlの中身はこんな感じです。これから作るTypeScript(というかJavaScript)を読み込むために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>
    @* これから作るjsファイルを指しておく *@
    <script src="~/js/app.js"></script>
</body>
</html>

この段階でデバッグ実行するとページが表示されるはずです。

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

TypeScript JSON 構成ファイル(tsconfig.json)を作ります。compileOnSavetrueにしておくと、tsファイルを保存するとjsファイルができるようになります。

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

細かい部分はよくわからないので、このあたりを確認しながらかなと。

試してませんが、tsconfig.jsonの代わりにプロジェクトのプロパティにあるTypeScript ビルドで設定してもいいのかもしれません。

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

プロジェクト直下にScriptsフォルダを作ります。その中にapp.tsファイルも作りましょう。

Scripts/
   └─ app.ts

app.tsの中身は最初にでてきたコードです。やっとですね。

document.addEventListener("DOMContentLoaded", event => {
    alert("Hello!");
});

app.tsを保存するとapp.jsができてるはずです。

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

npm 構成ファイル(package.json)を作ります。このあと説明するGulpを取得するためです。

{
    "version": "1.0.0",
    "name": "asp.net",
    "private": true,
    "devDependencies": {
        "gulp": "3.9.1"
    }
}

ファイルを保存してしばらくすると、プロジェクト直下にnode_modulesというフォルダができるみたいです。ソリューションエクスプローラーですべてのファイルを表示すると見えると思います。

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

Gulp 構成ファイル(gulpfile.js)を作ります。Scriptsフォルダ内のts、jsファイルをwwwroot/jsフォルダにコピーするタスクを設定します。

/// <binding ProjectOpened='default' />

const gulp = require("gulp");

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

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

スクランナーエクスプローラー(ソリューションエクスプローラーでgulpfile.jsを選択してポップアップメニューのスクランナー エクスプローラ)を開きます。publishタスクができているので、ダブルクリックなどでタスクを実行すると、wwwroot/jsフォルダにts、jsファイルがコピーされます。

wwwroot/
   └─ js/
      ├─ app.ts
      ├─ app.js
      └─ app.js.map

デバッグ実行すると、ページが表示されてalertが表示されます。

スクランナーエクスプローラーでdefaultタスクを選択してポップアップメニューのバインド > プロジェクトを開くを選択しておきます。ソリューションを開くと、defaultタスクが実行されてファイルの変更が監視されるようになります。tsファイルを保存するたびにwwwroot/jsフォルダにコピーされるので、開発が捗るんじゃないかなと思います。gulpfile.jsの1行目にある/// <binding ProjectOpened='default' />がそれなのかなと。

Gulpについてはこのへんを参考にしました。

これで目標達成です。

試した環境