銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Visual Studio Code で ASP.NET Core とTypeScript開発をセットアップしたい(未完)

Visual Studioを使って、ASP.NET Core で TypeScriptを使うセットアップについては公式のドキュメントがあります。

ASP.NET Core · TypeScript

なのですが、Visual Studio Codeを使った場合のセットアップ方法が見つからなかったので試してみました。ただ、とりあえず動いたけど、まだいまいち思い通りの挙動にならないという状態です。

まずはじめにyo aspnetでEmptyWebApplicationを生成します。ドキュメントに併せて、StaticFilesを利用できるようにします。

project.json

"Microsoft.AspNetCore.StaticFiles": "1.0.0"

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //略
    app.UseDefaultFiles();
    app.UseStaticFiles();
    //略
}

次にTypeScriptを追加します。

$ mkdir scripts
$ touch scripts/app.ts
function sayHello() {
    const compiler = (document.getElementById("compiler") as HTMLInputElement).value;
    const framework = (document.getElementById("framework") as HTMLInputElement).value;
    return `Hello from ${compiler} and ${framework}!`;
}

tsconfigを追加しますが、今回はプロジェクトのルートに配置することにします。

$ yo aspnet:TypeScriptConfig
{
  "compilerOptions": {
      "noImplicitAny": true,
      "noEmitOnError": true,
      "sourceMap": true,
      "target": "es5"
  },
  "files": [
      "./scripts/app.ts"
  ],
  "compileOnSave": true
}

次にgulpでTypeScriptのビルドタスクを記述することにします。必要なパッケージを追加できるようにpackage.json を作成します。

$ yo aspnet:PackageJson
{
    "version": "0.0.0",
    "name": "aspnetcorewithtypescript",
    "devDependencies": {
        "gulp": "3.9.1",
        "del": "2.2.0",
        "gulp-typescript": "2.13.6"
    }
}

で、gulpfileなのですが、問題が一つあって、Visual Studio CodeでCtrl+Shift+Bでビルドするコマンドはtasks.jsonに記述しますが、これは単一のコマンドしか指定できません(単一のコマンドでオプションを変えたものを複数実行することはできる)。そこで、dotnet 関連のビルドもgulpにまとめて記述してみることにします。

$ yo aspnet:Gulpfile
/// <binding AfterBuild='default' Clean='clean' />
/*
This file is the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkId=518007
*/
"use strict";

var gulp = require('gulp');
var del = require('del');
var gutil = require('gulp-util');
var spawn = require('child_process').spawn;
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");

var paths = {
    scripts: ['scripts/**/*.js', 'scripts/**/*.ts', 'scripts/**/*.map'],
};

function runner(cmd, args){
    return function(callback) {
        let command = spawn(cmd, args);
        command.stdout.pipe(process.stdout);
        command.stderr.pipe(process.stderr);
        command.on('close', function (code) {
            if (code !== 0) {
                throw new gutil.PluginError('dotnet', `Exited with code ${code}: ${cmd} ${args}.`);
            }
            callback();
        });
    }
}

gulp.task('clean', function () {
    return del(['wwwroot/scripts/**/*']);
});

gulp.task('default', function () {
    return tsProject.src()
        .pipe(ts(tsProject))
        .js.pipe(gulp.dest("wwwroot/scripts"));
});

gulp.task('dotnet-build', runner('dotnet', ['build']));
gulp.task('dotnet-restore', runner('dotnet', ['restore']));
gulp.task('dotnet-run', runner('dotnet', ['web']));
gulp.task('dotnet-test', runner('dotnet', ['test']));

これでgulp経由で起動できるようになったので.vscode/tasks.jsonを書き直します。

{
    "version": "0.1.0",
    "command": "gulp",
    "isShellCommand": true,
    "args": [],
    "tasks": [
        {
            "taskName": "default",
            "args": [],
            "isBuildCommand": true
        },
        {
            "taskName": "dotnet-build",
            "args": ["dotnet-build"],
            "isBuildCommand": true,
            "problemMatcher": "$msCompile"
        }
    ]
} 

ここまでやると、Ctrl+Shift+BでTypeScriptのビルドとdotnet buildがまとめて実行されるようになりました。が、問題はいくつかあって、一つはF5デバッグ起動するときにエラーになります。これはtasks.jsonのtasknameを変更したため、launch.jsonのpreLaunchTaskに指定しているタスクが実行できないためです。そして、preLaunchTaskは1つしか指定できないのでどうしよう、という状態です。

もっといいセットアップ方法がある気がするのですが、いったん調査結果としてまとめてみました。