yn2011's blog

技術メモ

img 要素に width と height を指定してもレイアウトシフトする原因は属性値が auto だからかも

環境

tldr;

img 要素に width と height を指定するとレイアウトシフトしないと聞いて試してみたが、レイアウトシフトが改善しないケースがあった。img 要素の width と height に auto を指定していて画像を読み込むまで幅を決定できない場合にレイアウトシフトが発生する。

width と height でレイアウトシフトを防ぐ

以下の HTML をブラウザで描画するとレイアウトシフトが発生する

<img src="https://via.placeholder.com/1200x600" />
<p>text</p>

画像が後から読み込まれ、text が下に移動する。

以下の場合はレイアウトシフトしない。ブラウザがアスペクト比を理解するからである。この例では実際の画像の幅と属性値が一致するが、一致していない場合でも width と height の属性値で描画を決定できるのでレイアウトシフトは回避できる。

<img src="https://via.placeholder.com/1200x600" width="1200" height="600" />
<p>text</p>

詳細な説明は以下を参照

width:auto と height:auto を組み合わせるとレイアウトシフトする

属性値でアスペクト比を伝えている場合でも、以下のスタイルを当てるとレイアウトシフトが発生する。

.image {
  width: auto;
  height: auto;
}
<img src="https://via.placeholder.com/1200x600" width="1200" height="600" class="image" />
<p>text</p>

これは、width と height 属性を HTML で指定していたとしても、CSS で値を auto にすると画像が読み込まれるまで幅と高さを解決できないからだと考えられる。

例えば、以下のように width と height を 200 に指定したとしても、auto のスタイルを当てている場合には無視されて実際の画像の大きさ(1200*600) で描画される。

 <img src="https://via.placeholder.com/1200x600" width="200" height="200" class="image" />

なのでブラウザは画像が読み込まれた後にレイアウトシフトを発生させるしかない。

片方だけ auto の場合はレイアウトシフトしない

width と height で片方が auto の場合は、属性値とアスペクト比から片方を事前に計算可能なのでレイアウトシフトを回避できる。ただし、画像の実際のアスペクト比と、width と height から計算するアスペクト比が一致していることは前提である。

これはOK

.image {
  width: auto;
}

これもOK

.image {
  height: auto;
}

これも大丈夫

.image {
  width: 100%;
  height: auto;
}

img 要素に指定した width と height から計算されるアスペクト比と、実際の画像のアスペクト比が一致しない場合

img 要素に指定した width と height から計算されるアスペクト比と、実際の画像のアスペクト比が一致しない場合でも片方が auto であれば画像が持つ正しいアスペクト比で幅を算出してくれる。

例えば、これはアスペクト比が 1 / 1 だと認識されそうだが

 <img src="https://via.placeholder.com/1200x600" width="200" height="200" class="image" />

height を auto にしている場合は、画像を読み込んだ後に本来のアスペクト比を利用して height = width / 2 で 100 としてブラウザは表示してくれる。

しかし、本来の画像のアスペクト比は画像をブラウザが読み込むまでは解決できないはずであるため、読み込み後にレイアウトシフトは発生する。この場合のレイアウトシフトは先に height=200 で確保した縦幅が 最終的に 100 になるので下から上へと要素が移動することになる。

逆に、上記の例で width を auto にした場合は(少なくとも上下の)レイアウトシフトは発生しない。画像の本来のアスペクト比が何であれ、高さが 200 であるということは変わらないからだ。左右に要素が存在する場合には横幅が画像を読み込んだ後に決定されるのでレイアウトシフトするはずだ。

疑問

CSS の width と height は初期値が auto なのに、CSS で明示する場合としない場合で挙動が変わるのはなぜ?

参考

(Android) Expo Bare workflow に Firebase Crashlytics を導入する

Firebase Crashlytics を使うとアプリがクラッシュした際にエラーレポートを送信することができる。

iOS に導入する手順は(iOS) Expo Bare workflow に Firebase Crashlytics を導入する に以前書いた。今回は Android アプリに Firebase Crashlytics を導入する手順について書く。

環境

  • Expo SDK 44
  • custom development client 利用
  • Firebase コンソールからアプリを登録済み
  • Android Studio (Emulator) でアプリを起動

