Firebase Hosting + Cloud Run で、Cloud Run が実行されない

Firebase Hosting で、特定のURLを Cloud Run で実行させるように rewrites の設定をした。
一回目は期待通りに Cloud Run が実行されるが、二回目以降は Cloud Run が実行されない(Response は、一回目と同じになる)。

調べてみると、Firebase Hosting の手前のCDNがキャッシュして応答を返すみたいです。
ここ参照。

Cloud Run 側のプログラムでも対応出来るようですが、Response に毎回設定するのも面倒なので、
Hosting の設定(firebase.json)に↓のように記載しました。

    {
      ・・・
      "rewrites": [
        {
          "source": "/**",
          "run": {
            "region": "xxxxx",
            "serviceId": "xxxxx"
          }
        }
      ],
      "headers": [{
        "source": "/**",
        "headers": [{
          "key": "Cache-Control",
          "value": "no-store"
        }]
      }]
    }

Firebase Functions ではキャッシュされないので少しハマりました。

Firebase に CI でデプロイする

CircleCI とか GitHub の actions (Workflows) で Firebase へのデプロイを設定する場合は token が必要になる。
token は↓で取得できる。

$ firebase login:ci

で、CIの設定は GitHub の actions ならこんな感じ。
※リポジトリ > Settings > Secrets から↑で取得した token 、デプロイ先のプロジェクトIDを追加しておく。

name: Deploy CI

on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: "12.x"
      - name: Install firebase cli
        run: npm install -g firebase-tools
      - name: Deploy
        run: firebase deploy --project ${{ secrets.FIREBASE_PROJECT_ID }} --token ${{ secrets.FIREBASE_TOKEN }}

Firestore でデータ削除

Webクライアント側でFirestoreのドキュメントを削除するときに、ドキュメントに紐づくコレクションが存在すると、コレクションが残る。
FirebaseのWebコンソールから確認すると削除したドキュメントは斜体になった状態で、下層のコレクションは普通に存在する。

Webクライアント側で丁寧に紐づくコレクションを削除するのも手ですが、データが多い場合などで完全に削除して良ければ、Firebase の Functions で削除可能です。
Functions で削除すると下層のコレクションもまるっと削除できます。

Functions は WebAPI として作るか、あるいは Firestore を拡張すると良いと思います。
私は後者の方が好みです。こんな感じでしょうか?

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import * as tools from "firebase-tools";

const deleteXxxx = async (
  snap: FirebaseFirestore.DocumentSnapshot,
  context: functions.EventContext
) => {
  await tools.firestore.delete(snap.ref.path, {
    project: process.env.GCLOUD_PROJECT,
    recursive: true,
    yes: true
  });

  return "OK";
};

export const firestoreDeleteXxxx = functions.firestore
  .document("xxxx/{deleteId}")
  .onDelete((snap, context) => {
    return deleteXxxx(snap, context);
  });

ReactでMaterial-UIを使ってみる

インストール

$ yarn add @material-ui/core
$ yarn add @material-ui/icons

全体のテーマを整える

src/assets/theme.ts

import indigo from "@material-ui/core/colors/indigo";
import pink from "@material-ui/core/colors/pink";
import red from "@material-ui/core/colors/red";
import { createMuiTheme } from "@material-ui/core/styles";

const theme = createMuiTheme({
  palette: {
    primary: pink,
    secondary: indigo
  }
});

export default theme;

上書きできる設定は これ

src/index.tsx

import { MuiThemeProvider } from "@material-ui/core";
import theme from "./assets/theme";

ReactDOM.render(
  <MuiThemeProvider theme={theme}>
    <App />
  </MuiThemeProvider>,
  document.getElementById("root")
);

使ってみる

import Button from "@material-ui/core/Button";
import AccessAlarmIcon from "@material-ui/icons/AccessAlarm";
・・・
  <Button variant="contained" color="primary">
    <AccessAlarmIcon />
    Hello
  </Button>
・・・

color="primary"と指定して、青かったボタンが、

ピンクに表示される。

React を勉強するにあたり

今までクライアントサイドを実装のため Vue.js を勉強してきたが、仕事の関係上 React も勉強していかないと。。。

で、React でアプリケーションを実際組むのに必要そうな情報をまとめてみる。

古いXcodeに、新しいiOSがインストールされた実機を接続してインストール

依存しているライブラリの関係など、古いバージョンのXcodeでiOSアプリを開発しています。
ただ、iOSがアップデートされると実機へのインストール時に対応していないとエラーになります。
“iOS 12 not supported by Xcode 9.2 : Could not locate device support files”
のようなエラーです。

そんな時の対応方法です。

古いXcodeと最新のXcodeが共存している前提です。
Finderから最新のXcodeを右クリックして”パッケージの内容を表示”から下記ディレクトリに移動します。
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

同様に古いバージョンのXcodeから同じディレクトリを表示して、必要なiOSバージョンのディレクトリをコピーすれば、
新しいiOSの実機にもXcodeからインストールできます。

Android で versionName, versionCode を取得

Android で build.gradle に設定した versionName, versionCode をプログラムで取得する。

        PackageManager pm = context.getPackageManager();
        String versionName = "";
        Integer versionCode = null;
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            versionName = packageInfo.versionName;
            versionCode = packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            //
        }

Android の ActionBar に画像を表示

ActionBar にオリジナルのレイアウトを適用し画像を表示する。

action_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp">

    <ImageView
        android:id="@+id/logo_action_bar"
        android:layout_width="match_parent"
        android:layout_height="32dp"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="8dp"
        android:scaleType="fitStart"
        android:src="@drawable/logo_action_bar"/>

</RelativeLayout>

Activityで適用

public class XxxActivity extends AppCompatActivity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ・・・

        // 表示するlayoutファイルの取得
        LayoutInflater inflater = LayoutInflater.from(this);
        View actionBarView = inflater.inflate(R.layout.action_bar, null);

        // プログラムでオリジナル画像を設定するなら下記
        // ((ImageView)actionBarView.findViewById(R.id.logo_action_bar)).setImageDrawable(getDrawable(R.drawable.xxxx));

        ActionBar actionBar = getSupportActionBar();
        actionBar.setCustomView(actionBarView);
        actionBar.setDisplayShowCustomEnabled(true);