2020/11版:TypeScript の開発環境を yarn で構築する
今回は開発環境ということで minify や uglify などは行わないところまでとします。
また、 git や npm のローカルの準備は既に終わってるものとします。
TL;DR
yarn init -y
yarn add typescript --dev
yarn run tsc --init
yarn add sirv-cli ttypescript @zoltu/typescript-transformer-append-js-extension rimraf yarn-run-all --dev
tsconfig.json
を設定したら yarn ttsc
でトランスパイル完了! 以上!
yarn を初期化して必要なパッケージを入れる
mkdir -p src/ts
mkdir -p public/js
yarn init -y
yarn add typescript --dev
yarn run tsc --init
- Download TypeScript | TypeScript
- typescript | yarnpkg
tsconfig.json を編集する
yarn run tsc --init
で tsconfig.json が生成されているので設定を変更していきます。
EcmaScript の各ブラウザ対応状況を確認の上、設定してみました。
デフォルトの "target": "ES3",
, "module": "commonjs",
でいい気もしますが今回はこうしました。
yarn run tsc --init
で生成された tsconfig.json
には簡単なコメントもついているのでそれを参考にしながら設定していきましょう。
{
"compilerOptions": {
"target": "ES2017",
"module": "es2015",
"sourceMap": true,
"outDir": "./public/js",
"rootDir": "./src/tsc",
"removeComments": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
- Can I use ES2017
- ECMAScript 2016+ compatibility table
- TSConfig リファレンス紹介 | TypeScript
- TypeScriptの
--esModuleInterop
は一体何をやっているのか | stone's throw
テスト実行に必要なファイルを揃える
./public/index.html
<!DOCTYPE html>
<html>
<head>
<title>index</title>
<script type="module" src="./js/index.js"></script>
</head>
<body>
<h1>FooBar</h1>
<p id="foo"></p>
</body>
</html>
./src/tsc/index.ts
import { addBaz } from './baz'
window.onload = function () {
const app = document.getElementById("foo") as HTMLParagraphElement;
app.innerHTML ="Hello Typescript World! foo";
addBaz(app);
};
./src/tsc/baz.ts
export function addBaz(p:HTMLParagraphElement):void {
const baz = document.createElement("p");
baz.textContent = "It is Baz.";
p?.appendChild(baz);
}
ビルドしてみる
yarn tsc
いい感じですね
確認用の簡易Webサーバーを用意する
HTML+JavaScript をローカルで動作確認するのに
ESModuleを使おうとしたりすると CORS で怒られたりします。
なので確認用の簡易Webサーバーを用意しましょう。
パッケージはいろいろありますが今回は sirv-cli
を使います。
yarn add sirv-cli --dev
yarn sirv public --port 8080
- sirv-cli | GitHub
- A lightweight CLI program to serve static sites~!
- 概要がすき。sites~!
- https://github.com/lukeed/sirv/tree/master/packages/sirv-cli
- sirv-cli | yarnpkg
- http-server | GitHub
- http-server is a simple, zero-configuration command-line http server.
- 今回は使いませんでしたがこれもありますね
- https://github.com/http-party/http-server
import 時の拡張子が必要なのをどうにかする
- TypeScript での
import
はコレでイケるimport { Foo } from './foo';
- ブラウザで動かす JavaScript はこうじゃないとダメ
import { Foo } from './foo.js';
これがつらたんです。実は TypeScript で import { Foo } from './foo.js';
と書いても
解釈してくれるんですが、 foo.js
なんてファイルは ./src/ts/
配下にはないわけで気持ち悪い。
TypeScript の ISSUE としても上がってるんですが
TypeScript 的には path を書きかえない方針のようなのでどうにかしたいです。
- Provide a way to add the '.js' file extension to the end of module specifiers #16577 | TypeScript | GitHub
- Typescript compiler is forgetting to add file extensions to ES6 module imports? | Stack Overflow
この ISSUE のコメントについてるようなスクリプトを実行してもいいし
いろんな方法がありますね。babel 使うならこれが良さそうです。
- babel-plugin-add-import-extension | yarnpkg
今回は ttypescript
+ @zoltu/typescript-transformer-append-js-extension
を使うことにしました。
yarn add ttypescript @zoltu/typescript-transformer-append-js-extension --dev
tsconfing.json
にも追記します。最終的にこんな感じですね。
{
"compilerOptions": {
"target": "ES2017",
"module": "es2015",
"sourceMap": true,
"outDir": "./public/js",
"rootDir": "./src/tsc",
"removeComments": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"plugins": [
{
"transform": "@zoltu/typescript-transformer-append-js-extension/output/index.js",
"after": true,
}
]
}
}
そしたらビルドしてやりましょう。コマンドが変わります。
yarn ttsc
確認。
index.ts
import { addBaz } from './baz'
// ...後略
↓
index.js
import { addBaz } from "./baz.js";
// ...後略
.js
が追記されてますね。オッケー!
- cevek / ttypescript | GitHub
- ttypescript | yarnpkg
- Zoltu / typescript-transformer-append-js-extension | GitHub
- @zoltu/typescript-transformer-append-js-extension | yarnpkg
トランスパイル前に出力先をきれいにしておく
rimraf
を導入してトランスパイル先のディレクトリを削除するようにします。
これで、ファイル名変更などで出力されなくなったファイルなどもちゃんと消えるようになりますね。
yarn add rimraf --dev
yarn rimraf ./public/js/
- npm run のスクリプトの中でディレクトリの削除を行う (rimraf) | まくまくNode.jsノート
- rimraf | yarnpkg
複数の yarn run を順次/並列に実行する
これまでの作業で
- トランスパイル前に出力先を全削除
- トランスパイル実行
- 開発用サーバーの起動
が揃いました。あとは yarn run する scripts を記述してやるだけなのですが
せっかくなので yarn-run-all
(中身は npm-run-all
ですがw) を導入して
yarn run を順次/並列実行できるように準備しておきましょう。
yarn add yarn-run-all --dev
- yarn-run-all | yarnpkg
- mysticatea / npm-run-all | GitHub
- npm run のスクリプトを連続実行・並列実行する (npm-run-all) | まくまくNode.jsノート
- npm-scripts の 順次・並列実行(npm-run-all) | Qiita
- npm-run-allのもっと便利な使い方 | ミツエーリンクス
yarn run の scripts を書く
こんな感じですね。
今回は yarn-run-all
のグロブを使ったスクリプト実行はやりませんでした。
"scripts": {
"clean": "rimraf ./public/js/",
"ttsc": "ttsc",
"watch": "ttsc --watch",
"cleanwatch": "run-s clean watch",
"serve": "sirv public --port 8080",
"build": "run-s clean ttsc serve",
"dev": "run-p cleanwatch serve"
},
- tsc CLI Options | --watch | TypeScript
- Typescript で開発している人は watch オプションが便利 | USEFUL EDGE
最終的な package.json
はこんな感じです。
{
"name": "my_project",
"version": "1.0.0",
"main": "index.js",
"repository": "git@github.com:<userid>/my_project.git",
"author": "your name",
"license": "MIT",
"scripts": {
"clean": "rimraf ./public/js/",
"ttsc": "ttsc",
"watch": "ttsc --watch",
"cleanwatch": "run-s clean watch",
"serve": "sirv public --port 8010",
"build": "run-s clean ttsc serve",
"dev": "run-p cleanwatch serve"
},
"devDependencies": {
"@zoltu/typescript-transformer-append-js-extension": "^1.0.1",
"rimraf": "^3.0.2",
"sirv-cli": "^1.0.8",
"ttypescript": "^1.5.12",
"typescript": "^4.0.5",
"yarn-run-all": "^3.1.1"
}
}
コマンドはこんな感じです。
# clean して ttsc して sirv でサーバー起動。localhost:8080 で確認できる
# Ctrl+c で停止
yarn build
# clean して ttsc --watch しつつ sirv でサーバー起動。localhost:8080 で確認できる
# Ctrl+c で停止
# TypeScript ファイルを編集して保存すればトランスパイルが走る
# ブラウザで確認しているときは保存後、ハード再読み込みしましょう
yarn dev
以上です。おつかれさまでした。
今回のプロジェクトファイル一式はこちらです。
なんで gulp/webpack 使わないの?
yarn でイケたからです
なんで babel 入れてないの?
IE11対応の予定はないし 前述のES2015対応状況などをみるに私の要件には不要と判断したからです
その他の参考サイト
- export - JavaScript | MDN
- import - JavaScript | MDN
- ES6のexportについて詳しく調べた | Qiita
- ES2015 (ES6) の import や export (default)(React基礎講座4) | Qiita
- Qiita開発チームがReactの開発で default export を使わなくなった理由 | Qiita
- TypeScript: 38の具体例から学ぶnamed export | Qiita
- ブラウザにおける ES Modules の利用とパフォーマンスについて | 30歳からのプログラミング
- サバイバルTypeScript
- 非公式のTypeScriptスタイルガイド | TypeScript Deep Dive 日本語版
Discussion