パッケージインストール

公式ドキュメントの手順通りにパッケージをインストールする。Firebase のサービス自体を初めて利用する場合は、@react-native-firebase/app のインストールが必要。

// 未インストールの場合
yarn add @react-native-firebase/app

yarn add @react-native-firebase/crashlytics

Android 向けのセットアップ

iOS では不要だったが、Android のビルド向けに設定が必要。手順は、Crashlytics - Android Setup の 1~4 を参照。

firebase.json を作成する

省略(iOS 導入の記事参照)

テストクラッシュを起こす実装をする

省略(iOS 導入の記事参照)

アプリをビルドし起動する

EAS Build 等を利用してアプリをビルドし Android Emulator で起動する。

正常に Crashlytics がレポート送信を行っていることを確認するため、Android Studio でログを表示する。ログの表示方法は、logcat を使用してログを書き込み、表示するを参照。

クラッシュを発生させる

自分の環境だと、crashlytics().crash() ではレポートを送信することができなかった。クラッシュを実行すると以下の画面が表示される。

f:id:pokuwagata:20220220150633p:plain

ログは以下になる。

2022-02-08 18:31:04.712 14816-15028/appId E/DevLauncher: DevLauncher tries to handle uncaught exception.
    java.lang.RuntimeException: Crash Test
        at io.invertase.firebase.crashlytics.ReactNativeFirebaseCrashlyticsModule$1.run(ReactNativeFirebaseCrashlyticsModule.java:83)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
        at java.lang.Thread.run(Thread.java:923)

どうやら先にエラーをキャッチされてしまっているようである。

一方で、JS エラー(throw new Error()) を起こした場合は以下のログが表示されアプリはクラッシュした。

2022-02-08 18:52:44.727 16610-16947/appId D/RNFBCrashlyticsInit: isCrashlyticsCollectionEnabled final value: true
2022-02-08 18:52:44.738 16610-16947/appId E/Crashlytics: Crash logged. Terminating app.

アプリを再起動して少し待つと、Firebase コンソールからは以下のようなレポートを閲覧できる。(なお、JS エラーをレポート送信するかどうかは firebase.json で設定可能)

f:id:pokuwagata:20220220151138p:plain

まとめ

Expo Bare workflow を利用した Android アプリに Firebase Crashlytics を導入する手順を書いた。

development client を利用していると、ネイティブコードのエラーを正常にレポート送信することはできなかった。stand alone にビルドしていればクラッシュすると思うので正常にレポート送信は行われるのではないかと予想している。この点については今後検証したい。

(iOS) Expo Bare workflow に Firebase Crashlytics を導入する

Firebase Crashlytics を使うとアプリがクラッシュした際にエラーレポートを送信することができる。Expo Bare workflow のプロジェクトに Firebase Crashlytics を導入する手順について書く。

環境

  • Expo SDK 44
  • Firebase コンソールからアプリを登録済み
  • iOS シミュレータビルドで検証

パッケージインストール

公式ドキュメントの手順通りにパッケージをインストールする。Firebase のサービス自体を初めて利用する場合は、@react-native-firebase/app のインストールが必要。

// 未インストールの場合
yarn add @react-native-firebase/app

yarn add @react-native-firebase/crashlytics

cd ios/ && pod install

最終的に EAS build するとしても Podfile.lock の更新のため pod install は必要だと思う(多分)

firebase.json を作成する

プロジェクトディレクトリの直下に、firebase.json を作成する。今回は疎通確認のため以下の設定値を有効にする。

ネイティブコードではなく、React Native で実行した JavaScript のエラーもレポート送信の対象にしている。

{
  "react-native": {
    "crashlytics_debug_enabled": true,
    "crashlytics_auto_collection_enabled": true,
    "crashlytics_is_error_generation_on_js_crash_enabled": true,
    "crashlytics_javascript_exception_handler_chaining_enabled": true
  }
}

設定値のリファレンスは Firebase JSON Config を参照。

テストクラッシュを起こす実装をする

crashlytics().crash() を実行するとネイティブ領域でエラーを発生させアプリをクラッシュさせることができる。

<Button title="Test Crash" onPress={() => crashlytics().crash()} />

以下のような JS Error でも良い。

