🤷

Cloud FunctionsでLintは後から設定する

2023/01/28に公開

自動設定は制約が厳しい!

Cloud FunctionsをTypeScriptで使ったときに、ESLint入れるとエラー連発して、結構ハマりました。難しすぎる😱
初心者向けに、制約を緩くしてESLintとprettierを設定します。

  • どうやるのか?
    • 最初から入れない.
    • 後から追加する.

私がやった設定

Cloud FunctionsをESLintなしで、環境構築した後に、このような設定をしました。

ESLint、Prettierを設定する

  1. ターミナルからfunctionsディレクトリに移動する.
cd functions
  1. eslintをinstallするコマンドを実行する.
npm init @eslint/config
  1. Prettierをinstallする.
npm i prettier
  1. functionsディレクトリに[.prettierrc]ファイルを作成する.
touch functions/.prettierrc
  1. eslintrc.jsを設定する.
    ;と""つけないと、エラー出すよ!って設定です。
module.exports = {
    "env": {
        "browser": true,
        "es2021": true
    },
    "overrides": [
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint"
    ],
    "rules": {
        "semi": ["error", "always"],
        "quotes": ["error", "double"]
    }
};
  1. prettierの設定
    タブが2行で、;と""つけてねって設定です。
{
  "tabWidth": 2,
  "semi": true,
  "doubleQuote": true
}

Firebaseを操作するコード

Firebaseのコンソールで操作をして動作を検証したコード。配列に、any型しか型定義できないのが、悩みですね。(string|number)と書いたら、エラー吐かれる!

index.ts
// Cloud Functions for Firebase SDKでCloud Functionsを作成し、トリガーを設定します。
import * as functions from "firebase-functions";
// FirestoreにアクセスするためのFirebase Admin SDKです。
import * as admin from "firebase-admin";
admin.initializeApp();
// Firestoreのインスタンスを取得。
const db = admin.firestore();

// 注文をするとショッピングカートに購入履歴が作成されるトリガー関数.
exports.createOrder = functions.firestore.document("orders/{orderID}").onCreate(async (snap, context) => {
  const newValue = snap.data();

  await db.collection("shoppingCart").add({
    name: `購入者の名前: ${newValue.name}`,
    goods: `購入した商品: ${newValue.goods}`,
    price: `購入した商品の価格: ${newValue.price}`,
    count: `購入した商品の数: ${newValue.count}`,
  });
});

// 注文を更新するとショッピングカートの購入履歴を更新するトリガー関数
exports.updateOrder = functions.firestore.document("orders/{orderID}").onUpdate(async(snap, context) => {
  const newValue = snap.after.data();

  const updatePromisse: any[] = [];

  const snapshot = await db.collection("shoppingCart").get();

  snapshot.forEach(doc => {
    updatePromisse.push(db.collection("shoppingCart").doc(doc.id).update({
      name: `購入者の名前: ${newValue.name}`,
      goods: `購入した商品: ${newValue.goods}`,
      price: `購入した商品の価格: ${newValue.price}`,
      count: `購入した商品の数: ${newValue.count}`,
    }));
  });
  await Promise.all(updatePromisse);
});

// 注文が削除されたら、ショッピングカートの購入履歴を削除するトリガー関数
exports.deleteOrder = functions.firestore.document("orders/{orderID}").onDelete(async(sanp, context) => {

  const deletePromise: any[] = [];

  const snapshot = await db.collection("shoppingCart").get();

  snapshot.forEach(doc => {
    deletePromise.push(db.collection("shoppingCart").doc(doc.id).delete());
  });
  await Promise.all(deletePromise);
});

// -----------------------------
// 退会テスト
// ユーザーが新規登録されたら、usersコレクションにメールの情報が保存されるトリガー関数
exports.sendWelcomeEmail = functions.auth.user().onCreate(async (user) => {
  await db.collection("users").add({
    email: user.email,
  });
});

// userが削除されたら、userコレクションを削除するトリガー関数
exports.sendByeEmail = functions.auth.user().onDelete(async (user) => {
  const deletePromise: any[] = [];

  const snapshot = await db.collection("users").get();

  snapshot.forEach(doc => {
    deletePromise.push(db.collection("users").doc(doc.id).delete());
  });
  await Promise.all(deletePromise);
});

// 削除するユーザーを登録するコレクションが作成されたら、FirebaseAuthenticatonのユーザーデータを削除する.
// リージョンは、asia-northeast1を設定。自分の設定したリージョンに合わせる。
exports.deleteUser = functions.region("asia-northeast1").firestore.document("deleted_users/{docId}").onCreate(async (snap, context) => {
  const deleteDocument = snap.data();
  const uid = deleteDocument.uid;

  await admin.auth().deleteUser(uid);
});

まとめ

DefaultのESLint使うと、謎のコメントをつけないとエラー消えなかったりして、結構悩まされました。Lintの設定は、規則がなければ、ゆる〜くしたいですね。

Discussion