はじめに
振り返るとだいぶ手順が多かったのでまとめてみます。
この記事は、書き始めた時期と書き終わった時期に数ヶ月ほどの差があります。
そのため一部チグハグなところがあると思いますが、目を瞑っていただけるとありがたいです。
また、その数ヶ月の間にコンテナの起動方法をDocker ComposeからDev Containersに変えたので、そのあたりが特にチグハグだと思います。
作る環境
- TypeScript
- Jest
- VSCode(ローカルPCにインストール済み)
- Git
みたいなのを、Dev Containersという拡張機能を使ってDockerで作ります。
ローカルの環境
- OS:MacOS Sonoma 14.1 (Apple M1)
- ターミナル:ITerm2をVSCodeから使ってる
- エディタ:VSCode(拡張機能あり)
- Git Graph
- Docker
- Dev Containers
- Jest
- など...
- Docker Desktopインストール済み
愚痴
私はもともとJavaScriptの学習をしていたのですが、色々やっていくうちにTypeScriptいいなと思い始めました。
ですが、TSはJSと違ってコンパイラ(トランスパイラ)が必要です。
そしてローカルPCにコンパイラを入れるのが嫌だったため、TSをやるときはいつもDockerを立てています。
そして毎回1からDocker立ててTypeScript入れてJest入れて設定ファイル編集して...とかやっているのですが、これはあまりに非効率だと昨日気づきました。
ただ自動化する方法がわかんないので辛いです。
まあそれでも今後少しでも楽になるように、今日のところは上に書いた開発環境を作る手法をメモっておこうと思います。
結論
これは先日怒りの感情に任せて書いたメモです。
これだけだと分かりづらいので、下に詳しい解説を書いていこうと思います。
-
devcontainer.json
をコピペで作る- TypeScriptとJestを入れる
-
node_modules
をボリュームにする - 拡張機能のセッティングする
-
tsconfig.json
のセッティング-
tsc --init
でtsconfig.json
を生成する -
rootdir
を./src
にする -
outdir
を./build
にする -
target
をes2022
にする -
resolveJsonModule
をtrue
にする - 一応動くか試してみる
-
- Jestのセッティング(
jest.config.js
)- TypeScriptでテストを書くには追加でパッケージを入れる必要がある
@types/jest
ts-jest
- まずは
jest --init
でjest.config.js
を生成する- configファイルでTypeScriptを使うか?に
y
と答えるとやり直し
(ts-node
が必要って言われる)
- configファイルでTypeScriptを使うか?に
- デフォルトだと
import
使えない問題を解消する
(ts-jest
を入れた上でpreset
にts-jest
を指定する) - テストファイル作って一応動かしてみる
- だいたいここでなんかエラー出るので調べる
- TypeScriptでテストを書くには追加でパッケージを入れる必要がある
-
.gitignore
を作って以下を書く-
node_modules
インストールしたパッケージがある場所 -
build
コンパイルしたjsファイル置き場 - 時と場合によっては
.gitignore
- やってるとだんだん増えてゆく
-
1. Dockerコンテナを立てる
まずはDockerコンテナを立てていきます。
忙しい方は下のまとめを読んでみてください。
devcontainer.jsonの作成
昔はdockerfile
とcompose.yaml
を作っていたのですが、最近は.devcontainer/devcontainer.json
でやるようにしています。
これはVSCodeのDev Containerという拡張機能用のファイルで、Dockerコンテナの構築をやってくれる便利なものです。
以下のファイルを新しく作ります。
{
"name": "Dev Steps",
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye",
"workspaceFolder": "/project",
"workspaceMount": "source=${localWorkspaceFolder},target=/project,type=bind",
"mounts": [
"target=${containerWorkspaceFolder}/node_modules,source=dev-steps-volume"
],
"features": {
"ghcr.io/devcontainers-contrib/features/jest": {
"version": "latest"
}
},
"customizations": {
"vscode": {
"extensions": [
"Orta.vscode-jest",
"shd101wyy.markdown-preview-enhanced"
]
}
},
"onCreateCommand": "sudo chown node node_modules && yarn install"
}
ここでは、以下のことをやっています。
- ベースイメージにTypeScript + Node.jsを指定
-
node_modules
をボリュームにする - Jestのインストール
- テストフレームワーク
-
features
のところに書ける
- ワークスペースに
/project
を指定 - 使いたい拡張機能のインストール
- ここではJestとMarkdown Preview Enhanced
-
yarn install
を実行-
node_modules
の権限をnode
に変更
-
こんな感じです。
あとはここに適宜必要なものを追加していきます。
ちなみに/project
というパスはプロジェクトルートです。
時と場合によって変わったりもします。
また、コンテナの/project
に現在開いているワークスペースのフォルダを紐づけるため、workspaceMount
を設定しています。
node_modules
をボリュームにする理由
node_modules
はnpmやyarnでインストールしたパッケージ置き場なので、基本的にファイルの量が膨大になります。
しかも一度package.json
に追記してしまえば、コマンドひとつ叩くだけでインストールができます。
そんなものをローカルPCに置いておく必要があるのか...?
私が出した答えはNOでした。
/project/node_modules
をボリュームにすると、このディレクトリの中身はコンテナとローカルで共有されなくなります。
なので、コンテナでyarn install
すると、コンテナにはパッケージがインストールされますが、ローカルPCにはインストールされません。
コンテナを立てる
必要なファイルができたので、Dockerコンテナを立てていきます。
といってもコマンドを打つわけではなく、VSCode右下に出る通知からやります。
まずはウィンドウをリロードします。
これはコマンドパレットからやるといいと思います。
次に、右下に出てきた通知から「コンテナーで再度開く」をクリックします。
そしたらしばらく待ちます。
コンテナを起動しているため、結構時間がかかることもあります。
少し待ったら、node_modules
だけがあるVSCodeが立ち上がると思います。
これで準備は完了です。
正常にできているか確認する
さて、ここまでで出来ていて欲しいのは以下です。
- Node.jsのインストール
- TypeScriptのインストール
- Jestのインストール
-
node_modules
のボリューム化 - ワークスペースが
/project
になっている
というわけで、まとめて確認していきます。
まずはVSCodeからターミナルを開きます。
すると、おそらくプロンプトが以下のようになっていると思います。
青い部分が/project
となっていたら、ワークスペースが/project
に設定されています。
では、ここからコマンドを打って各ツールがあるか確認します。
node --version
v20.11.1
tsc --version
Version 5.3.3
jest --version
29.7.0
バージョンの差異はあれど、だいたいこんな感じに出力と思います。
エラーなく各コマンドが実行できれば成功です。
また、VSCodeのエクスプローラーにnode_modules
があれば、おそらくnode_modules
のボリューム化は出来ています。
あとは拡張機能が有効されているか確認してみてください。
Gitを設定する
せっかくならGitの設定もここでやってしまいましょう。
Gitを初期化する
まずは初期化です。
律儀にgit init
コマンドを打ってもいいですが、せっかくVSCodeを使っているのでVSCodeからやります。
サイドバーのソース管理アイコンを押して、「Initalize Repository」を押します。
(画像は私の前の記事の使い回しですが、実際は英語です)
ちなみに、VSCodeからGitを操作する方法を記事にしてるので、良かったら見てみてください。
.gitignoreを作る
Gitで管理しないフォルダ/ファイルを設定していきます。
私は基本的に以下を使っています。
.DS_Store
build
node_modules
-
.DS_Store
... Macが内部で使っているファイル、Git管理する必要はない -
build
... TypeScriptをコンパイルしたJSファイルが入る場所 -
node_modules
... パッケージ置き場
コミットする
ついでにコミットしておいたほうがいいと思います。
設定ミスってぐちゃぐちゃになる前にやっておくと、後戻りできて楽です。
1のまとめ
-
拡張機能群を入れる
-
.devcontainer/devcontainer.json
を作るdeccontainer.jsonのテンプレ
.devcontainer/devcontainer.json{ "name": "Dev Steps", "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye", "mounts": [ { "type": "volume", "source": "dev-steps-volume", "target": "${containerWorkspaceFolder}/node_modules" } ], "features": { "ghcr.io/devcontainers-contrib/features/jest": { "version": "latest" } }, "workspaceFolder": "/project" }
-
コンテナを立てる
- VSCodeをリロードする
- 通知から「コンテナーで再度開く」を選択する
-
うまく出来ているか確認する
- ターミナルのプロンプトに
/project
があることを確認する - 以下コマンドを打ってみる
node --version
tsc --version
jest --version
- エクスプローラーに
node_modules
があることを確認する - 拡張機能が有効化されていることを確認する
- ターミナルのプロンプトに
-
Gitを設定する
- VSCodeのサイドバーから初期化する
-
.gitignore
を作るnode_modules
build
.DS_Store
- コミットする
2. tsconfig.jsonを書き換える
さて、1で作ったdevcontainer.json
には、typescript
とjest
をインストールする設定が書いてありました。
そのため、もうすでにこのコンテナにはTypeScript(とJest)が入っています。
ということで、さっそくtsconfig.json
を書き換えていきます。
ファイルを生成する
まずはターミナルに以下のコマンドを入力して、tsconfig.json
を生成します。
tsc --init
すると何やら長いファイルが生成されます。
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// 以下略
}
設定を書き換える
そしたら、ここの設定をお好みで書き換えていきます。
私は以下のように設定することが多いです。
{
"compilerOptions": {
"target": "ES2022", // なんとなく
"rootDir": "./src", // srcにtsファイルを入れる
"outDir": "./build", // コンパイルしたファイルは./buildに配置
"resolveJsonModule": true // JSONをimportできるようにする
},
"exclude": [
"**/*.test.ts" // テストファイルはコンパイル対象から除外
]
}
ここの設定はお好みでいいと思います。
コンパイルしてみる
この設定でコンパイルできるか試してみます。
ここで動かなかったらtsconfig.json
の設定を見直します。
まずはsrc
ディレクトリを作ります。
これはrootDir
の設定が./src
なのに合わせています。
そして、src
ディレクトリの直下にindex.ts
を作ります。
const text: string = 'Hello World!';
console.log(text);
ではコンパイルします。
以下のコマンドを入力してください。
tsc
すると、新しくbuild
ディレクトリが作られ、その中にコンパイルしたindex.js
ファイルが入ります。
だいたい以下のような中身になるはずです。
"use strict";
const text = 'Hello World!';
console.log(text);
エラーが出ずに上のような結果になれば、ひとまずコンパイルは大丈夫だと思います。
あとはエラーが出た都度tsconfig.json
を編集する感じです。
2のまとめ
-
tsc --init
でファイルを生成する -
設定を書き換える
私が使っている設定
tsconfig.json{ "compilerOptions": { "target": "ES2022", "rootDir": "./src", "outDir": "./build", "resolveJsonModule": true }, "exclude": [ "**/*.test.ts" ] }
-
tsc
を実行してコンパイルできることを確認する
3. jest.config.jsを書き換える
次はJestの設定ファイルであるjest.config.js
を書き換えていきます。
ちなみに、この設定ファイルがない状態でjest
コマンドを実行すると、以下のように怒られます。
jest
Error: Could not find a config file based on provided values:
略
ファイルを生成する
以下のコマンドを入力します。
yarn init -y
warning The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.
success Saved package.json
Done in 0.04s.
jest --init
? Would you like to use Jest when running "test" script in "package.json"? y
? Would you like to use Typescript for the configuration file?
? Choose the test environment that will be used for testing
> node
? Do you want Jest to add coverage reports? n
? Which provider should be used to instrument code for coverage?
> v8
? Automatically clear mock calls, instances, contexts and results before every test? y
yarn init -y
を実行しているのは、package.json
を生成するためです。
このファイルがないとjest --init
を実行した時にエラーが出て失敗してしまいます。
Warningが出ていますが、とりあえず気にしないことにします。
jest --init
で設定した内容は以下のとおりです。
-
test
スクリプトをpackage.json
に追加するか? yes- これをやると
yarn test
でテストが実行できるようになる
- これをやると
-
jest.config.js
にTypeScriptを使うか? no- これを
y
にしたらts-node
が必要って言われた記憶がある - JSでもJSDocコメントによって補完は出る
- これを
- テスト環境はどうするか? node
- よくわからんけど
node
でいいと思う
- よくわからんけど
- カバレッジレポートは必要か? no
- よくわからんからnoにしてる
- v8とbabelのどっちを使うか? v8
- これもよくわからん
- テスト前にデータを消去するか? yes
- よくわからんが消していいと思う
多分これでも動くとは思いますが、一応自分で調べることを推奨します。
必要なものをインストールする
現状だとテストができないため、必要なパッケージを入れます。
型定義を追加する
現状だと型定義がないため、describe
などの関数を書こうとするとVSCode上でエラーが出てしまいます。
これを解消するため、@types/jest
パッケージを入れます。
yarn add --dev @types/jest
これで補完が効いてエラーが出なくなるはずですが、一応試してみます。
というわけで、テストファイルを作ります。
test
ディレクトリを新しく作り、その中にsum.test.ts
を作ってください。
describe('test', () => {
test('てすと', () => {
expect(1 + 1).toBe(2);
});
});
ここの内容はなんでもいいですが、describe
を書いてエラーが出なければ多分大丈夫だと思います。
importを使えるようにする
このJest、実はデフォルトのままだとimport
文が使えません。
エラーが発生することを確認する
試しに、src/index.ts
とtest/sum.test.ts
を以下のようにします。
// xとyの合計を返す関数
export function add(x: number, y: number) {
return x + y;
}
+ import { add } from "../src/index";
describe('test', () => {
test('てすと', () => {
- expect(1 + 1).toBe(2);
+ expect(add(1, 1)).toBe(2);
});
});
そして、以下のコマンドを実行します。
jest
FAIL test/sum.test.ts
● Test suite failed to run
Jest encountered an unexpected token
# 略
SyntaxError: Cannot use import statement outside a module
見ての通り、「SyntaxError: Cannot use import statement outside a module」というエラーが出ました。
これはimport
がモジュールではない箇所で使われているというエラーです。
インストールする
このエラーを解決するためには、ts-jest
というパッケージが必要です。
これはJestが内部で使う、TypeScriptをNode.jsで実行できるJavaScriptにするためのものです。
というわけで、以下のコマンドを実行してください。
yarn add --dev ts-jest
warning " > ts-jest@29.1.2" has unmet peer dependency "jest@^29.0.0".
warning " > ts-jest@29.1.2" has unmet peer dependency "typescript@>=4.3 <6".
# 略
上のようなWarningが出ますが、ひとまず気にしないことにします。
また、このts-jest
を使うためにはtypescript
パッケージが必要です。
これは自動でインストールされないので、手動で入れていきます。
以下のコマンドを実行してください。
yarn add --dev typescript
設定ファイルを書き換える
ということで、jest.config.js
を書き換えていきます。
といっても書き換えるのはpreset
のみです。
以下のようにファイルを編集してください。
/** @type {import('jest').Config} */
const config = {
// 他の設定はデフォルトのままにしておく
preset: "ts-jest"
};
これで、先ほどインストールしたts-jest
パッケージを、Jestが内部で使うようになるはずです。
テストしてみる
では、いよいよテストを実行してみたいと思います。
まず、src/index.ts
とtest/sum.test.ts
が以下のようになっていることを確認してください。
多少違っても、import
とexpect().toBe()
あたりが入っていれば大丈夫です。
export function add(x: number, y: number) {
return x + y;
}
import { add } from "../src/index";
describe('test', () => {
test('てすと', () => {
expect(add(1, 1)).toBe(2);
});
});
確認ができたら、ターミナルに以下のコマンドを入力してください。
jest # yarn test でも可
PASS test/hello.test.ts
test
✓ てすと (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.295 s
Ran all test suites.
こんな感じでエラーが出ずに実行できれば成功です。
3のまとめ
-
yarn init -y
を実行してpackage.json
を生成する -
jest --init
を実行してjest.config.js
を生成する- 「Would you like to use Jest when running "test" script in "package.json"?」は
y
にしたほうが便利だと思う - 「Would you like to use Typescript for the configuration file?」を
y
にする場合、ts-node
パッケージが追加で必要だった気がする
- 「Would you like to use Jest when running "test" script in "package.json"?」は
- 必要なモジュールを入れる
-
@types/jest
... Jestの型定義 -
ts-jest
... TypeScriptで書いたテストを実行するために必要 -
typescript
...ts-jest
のために必要
-
- 設定ファイルを書き換える
-
jest.config.js
のpreset
をts-jest
にする
-
-
jest
コマンドでテストしてみる
参考