8/5/2022
Firebase Functionsで絶対パスでimportする
FirebaseでCloud Functionsを使うときに相対パスでimportさせられる問題をBabelで解決しました
Webpackで解決している人は見かけた(*1, *2)のですが、Babelでやっている人は見かけなかったので書いてみました
ゴール
メンヘラせんぱいはFirebaseで動いており、サーバー側で行いたい処理はFirebase Functionsを使っています
最近Functionsのディレクトリ構成を見直したくなったのですが、すべて相対パスでimportしていたため、簡単にディレクトリ間を移動できませんでした。階層が深いと ../
がかなり多くなって見栄えも悪いです
import { triggerOnce } from '../../utils/triggerOnce'
aliasをはり、↓のようにルートから @
で絶対パスでimportできるようにすることがゴールです
import { triggerOnce } from '@/utils/triggerOnce'
相対importのとき
FirebaseでFunctionsを使うときにプロジェクトを作成するとまず次のようなディレクトリ構成になると思います
functions
├── node_modules
├── src
├── index.js
├── package.json
└── tsconfig.json
そして型定義やリポジトリ層を用意すると、弊社ではこのようなディレクトリ構成になりました
functions
├── node_modules
├── src
│ ├── batches
│ ├── entities
│ ├── plugins
│ ├── repositories
│ ├── triggers
│ └── utils
├── package.json
└── tsconfig.json
そしてこれらをimportしようとした結果、次のようなコードになります
import * as admin from 'firebase-admin'
import * as functions from 'firebase-functions'
import { db, serverTimestamp } from '../../firestore'
import HogeRepository from '../../repositories/HogeRepository'
import { triggerOnce } from '../../utils/triggerOnce'
この大量の ../ を消します
原因
ということで絶対パスを使いたいのですが、ただtsconfig.jsonにpathsを設定するだけではうまくいきません
Firebase Functionsではビルドにtscを使っているのですが、tscがaliasを解釈してくれず、ビルド時にパスが自動で変換されないことが原因です
絶対pathを使えるようにする
解決策としては、tscをやめてWebpackやBabelで解決します
今回はBabelを使うことにしました。WebpackではなくBabelを選ぶ理由としては、弊社のテックリード(@remew)の言葉を借りると、
・webpackはバンドラーで、babelはASTレベルの変換のために使うというイメージ
・webpackで解決できるのはバンドルする仮定でimportのパスを解決する必要があるから結果的に問題が解決できる
・今回はバンドルしたいわけじゃないのにwebpack入れるのもびみょい
からとのことです
作業
それでは実装に入ります
まず必要なライブラリをnpm installしていきます
$ npm install --save-dev @babel/cli @babel/core @babel/preset-env @babel/preset-typescript babel-plugin-module-resolver
babel.config.jsで ./src
に @
というaliasをはります
// babel.config.js
module.exports = {
presets: [
[
'@babel/env',
{
targets: {
node: '10.0'
}
}
],
'@babel/typescript'
],
plugins: [
[
'module-resolver',
{
root: ['.'],
alias: {
'@': './src'
}
}
]
]
}
次にtsconfig.json側にもaliasを設定します
// tsconfig.json
{
...,
"paths": {
"@/*": ["./src/*"],
"@": ["./src"],
},
}
もしtslintでno-implicit-dependenciesで怒られていたら @
からのimportではoffにするように設定しておきましょう
最後にデプロイコマンドを書き換えます
// package.json
{
...,
"build": "tsc --noEmit && babel src -d lib --extensions .ts",
}
これでデプロイできました🎉
さいごに
今回はBabelを使ってFirebase Functionsで絶対パスでimportできるようにしました