<Button title="Test Crash" onPress={() => throw new Error("test")} />

アプリをビルドしシミュレータで起動する

アプリをビルドし iOS シミュレータにインストールする。

デバッグ用に iOS シミュレータのログを確認できるようにしておく。

$ xcrun simctl spawn booted log stream --level debug --style compact | grep -i crash

crash で grep し、Crashlytics 関連のログのみが表示されるようにする。

以下のようにfirebase.json の設定値がログに出力されていればOK

2022-02-03 17:08:16.938 Df appName[63895:42a438] +[RNFBSharedUtils getConfigBooleanValue:key:defaultValue:] [Line 160] RNFBCrashlyticsInit crashlytics_auto_collection_enabled final value: 1

テストクラッシュ用に実装したボタンを押下するとアプリがクラッシュする。

再度アプリを起動すると以下のようなログが出力される。

2022-02-03 17:14:22.300 Df appName[64062:42b7c7] +[RNFBCrashlyticsInitProvider configureWithApp:] [Line 101] RNFBCrashlyticsInit initialization successful
2022-02-03 17:14:23.192 Df appName[64062:42b7d5] [com.apple.network:connection] [C6 4F05B069-6BF2-442B-9434-CF5F0223CBF1 crashlyticsreports-pa.googleapis.com:443 tcp, url hash: 668ea868, tls, definite, attribution: developer, context: com.apple.CFNetwork.NSURLSession.{4F3F6DE6-21E5-4E1C-8B27-6043E5450330}{(null)}{Y}{2} (private), proc: EA95ADB9-AD35-39EC-BB62-880027AC07B2] start
2022-02-03 17:14:23.192 I  appName[64062:42b7d5] [com.apple.network:connection] nw_endpoint_handler_start [C6 crashlyticsreports-pa.googleapis.com:443 initial path ((null))]

Crashlytics の初期化成功後に、ネットワーク通信が始まりレポート送信が行われる。アプリがクラッシュしたタイミングではなく、クラッシュ後にアプリを起動しないとレポートは送信されないことに注意。

Firebase コンソールでレポートを確認する

f:id:pokuwagata:20220212120955p:plain

送信したレポートを閲覧できていれば Firebase Crashlytics の導入に成功している。

crashlytics().setUserId(id) によってユーザの識別子を付与してレポートを送信することも可能。

まとめ

Expo Bare workflow を利用した iOS アプリに Firebase Crashlytics を導入する手順を書いた。

Bare workflow の Android の場合はパッケージインストール以外にも追加で build.gradle を編集する必要があるが、iOS の場合は比較的ラクに導入できると思う。

手元では Android でも既に導入に成功しているので別の記事で手順やハマりポイントを書きたい。

(Android) Expo bare workflow で 環境別に複数の applicationId を使い分ける

公式ドキュメントのExample: configuring development and production variants in a bare projectを参考にやってみたのでメモ。

環境

  • Expo SDK 44
  • bare workflow

applicationId とは

アプリの識別子。

すべての Android アプリには、「com.example.myapp」など、Java パッケージ名に似た一意のアプリケーション ID があります。 https://developer.android.com/studio/build/application-id?hl=ja

Expo manage workflow の app.json に存在する package プロパティはこの applicationId を設定している。また、iOS アプリにも同様の識別子は存在する。

概要

Android アプリのビルドバリアントという仕組みを利用する。環境別(dev, stg, prd...) にビルドバリアントを作成しそれぞれに applicationId を定義する。

ビルドバリアントは、ビルドタイプとプロダクトフレーバーの組合わせである。ビルドタイプが debug/release 、プロダクトフレーバーが dev/prd が存在する場合はビルドバリアントは 4つ存在することになる(dev-debug, prd-debug, ...)

したがって、厳密にはビルドバリアントに applicationId を定義するのではなく、ビルドタイプとプロダクトフレーバーそれぞれに定義している(どちらか片方でもいい)

今回の環境別に異なる applicationId を使い分けるという目的を達成するためには、このプロダクトフレーバーを使う。

build.gradle にプロダクトフレーバーを追加する

