Visual Studio Code & TypeScriptを使い、ブラウザ用の開発設定についてのメモです。以下のような条件の開発設定です。
- 複数のTypeScriptファイルに分割して開発
- TypeScriptのコードは、Node.jsからも利用できる(Module対応)
- Visual Studio Codeからデバッグできる
- async/await構文に対応する
この記事で扱う環境のバージョンは以下の通りです。
- Visual Studio Code : 1.10.1
- Node : 6.5.0
- TypeScript : 2.2.1
#環境構築
基本的な環境構築方法(Visual Studio CodeとNode.js等のセットアップ)については、筆者のページにまとめていますので、こちらをご連ください。
TypeScript関連のセットアップが終わったら、Visual Studio Codeに「Debugger for Chrome」拡張機能をインストールします。もし、Chromeがインストールされていない場合は、Chromeもインストールします。
#tsconfig.json の記述
TypeScriptのプロジェクトのディレクトリ(.tsファイルが置いてあるディレクトリ)に、「tsconfig.json」というファイルを作成し、設定を記述します。以下のような感じです。
{
"compilerOptions": {
"target": "ES5",
"module": "amd",
"sourceMap": true,
// 出力するファイル名を指定
"outFile": "./src/main.js",
"lib": [
"dom",
"es5",
"scripthost",
"es2015.promise"
]
}
}
ポイントは3つ
- modlue に amd を設定(AMD形式のモジュールを使用)
- outFile を指定(今回は、./src/main.jsを指定しましたが、ここは場合によって変更してください)
- lib を指定(特に、「es2015.promise」が重要です)
modlueを指定しない場合、トランスパイルされたファイルがoutFileに指定されたファイルにすべて結合されて出力されるため、ブラウザ上で動作させる場合、こちらの方が便利かもしれません。ただ、Node.jsでこの設定でVisual Studio Codeからデバッガをアタッチした場合、うまくブレークポイントを設定することができませんでした。そのため、筆者は、ブラウザ上で動作させる場合にもModuleを使用して開発する方針にしています。
modlueにamdを指定しているため、outFileの設定は必須ではありません。ただ、これを設定しないと、tsファイルごとにjsファイルとmapファイルが生成され、ディレクトリが汚れます。そのため、少なくとも開発中は一つのjsファイルにまとめるように設定しています。
libの指定は、async/awaitを使うために、重要です。awaitで待つ関数はPromiseオブジェクトを返さないといけないのですが、ここで指定しておかないと、インテリセンスに文句を言われました。そのほかのライブラリはデフォルトのもののようです。
.vscode/tasks.json
「.vscode/tasks.json」ファイルがない場合、プロジェクトのビルド(Ctrl + B)を行うと、「タスクランナーが構成されていません。」と出ると思います。そこで、右端の「タスクランナーの構成」をクリックし、「TypeScript - tsconfig.json」を選択します。すると、
「.vscode/tasks.json」が作成されます。内容は特に編集する必要はありません。
以下のようなファイルが作成されます。
{
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"args": ["-p", "."],
"showOutput": "silent",
"problemMatcher": "$tsc"
}
.vscode/launch.json
次に、デバッグ用の設定を記述します。デバッグを開始すると、デバッグ構成を選択できますが、デフォルトですとあまりいい感じにならないため、手動で「.vscode/launch.json」ファイルを作成し、以下のように記述します。
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Local",
"type": "chrome",
"request": "launch",
// 読み込むHTMLファイルを指定
"file": "${workspaceRoot}/index.html",
"trace" :true,
"sourceMaps": true,
"runtimeArgs": [
"--allow-file-access-from-files"
]
}
]
}
このように記述すると、デバッグを開始すると、ディレクトリ下の「index.html」ファイルをChromeで開き、デバッグができるようになります。「runtimeArgs」に「--allow-file-access-from-files」を渡しておくことで、ローカルファイルを読み込むようなJavaScriptの実行もデバッグできます。
ちなみに、すでにChromeが起動しているといろいろとうまくいきませんので、一旦終了しておく必要があります(Macの場合は、プロセスを終了させておきます)。もし、起動中のChromeを使用したい場合は、requestにattachを指定し、Chromeの起動設定を変更する必要があります(この記事では詳細は省略します)。
index.html
さて、Chromeから最初に読み込むHTMLファイルを記述します。以下のような感じです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title> Test </title>
</head>
<body>
<!-- javascriptの読み込み -->
<script src="https://www.promisejs.org/polyfills/promise-7.0.4.min.js"></script>
<script data-main="./src/main.js" src="require.js"></script>
</body>
</html>
AMD方式でトランスパイルするように設定したため、HTMLからJavaScriptファイルを読み込むためには、RequireJSを使用します。こちらのサイトから「require.js」ファイルをダウンロードし、index.htmlと同じディレクトリに配置してください。そして、
<script data-main="./src/main.js" src="require.js"></script>
のようにdata-main
を使って、対象のJavaScriptファイルを読み込むようにします。また、TypeScriptでasync/awaitを使う場合、Promiseが必要になるのですが、PromiseはIE11では対応していないため、PolyFillのライブラリも読み込むようにしておきます。
テストしてみる
プロジェクトディレクトリは、以下のようなファイル構成とします。
- .vscode
- launch.json
- tasks.json
- index.html
- require.js
- main.ts
- module.ts
- src
- main.js
- main.js.map
このうち、「launch.json」「tasks.json」「index.html」「require.js」は先に述べた通りです。また、「src」ディレクトリ以下はビルドすると自動生成されます。main.tsとmod.tsは、以下の通りです。なお、エントリポイントとなるtsファイルの名前とトランスパイル後のjsファイルの名前は同じにしておく必要があるようです。
import Hello = require("./mod");
var hello:Hello = new Hello();
hello.Show();
class Hello
{
public Show()
{
console.log("Hello!!");
}
}
export = Hello;
以下、注意事項のメモです。
- エントリポイントとなるtsファイルとトランスパイル後のjsファイル名とが異なった場合、実行されませんでした…
- module.tsというファイル名にすると、いろいろとトラブりました。おそらく、何かを書き換えてしまったのだと思います。
デバッグを開始すると、Chromeが起動します。ただ、ブレークポイントの設定が間に合わないのか、うまくブレークポイントを設定しても止まらないことがあります。その場合、Visual Studio Codeの方から「再起動」するとうまくいきました。
以上の設定で、tsファイル側にブレークポイントを仕掛けてデバッグすることができます。また、TypeScriptのモジュール仕様も利用することができます。(export/import周りの仕様は、別途記事にしていきたいと思います。)
async/awaitも対応しています。例えば、mod.tsを以下のように書き換えます。
class Hello
{
showDelay()
{
return new Promise( resolve =>
{
window.setTimeout(
()=>{
console.log("Hello 2");
resolve();
},
1000);
});
}
public async Show()
{
console.log("Hello 1");
await this.showDelay();
console.log("Hello 3");
}
}
export = Hello;
これを実行すると、Hello 1が出力されたのちに、1秒後にHello2→Hello 3と表示されます。IE11でも問題なく動作します。(Promiseについては、こちらで紹介しています。)
まとめ
筆者のTypeScript環境(ブラウザ開発編)についてまとめました。とりあえず、大規模なものの開発に必要なモジュール部分とデバッガのアタッチ、TypeScriptで使えると便利なasync/await周りを利用できるための設定方法を紹介しました。
###参考