TypeScriptを用いたサーバーサイドの開発で、ORMとしてTypeORMを使っている人も多いと思います。TypeORMはモデルを設定ファイルや環境変数で指定されたパスから動的に読み込むことから、ts-nodeやts-node-devなどでTypeScriptのまま動かす場合とtscでJavaScriptにトランスパイルしてから動かす場合で、パスに差異が出て困ることがあります。
問題となるケース
ormconfig.js
に設定を書く運用の場合を考えます。最初は公式ドキュメントを真似して以下のように書いていました。
module.exports = [{
name: 'default',
type: 'mysql',
host: process.env.MYSQL_SERVER,
port: process.env.MYSQL_PORT,
username: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
synchronize: true,
logging: false,
entities: ['src/entity/**/*.ts'],
migrations: ['src/migration/**/*.ts'],
subscribers: ['src/subscriber/**/*.ts']
}];
開発中はずっとts-node-devでTypeScriptのまま動かしていたのでこれで何の問題もなかったのですが、いざ本番環境向けにtscでトランスパイルしてみると、Repository Not Foundとかで全然動かない。
原因はすぐ察しがつく通り、entities
やmigrations
やsubscribers
の指定が拡張子.ts
になっていること。トランスパイル後は.js
になるので、TypeORMはモデルを読み込むことができません。またtsconfig.json
の内容次第ではディレクトリ構成も変わったりすることもあり得ます。
解決策
本番運用をts-nodeにする
正直これが一番手っ取り早い気がしています。起動さえしてしまえばトランスパイルする場合とパフォーマンスに大差はないという話もありますし。一応、今回の本題はこれではありません。
ormconfig.jsの設定値を実行環境に応じて切り換える
こっちが本題です。まず、ormconfig.js
をこんな感じにします。
const commonConfig = {
name: 'default',
type: 'mysql',
host: process.env.MYSQL_SERVER,
port: process.env.MYSQL_PORT,
username: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
synchronize: true,
logging: false
};
const tsConfig = {
entities: ['src/entity/**/*.ts'],
migrations: ['src/migration/**/*.ts'],
subscribers: ['src/subscriber/**/*.ts']
};
const jsConfig = {
entities: ['dist/entity/**/*.js'],
migrations: ['dist/migration/**/*.js'],
subscribers: ['dist/subscriber/**/*.js']
}
if (process.env.TS_NODE) {
module.exports = [{...commonConfig, ...tsConfig}];
} else {
module.exports = [{...commonConfig, ...jsConfig}];
}
package.json
のscripts
をこうします。
"scripts": {
"dev": "TS_NODE=true ts-node ./src/index.ts",
"dev:watch": "TS_NODE=true ts-node-dev ./src/index.ts",
"build": "npm-run-all clean tsc",
"clean": "rimraf dist/*",
"tsc": "tsc",
"start": "TS_NODE= node ./dist/index.js"
},
ts-nodeやts-node-devで動かす場合はTS_NODE
に適当な値を設定して、nodeで動かす場合はTS_NODE
を空にします。ormconfig.js
ではTS_NODE
を見てモデルのロードパスを切り換えます。
ormconfig
はJSONやYAMLなどで書くこともできますが、その場合ロジックが書けないのでJavaScriptで書く方が何かと便利です。
これを応用すると、例えば開発・ステージング・本番でDB周りの設定値を切り換えるといったことも比較的シンプルに実現できます。