Expo の managed workflow から eject すると、/android/app/build.gradle が生成される。このファイルに新しいプロダクトフレーバーを追加する(今回は例として、development と production)

 buildTypes {...} // 省略
 // 以下を追記
 flavorDimensions "env"
    productFlavors {
        production {
            dimension "env"
            applicationId 'com.example.myapp'
        }
        development {
            dimension "env"
            applicationId 'com.example.myapp.dev'
        }
    }

ビルドバリアントを指定してビルドする

expo run:android の場合

expo run:android コマンドは --variant オプションを受け取ることができるので、ビルドバリアントを指定する。

ビルドバリアントは、ビルドフレーバーが development, ビルドタイプが debug の場合は以下のように指定ができる(ビルドタイプは大文字から始めることに注意)

expo run:android --variant developmentDebug

これで指定したビルドバリアントの applicationId を持つアプリをビルドできた。

EAS build の場合

ローカル環境で Android のビルドを行うと環境面で躓くことが多いので、自分は EAS build することの方が多い。

EAS build の場合は、eas.jsongradleCommand というプロパティを使ってビルドバリアントの指定を行う。

コマンドの書式は、(assemble|bundle)FlavorBuildType となっている。 assemble を指定すると、ビルドファイルの拡張子が.apk になり、bundle の場合は .aab になった。この辺の技術的な違いはよく分からない。 ビルドフレーバーとビルドタイプを大文字から始めることに注意(Upper Camel)

{
  "cli": {
    "version": ">= 0.35.0"
  },
  "build": {
    "development": {
     ...
      "android": {
        "gradleCommand": ":app:assembleDevelopmentDebug" // dev
      }
    },
    "production": {
      "android": {
        "gradleCommand": ":app:bundleProductionRelease" // prd
      }
    }
  },
  "submit": {
    "production": {}
  }
}

あとは、通常通りにプロファイルを指定して EAS build を開始すれば良い。

eas build --profile development --platform android

ビルドバリアント毎にアプリケーションの名前も変えたい

ホームスクリーン上に表示されるアプリケーションの名前もビルドバリアント毎に変えることができる。

プロダクトフレーバー毎に新しくディレクトリとファイルを作成する。development の場合だと以下になる。

android/app/src/development/res/value/strings.xml

このファイルに以下のように名前定義をする。

<resources>
    <string name="app_name">(dev)app-name</string>
</resources>

参考

2021 年を振り返る

技術

2021 年はプロダクトのグロースや新規構築を通じてずっと Next.js に触れ続けていた年だった。

現職で自分が関わるプロダクトは、事業領域の特性的にも機能要件があまり難しくないことが多い。複雑な状態を持つ SPA を開発しているというよりは、静的ページの自動生成と、静的ページを React で効率よく書くためのフレームワークとして Next.js の SSG を利用しているに過ぎない。それらは公式のドキュメントや過去の別プロダクトのコードベースなどの資産を活用すれば開発自体は難しくはない。一方で toC な感じのデザインをシュッと実装できることが必要で、自分はいわゆる Web 制作の経験がない。ちょっとこれは不味いなということで個人的に色々勉強して、HTML/CSS の知識体系を確立しようとしていた。

単なる知識ではなく、”知識体系”と書いたのは、特に CSS については、イディオムの丸暗記ではなく、なぜこういう動きになるのか? CSS 全体を支配する規則の中でどう説明可能なのか?みたいなことを意識していたからである。まあ分からんことも多いのだけど。

直近では技術調査として Expo (React Native) をよくやっている。もしかすると 2022 年は React Native をやる年になるのかもしれない。

引っ越し

交通の便が良いので駒込に住んでいたが、昨今の時勢や会社の方針としても最低あと 1 年以上は在宅勤務が続きそうと思い郊外へ引っ越すことにした。

2020年に結婚してからも1人暮らし用の部屋に住んでいて手狭だったのと、隣に引っ越してきた外国人の方々が夜間に騒ぎまくるとか色々環境に限界を感じていて、しかも通勤時間を考慮する必要がないなら都内にいる理由がないよねって感じだった。

今は千葉県の柏近辺に住んでいる。都内と比較すると家賃相場は 3~4 万円程度安い印象があり、前より少し高い家賃を払うだけで(前よりは)けっこう広い部屋を借りることができている。

