Help us understand the problem. What is going on with this article?

Firebase Functions + TypeScriptをparcelで事前ビルドしてやりすごす

Firebase functionsは現在標準でTypeScriptに対応している。
しかしHostingなど他の機能も使いたい場合や、それらとモジュールを共有したい場合、tsconfigやpackage.jsonが複数のディレクトリに割れたりしてちょっとしんどくなる。
この場合lernaなどでmonorepo構成を取るのが良いのだろうが、TypeScriptが絡んだりするとなかなかまだハマりどころが少なく無く面倒になりがちだ。

そこで以前AWS Lambda向けのファイルをparcelでビルドしたのと似たようなことをやってみたら思ったより悪くなかったのでまとめておく。

1. 準備

まずは適当にディレクトリを作るとこから

$ mkdir some-firebase-project
$ cd some-firebase-project
$ yarn init -y
$ touch firebase.json

parcelとtypescriptも入れてしまおう

$ yarn add parcel typescript
$ yarn tsc --init

あと今回はfirebase initは使わないのでそこは自前で行う

$ mkdir functions
$ touch functions/package.json

2. package install

次にプロジェクト直下でパッケージインストール。トップディレクトリでfunctionsに必要なパッケージを入れる。最終的にbundleしたものをアップするのでpeerDependencyも入れる

$ yarn add firebase-admin @firebase/database @firebase/app @firebase/app-types @firebase/database-types firebase-tools

3. functionファイルの用意

function本体となるファイルを配置する。

$ mkdir src
$ mkdir src/functions
// src/functions/index.ts
import * as functions from "firebase-functions" // 全インポートにしないとひっかかるっぽい

exports.helloWorld = functions.https.onRequest((request, response) => {
  response.send("Hello from Firebase!")
})

4. スクリプト設定(本題)

package.jsonをこんな感じで設定

{
  "scripts": {
    "build:functions": "parcel build src/functions/index.ts --target=node -d functions -o index.js --bundle-node-modules --no-source-maps --no-minify",

だいたいAWS Lamdaの場合と一緒で、--target=node--bundle-node-modulesにしている。
またfirebase-admin関連がsourcemap関連のwarningを吐き出してくるので--no-source-mapsを付けている。
また吐き出し先を-d functionsでfunctions下にしている。

--no-minifyをしてるのはビルド速度を上げたい&サーバーサイドのスクリプトなのでminifyする意味あんまり感じない&デバッグ楽そう ぐらいな気持ちなので好みで決めていい

これでyarn build:functionsが出来た。

4.5. Cannot resolve dependency 'http2' の対策をする

本当はここまでで通るはずなのだが、そのまま実行するとCannot resolve dependency 'http2'のエラーが出る事がある。
どうもparcelの問題として、http2モジュールをうまく読み込めずビルドが失敗する状態にあるようだ

https://github.com/parcel-bundler/parcel/issues/2921

ということでその場合は下記のようにhttp2パッケージをインストールしてしまえば解決する

$ yarn add http2

5. firebase.jsonの準備

次にfirebase.jsonを記述する。だいたいこんな感じ。predeployで指定を与える部分が重要

{
  "functions": {
    "source": "functions",
    "predeploy": "yarn build:functions"
  },
  "hosting": {
    ... 
  }
}

6. functions/package.jsonをいじる

AWS Lambdaと違ってpackage.jsonが無いとdeploy時に失敗してしまうので、これを回避するためにpackage.jsonを置いとく。
バージョンは10にしておく。今回はparcel側で--bundle-node-modulesするやり方をとっているのでdependenciesは不要だ。

functions/package.json
{
  "name": "functions",
  "engines": {
    "node": "10"
  },
  "main": "index.js",
  "private": true
}

7. gitignoreする(オプション)

細かいがgitignoreとしてfunctions/index.jsを追加しておくと良い。

functions/index.js
dist

好みでなければ吐き出し先をfunctions/lib/などディレクトリ先にしてそこごとignoreするのも良いだろう。

8. deploy

レッツデプロイ。

$ firebase deploy --only functions

おまけ: hostingがここに入った場合

hositngが入るとこんな具合のディレクトリ構成になる。

.
├── dist # hostingの出力先
│   ├── hosting.09bd9689.js
│   └── index.html
├── functions # functionsの出力先
│   ├── index.js
│   └── package.json
├── src
│   ├── functions # functionsのソース
│   │   └── index.ts
│   ├── hosting # hostingのソース
│   │   ├── index.html
│   │   └── index.tsx
│   └── lib # 共通部分
│       └── database-client.ts
├── firebase.json
├── package.json
├── renovate.json
├── tsconfig.json
└── yarn.lock

firebase.jsonとpackage.jsonはこんな感じになる

package.json
  "script": {
    "build": "parcel build src/index.html",
      ...

firebase.json
  "hosting": {
    "public": "dist",
    "predeploy": "yarn build",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした