最近は TypeScript を勉強中です。そこで、クライアントサイドではなくサーバーサイドのコードを書くのに Express を用いてみることにしました。データベースもちょっと触るのに何かよさそうなライブラリを探した結果、typeorm を使ってみることにしました。これらの開発環境として Visual Studio Code (VSCode) を用いて進めていきたいので、その環境設定を行いました。
これらの組み合わせで手間取ったので、情報を残しておこうと思います。手探りでやっていることもあり、もしかしたら間違った内容になっているかも知れませんがご了承願います。
各種パッケージのインストール
プロジェクト用のフォルダを作った後、必要なパッケージをインストールします。
npm install express typeorm reflect-metadata sqlite3
開発用として次のパッケージもインストールします。
npm install -D @types/node @types/express typescript
typeorm の初期化
先に typeorm の初期化を実行しておきます。これにより tsconfig が編集されるので注意です(後で修正します)。
npx typeorm init --database sqlite3
これにより src フォルダ以下に entity, migration というフォルダが出来て、ルートに index.ts ファイルが生成されます(上書きされます)。
tsconfig.json の修正
tsconfig.json が typeorm の初期化によって修正されるので、再設定を行います。自分の環境では、 src フォルダにソースコード類を配置して、 build フォルダに生成物が配置されるようにしたいので、以下の設定をおこなっています。
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"sourceMap": true,
"outDir": "./build",
"strict": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
},
"include": [
"src/**/*.ts"
]
}
typeorm がデコレーターを使用するため、それらの設定も ON です。
ormconfig.json の修正
まずはデータベースの設定をします。ここでは sqlite3 の設定の例です。
{
"type": "sqlite",
"database": "database.sqlite",
"synchronize": true,
"logging": false,
続いてソースコード類の設定ですが、以下のように設定します。
それぞれトランスパイルされた先の js ファイルを参照するように設定を変更します(デフォルトでは *.ts で、 src フォルダ以下を参照していると思います)
"entities": [
"build/entity/**/*.js"
],
"migrations": [
"build/migration/**/*.js"
],
"subscribers": [
"build/subscriber/**/*.js"
],
"cli": {
"entitiesDir": "src/entity",
"migrationsDir": "src/migration",
"subscribersDir": "src/subscriber"
}
}
このようにトランスパイル先のフォルダを指定しない場合、以下のエラーメッセージが実行時に出力されます
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
^^^^^^
SyntaxError: Cannot use import statement outside a module
上記の内容は entity の部分を修正すると解決できますが、 typeorm migration を使っていくためには他の部分も修正が必要になります。
typeorm migration の実行
デフォルトで生成されたモデルらをベースにデータベースの準備をします。まずは TypeScript のコードをコンパイル(トランスパイル)して、 js コードを出力しておきましょう。そのあとで、typeorm migration:create で生成スクリプトを準備します。
npx tsc
npx typeorm migration:create -n Initialize
この後で migration:run コマンドを実行します。正常に実行できたでしょうか。エラーが出る場合には今までの設定を見直すか、もしかすると TypeScript のトランスパイル時に Lint 警告で引っかかっているのかもしれません。
npx typeorm migration:run
index.ts の準備
Hello,world 的な最初のコードを用意しておきます。このファイルは src/index.ts として作成します。
typeorm で生成されるひな形のコードと、 Hello,world メッセージを出すものとのミックスされたコードになっています。
import express from 'express';
import {createConnection} from "typeorm";
import {User} from "./entity/User";
const app = express();
app.get("/", (req: express.Request, res: express.Response) => {
res.send("Hello,world");
});
createConnection().then(async connection => {
console.log("Inserting a new user into the database...");
const user = new User();
user.firstName = "Timber";
user.lastName = "Saw";
user.age = 25;
await connection.manager.save(user);
console.log("Saved a new user with id: " + user.id);
console.log("Loading users from the database...");
const users = await connection.manager.find(User);
console.log("Loaded users: ", users);
console.log("Here you can setup and run express/koa/any other framework.");
}).catch(error => console.log(error));
app.listen(3000, () => console.log("Startup"));
このコードを実行すると、データベースに設定したユーザーのエントリができます。
また、 http://localhost:3000/ にアクセスすると、 Hello,world という文字列が返ってくるものになっています。
VSCode のデバッグの設定
VSCode を用いているので F5 ボタン押下によるデバッグ開始をしたいですね。その設定をします。
launch.json の設定は次の通りです。program にはトランスパイル後の index.js ファイルを指定するのがポイントです。そのため、事前にトランスパイルされるようにタスク “tsc’ を構築します。
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"preLaunchTask": "tsc",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\build\\index.js",
"outFiles": [
"${workspaceFolder}/**/*.js"
],
"smartStep": true
}
]
}
タスクとしての tsc は以下のように tasks.json で準備しています。
{
"version": "2.0.0",
"tasks": [
{
"type":"typescript",
"label": "tsc",
"tsconfig": "tsconfig.json",
"problemMatcher":[
"$tsc"
]
}
]
}
これによって、F5 で実行するときには事前に tsc コマンドによるトランスパイルが実行され、ソースマップを参照しつつデバッグを行う、ということを実現しています。
ts-node というトランスパイルなしで実行する方法もあるようなのですが、これと typeorm を組み合わせてうまく開発環境の構築をすることが出来ませんでした。そのため、事前にトランスパイルを必須のタスクとしています。
おまけ
Express + typeorm でデータベースをアクセス出来るようになるので、バックエンドAPIを実現するくらいならこれで始められるのですが、Web のページも一緒にホスト・サーブしてほしいとなると、もうちょっと準備が必要です。
ということで、静的なファイルを配置してそれをサーブする部分を、このひな形に追加してみます。
build/static フォルダを作成し、ここに html などの静的なファイルを配置します。気持ちとしては src 以下や、src フォルダと平行して static を配置したいところではありますが、適切に処理する方法が思いつかなかったため、このようにしています。
今は build/static/sample.html などと配置しておきます。
index.ts ファイルを次のように編集して、 static フォルダの設定を行います。
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'static')));
編集した後でプログラムを実行して、 http://localhost:3000/sample.html へアクセスしてみて、ファイルが表示されれば成功です。
まとめ
TypeScript + Express + Typeorm で、VSCode を使って開発していくための初期設定を説明しました。ひとまず自分はこれで開発を進めていくつもりです。主に勉強用ですが、同じように苦戦している人の参考情報になればと思います。
Express でデータベース(ORマッパー) となると、 Sequelize が大変有名なようですが、 TypeScript との組み合わせがちょっと手間取りそうだったので選択から外しました。