自分は地方出身(青森) だからかもしれないが、都心のコンクリートジャングルよりは空の広い郊外の方が性には合っている気がしていて、なんとなく近所を散歩していても落ち着く感じがある。人も少ないし静かだ。

デスク周り

デスクワークの疲れを軽減したかったので色々揃えてみた。

昇降式デスクを買ったり

MD770 を買ったり

アーロンチェアを買ったり

それなりに出費は嵩んだが、ウォーレン・バフェット氏も言うように自分の身体は交換不可能であり必要経費だと思っている。

読書

今年のいつ頃からか忘れたが、所属部署のシニアマネージャー(@primunu) の企画した読書会(毎日 9:30 ~ 10:00 )に参加させて頂いている。

こう書くと何人も参加しているような印象を受けると思うが、最終的には自分とシニアマネージャー氏だけの 1on1 的な会になっている。毎日と書いたがお互い欠席は自由な感じで週 3 回ぐらいは同時に参加してるかな?という緩い感じ(参加者が自分だけでも読書する)。各自好きに本を読んだり、自分は本を読みながらシェル芸をしたりする時間になっている。

自分は元々通勤時間で読書していたので、在宅勤務が始まった去年はあまり読書していなかったが、今年はこの会によって読書習慣を取り戻している。今年読んだ本の列挙は別記事でやるかもしれない。

今年 1番影響を受けたのはデジタル・ミニマリスト 本当に大切なことに集中する だと思う。これがきっかけで Twitter の利用時間を 1日 15分に制限したり、その他の SNS はアプリを削除したりして安らかな日々を送ることができている。多分。

ちなみに完全な趣味としては、なぜか司馬遼太郎泉鏡花をけっこう読んでいた。

髪が伸びた

外出自粛も叫ばれていた中で、長髪にすれば散髪に行かなくても良いんじゃないか?と思ったのと、何となく憧れがあり伸ばしてみている。しかし短髪だった人が伸ばす場合は放置で済むわけではなく、定期的に散髪で調整しないとマジで変な髪型になってしまう。結局当初の目的は達成できてないけど、まあ在宅勤務で人に会うことも少ないし長髪もありかと思ってまあそんな感じになっている。

筋トレ

通っていたパーソナルジムのトレーナーがお寺で修行をしたいので退職するという事件発生?をきっかけに、ジムを解約し自主トレに移行。金銭的な負担もまあまあ大きかったし、トレーニングや食事について多少は知識と経験が身についたと思う。契約前と比べると体重 +10kg 前後を達成できている。

引越し後から近所のジムを契約して週 1 回を目安に通っている。週 1 だとトレーニングする部位を絞らないと成果がでにくいのと筋トレしてる感が出やすいのが上半身かな、という感じで胸・肩のフリーウェイトをやっている。

平日夜のジムは混雑して嫌なので、18時前には行くようにしている。17時頃の夕会には運動着に着替えた状態で参加して、夕会が終わったら即退勤して家を出る。駒込の近くのジムや体育館は平日 17 時台でも人がそこそこいたりするが、近所のジムはほぼ人がいないので最高。こういう点でも(少なくとも自分にとっては)都内に居住する利点は少ないと感じる。

ギター

在宅勤務で時間に余裕ができたのと、プログラミング以外に趣味が欲しかったのでエレキギターを始めた。毎日 30 分~練習するようにしている。といっても家に居ない日とか時間がない日もあるので実績としては週 6 ぐらいかもしれない。

練習する上で特に目標とかマイルストーンは設定してない。自分の性格的に目標を設定して達成できないと萎えて止めそうだし、達成のために真剣になりすぎても継続できなさそうだしというのが理由。

練習は毎日30分と書いたが、正確には毎日ギターに触るという部分だけはちゃんと守ろうと意識していて、時間は別に飽きるまでで良いかって感じで運用している。経験上、「やりたいときにやる」と「最低 1分でも毎日やる」は似ているようで全然違うと思っていて、結局ギターさえ持てば 30 分ぐらいはやる生き物だと思うよ、人間は。

完全初心者な上に気軽に相談できる人もいないので当初はスクール通いも検討したが、 YouTube の初心者向け動画がめちゃくちゃ充実していることが分かり、人に会わなくても動画見て自分が実際にやるだけだなって感じがしたので本当に孤独にやっている。プログラミングもそうかもしれないけど、人に教わるというよりは、自分の中に積み上げていくしかない部分の比重が大きいスキルだと思っている。

もうあと何ヶ月かで 1 年ぐらいは練習していることになるが、特にアウトプットとかはなく、1曲通して弾けるものもない。5曲ぐらいの弾きたいフレーズだけを集めて繰り返し毎日チマチマやっている(1曲だと飽きるので)

まあ成長してる実感はあって日々楽しいは楽しいので 5, 10 年後とかにはちゃんと趣味ですって言えるようになれてると良いなぐらいな感じに思っている。

株式投資

前から興味があったのと、よく「エンジニアはビジネスを理解してない」みたいに言われている印象があって、「じゃあ理解してみるか」と思い、積立ではなくあえて個別株の投資(と学習)を始めた。これも詳細を書くと長くなるので別記事でやるかもしれないが、とりあえずできるようになった気がするのは

  • 財務三表の意味が分かる、読める
  • DCF ツールで自分なりに理論株価を算出する
  • 事業の参入障壁を分析する
  • 実際に市場で売買する

など。振り返ってみると結構な時間を株式投資の勉強・分析に使っていたと思う。まあ粗利と営業利益の区別も分からないような状態から始めたにしてはけっこう進歩したんじゃないか。

なお投資成績としては、現時点で含み損。キャリア的に業界が近いのでマザーズの情報通信セクターでポジションを持っているが、今年後半は流動性の低いマザーズ市場全体が嫌気され厳しい状態になっていてツラミ(そもそも日本株自体が対して良くはないんだが、マザーズは更に厳しい)

実際やってみた感想として、個別株の集中投資は究極的にはギャンブルで、どれだけ後付でなにかもっともらしいことを言ったとしても、その時点では人が合理的に予想不可能なことを当てたら勝てるって感じのゲームなのかなって思っている。

短期は市場の予測が不可能だし運なのは当たり前だとして、株価が企業価値に収斂すると言われている中長期(5年~)でやるとしてもギャンブルの色は強いと思ったし、長期でやるなら投資信託でも良くない?ってなった。

そもそも自分が中で働いたこともなければ、社員や経営者と会ったこともなく、使ったこともないようなサービスを売る歴史の浅い会社に対して、決算資料とかだけ見て信用して投資するってなんか根本的におかしくないか?それは投機=ギャンブルだよね。

まあ自分が負けているので批判的な感じになっているのも否めないが、今年である程度の勉強にはなったので、来年は新規に購入はせずに市場を見ながら適当なタイミングで換金しつつ何らかの投資信託へ移行する気がする。

総括

業務時間で自分の市場価値が上がるような学習や経験をさせてもらっているし、在宅勤務で通勤時間がなくなって時間が増えたので自分の好きなことを沢山できた年だった。めでたい。

Expo のビルドで発生する Unable to find a specification for `UMCore` depended upon by `EX**` について

この記事は React Native Advent Calendar 2021 の10 日目の記事です。

Expo 歴 1 ヶ月ぐらいなので記述に間違いがあるかもしれないですが、同じエラーに悩んでいる方向けのヒントになればと思い公開。

環境

  • expo 42 -> 43 に更新する際に発生
  • managed work flow

事象

iOS 向けに Expo Build を実行し、expo.dev の Logs を確認すると、Install Pods で Unable to find a specification for UMCore depended upon by EXScreenOrientation というエラーが出てビルドに失敗した。

解決

Expo SDK 43 から、react-native-unimodules が 非推奨になり、expo-modules-coreexpo-modules-autolinking を利用するようになった。

react-native-unimodules に依存しているパッケージ (このエラーの例だと、expo-screen-orientation) が存在する場合に、このエラーが発生するようだ。

流石にこれらのパッケージを 1つずつ確認して更新や、対応していない場合は削除等の対応を行うのは大変なので、移行用ツールが提供されているようだ。

Migrating to Expo modules

$ expo upgrade 43

Your git working tree is clean
To revert the changes after this command completes, you can run the following:
  git clean --force && git reset --hard
✔ You are already using the latest SDK version. Do you want to run the update anyways? This may be useful to ensure that all of your packages are set to the correct version. … yes

✔ Validated configuration.
✔ No additional changes necessary to app config.

✔ Updated known packages to compatible versions.
✔ Cleared packager cache.
Failed to query all project files. Skipping `.expo.*` extension check...
✔ Validated project

👏 Automated upgrade steps complete.
...but this doesn't mean everything is done yet!

✅ The following packages were updated:
@react-native-async-storage/async-storage, react-native-safe-area-context, react-native-reanimated, react-native-gesture-handler, expo-updates, react-native-unimodules, expo-status-bar, react-native-svg, expo-linking, react-native-screens, expo-splash-screen, react-native-pager-view, expo-app-loading, expo-dev-client, react-native, react, react-dom, typescript, @babel/core, @types/react, react-native-web, @types/react-native, expo

🚨 The following packages were not updated. You should check the READMEs for those repositories to determine what version is compatible with your new set of packages:
@expo/html-elements, @expo/match-media, @react-navigation/bottom-tabs, @react-navigation/drawer, @react-navigation/material-top-tabs, @react-navigation/native, @react-navigation/stack, @types/react-native-snap-carousel, native-base, react-helmet-async, react-native-responsive-screen, react-native-safe-area-view, react-native-snap-carousel, react-native-tab-view, react-responsive, recoil, recoil-persist, styled-components, styled-system, use-media, @react-navigation/devtools, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, @welldone-software/why-did-you-render, babel-loader, deepmerge, eslint, eslint-config-prettier, eslint-plugin-prettier, eslint-plugin-react, eslint-plugin-react-hooks, prettier, react-devtools, react-native-flipper

⬆️  To finish your react-native upgrade, update your native projects as outlined here:
  https://react-native-community.github.io/upgrade-helper/?from=0.63.4&to=0.64.3

🏗  Run pod install in your iOS directory and then re-build your native projects to compile the updated dependencies.

Please refer to the release notes for information on any further required steps to update and information about breaking changes:
https://blog.expo.dev/expo-sdk-43-aa9b3c7d5541

このように、expo upgrade 43 することで、自動的に SDK 43 対応のパッケージに更新してくれる。ただし、自動更新の対象になっていないパッケージもある(The following packages were not updated.)

これらについては、EAS Build を行ってエラーが出る度に 1つずつ対応していくか、node_modules 内をUMCoregrep してエラーになりそうなパッケージを探していくかする必要がある。

自分の場合は、grep@expo/match-media のコードがマッチしたためパッケージを確認したが特に対応されていなそうだったのと、現時点で利用していなかったのでパッケージ自体を削除した。なお、今確認すると SDK 43 対応の PR はマージされているが、npm に対して publish はされていなさそう。v0.2.0 がどの時点のコミットなのかも分からなかった。

まとめ

以上の対応を行うことで、Unable to find a specification for UMCore depended upon by EX** のエラーは発生しなくなった。

おすすめの .gitconfig 設定

おすすめの .gitconfig 設定、といってもそんなにマニアックなものでもないが何も設定してないという方向けに参考になれば。

 [alias]
         co = checkout
 [push]
         default = current
 [core]
         ignorecase = true
 [fetch]
         prune = true

[alias] co = checkout

開発業務をしていると、1日に何度も git checkout する。ブランチを切り替える、ブランチを作成する、ファイルの編集内容を破棄する等何かと使う。

しかし、よく使うコマンドの割には checkout の文字数は長いので、git co にしている。

[push] default = current

ローカルで新規に作成したブランチを push する際に、git push origin feature/xxx というコマンドを打つ必要がなくなる。origin 以外を指定したいとき、別のブランチを指定したいことがないのでこれにしている。

[core] ignorecase = true

適宜変更はするが、macOS に合わせている。

[fetch] prune = true

git fetch と同時に remote に存在せず local に存在するブランチを削除する。

  • ローカルにブランチが蓄積されていくデメリット
  • 間違って remote ブランチだけ削除してしまってもローカルから復旧可能なメリット

を天秤にかけて、自動的にブランチが整理されていく方を取った。ローカルから復旧できないことが致命傷になることもあるとは思うがチーム開発ならメンバー全員が削除してない限りは何とかなるでしょ多分。(他力本願)