yn2011's blog

技術メモ

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 ブランチだけ削除してしまってもローカルから復旧可能なメリット

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

Android バージョン毎の WebView と Chrome の対応表

自分用に整理していたが、けっこう有用かもしれないので公開する。

バージョン Name WebView更新*1 WebView 依存アプリ*2 Chrome バージョン*3 リリース日
4.1-4.3 KitKat 不可 - Chrome ベースではない 2012年7月9日
4.4 KitKat 不可 - Chrome Android version 30 2013年10月31日
4.4.3 KitKat 不可 - Chrome Android version 33 -
5 Lollipop 可能 Android System WebView 最新を利用可能 2014年11月12日
6 Marshmallow 可能 Android System WebView 最新を利用可能 2015年10月5日
7 Nougat 可能 Chrome 最新を利用可能 2016年8月22日
省略 - - - - -
12 - 可能 Chrome 最新を利用可能 2021年10月4日

要約

  • Android バージョン 4 の WebView に対応することは、Chrome 33 以下に対応することを意味するので注意しよう
  • Android バージョン 5~6 と 7 以降では、WebView のブラウザ機能を更新可能ではあるが、依存する(更新する)アプリケーションが違うので注意しよう

Android Emulator について

参考

*1:JavaScript エンジン、レンダリングエンジン等のブラウザ機能を更新することが可能かどうか

*2:JavaScript エンジン、レンダリングエンジン等のブラウザ機能を更新するために何のアプリを更新すればいいか

*3:WebView で提供可能なブラウザ機能がどのChrome バージョン相当か

自分が購読しているテックブログ一覧2021

自分がどうやって技術系のインプットを行っているかについて書く。

いつ

休日。平日はほぼ見ない(週に1~2 時間でインプットが完了するように量を調整している)

どうやって

InoreaderRSS を購読。

何を

大まかに分けると3つ

  • 企業のテックブログ
  • 技術(OSSSaaS) のメディア(一次ソース)
  • ほぼ確実に参考になる個人ブログ(blog.jxck.io, JSer.info 等)

企業のテックブログを読む理由は一言で言うと自分の業務に役立つから。

など、書籍からは得にくい”現実の(主に日本の) IT 企業" の現場の動きを観測している。

加えて、自分が所属企業でブログを書く際に

  • どういうことをテーマにしたら需要がありそうか
  • 同じテーマで既に公開されている記事がどんな内容か

などを知っている方が良い記事が書けるので日常的にテックブログを読んでおくのは役に立つ。

やらないこと

逆に、デイリーのニュースフロー的なものとか、ポエムっぽいものとかは自分の中で優先度が低いので読まない。(はてなのテクノロジーカテゴリ、GitHub トレンド等)

一覧

Inoreader からエクスポートした。

title url
LIVESENSE ENGINEER BLOG https://made.livesense.co.jp/
Pulp Note https://pulpxstyle.com/
microCMSブログ https://blog.microcms.io/feed.xml
メルカリエンジニアリングブログ https://engineering.mercari.com/blog/feed.xml
CodeGrid - フロントエンドに関わる人々のガイド https://www.codegrid.net/
TypeScript https://devblogs.microsoft.com/typescript
Overreacted https://overreacted.io/
Next.js Blog https://nextjs.org/
ZOZO Technologies TECH BLOG https://techblog.zozo.com/
BASE開発チームブログ https://devblog.thebase.in/
freee Developers Blog https://developers.freee.co.jp/
blog.jxck.io https://blog.jxck.io/
ECMAScript Daily https://ecmascript-daily.github.io/
メドピア開発者ブログ http://tech.medpeer.co.jp/
Ahmad Shadeed Blog http://ishadeed.com/
DeNA Engineers' Blog https://engineer.dena.com/
JSer.info https://jser.info/
食べログ フロントエンドエンジニアブログ https://note.com/tabelog_frontend
LINE ENGINEERING https://engineering.linecorp.com/ja/
SmartHR Tech Blog https://tech.smarthr.jp/
クックパッド開発者ブログ http://techlife.cookpad.com/
Goodpatch Blog https://goodpatch.com/blog
Google Developers Japan http://developers-jp.googleblog.com/
リクルートテクノロジーズ メンバーズブログ https://recruit-tech.co.jp/blog
Yahoo! JAPAN Tech Blog https://techblog.yahoo.co.jp/
Hatena Developer Blog http://developer.hatenastaff.com/
CyberAgent Developers Blog | サイバーエージェント デベロッパーズブログ https://developers.cyberagent.co.jp/blog
Social Change! https://kuranuki.sonicgarden.jp/
リクルートライフスタイル RECRUIT LIFESTYLE http://engineer.recruit-lifestyle.co.jp/techblog
GitHub Engineering http://githubengineering.com/

おまけ

Inoreader は フィードを xml でエクスポート/インポートできる。上記の表は、エクスポートした xmljson に変換してシェルで加工して作成した。 以下のコマンドを実行すると表のヘッダーより下の部分を生成できる(ファイル j には 変換した json を用意)

$ paste -d '|' <(cat j | jq -r '.opml.body.outline[]."-text"') <(cat j | jq -r '.opml.body.outline[]."-htmlUrl"') | sed -e 's/.*/|&|/g'

|LIVESENSE ENGINEER BLOG|https://made.livesense.co.jp/|
|Pulp Note|https://pulpxstyle.com/|
...

今回 Inoreader から エクスポートした xml は gist で公開しているので、多分インポートに使えるはず(試してはない)

https://gist.github.com/pokuwagata/eae3f30e2539f1f0de7e54615caaafd6

img タグからのリクエストは Origin ヘッダーを持たないのでレスポンスの Access-Control-Allow-Origin を満たしていなくても CORS 違反にならないらしいという話

歴史的経緯により img タグからのリクエストは(crossorigin 属性を付与しない限り)クロスオリジンの場合でも preflight リクエストは飛ばない。これを simple request と呼ぶことは知っていた。

しかし、画像のレスポンスヘッダーに例えばAccess-Control-Allow-Origin: https://hoge.com が含まれる場合に、hoge.com 以外から img タグを利用してリクエストを送ると CORS 違反になるんじゃないかと思っていた。

しかし実際に試してみたら、そのような画像に対して、img タグからリクエストを発行すると正常に画像を取得することができることが分かった。

例えば、localhost で以下のコードを動かすと画像が正常に表示される。 はてブ数を表示する画像 URL はレスポンスに Access-Control-Allow-Origin: https://b.hatena.ne.jp を含むので例として使用している。

コード例1 (画像を取得できる)

<img src="https://b.st-hatena.com/images/users/gif/normal/00001.gif"> // OK

コード例2 (これは駄目)

fetch("https://b.st-hatena.com/images/users/gif/normal/00001.gif"); // CORS エラー

コード例3 (crossorigin 属性を付与すると駄目)

<img src="https://b.st-hatena.com/images/users/gif/normal/00001.gif" crossorigin="anonymous"> // CORS エラー

Chrome の Network タブを見てみると、コード1 の場合はリクエストヘッダーに Origin が含まれていないが、コード2,3 の場合は含まれている。

これは、MDN の Origin に関する記述から引用すると

There are some exceptions to the above rules; for example if a cross-origin GET or HEAD request is made in no-cors mode the Origin header will not be added.

ブラウザは、Origin ヘッダーを基本的には付与するものの、いくつもの例外が存在し、no-cors モードのリクエストには付与しないという。

no-cors モードは、すなわち img タグが(crossorigin 属性を付与しない限り)クロスオリジンでリクエストを行う場合に該当する。 Origin ヘッダーがなければ、たとえレスポンスに Access-Control-Allow-Origin ヘッダーが含まれていても許可されている Origin なのか判定できないから CORS 違反にはならないということだろうか?

ちなみに、fetch を利用して img タグのリクエストを再現すると以下になり、この場合は CORS 違反とはならない。

コード4

fetch("https://b.st-hatena.com/images/users/gif/normal/00001.gif", {
  mode: "no-cors",
});

mode: no-cors の意味がやっと分かった気がする。

ちなみに、img タグを使われると画像配信側はクロスオリジンリクエストでレスポンスを必ず読み取られてしまうのか、というとそんなことはない。

Origin 解体新書の Origin をまたぐその他の仕様 にも記載があるが、サーバー側でリクエストのヘッダーに Origin が含まれているのか判定し、403 エラーを返す実装にすることで実現できる。

こうすると、コード1 のように crossorigin 属性が未付与の場合は Origin ヘッダーが含まれないので 403 エラーになるし、コード3 のように Origin ヘッダーを含めても許可されていない Origin は Access-Control-Allow-Origin に許容すべきオリジンを列挙してレスポンスに含めることでブラウザはレスポンスを読み取れない。

参考

https://stackoverflow.com/questions/47978252/how-img-tag-gets-content-over-cors-headers

flex item は幅を指定せずに margin: auto で縦横中央揃えできる

margin: auto を使用した縦横中央揃えは要素自体に幅((max-)width, (max-height))の指定が必須と思っていた。

例えば、position: absolute と組み合わせた以下の要素は親(absolute の基準)に対して縦横中央揃えされるが

 .test {
  background-color: aqua;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  max-height: 100px;
  max-width: 100px;
}

これは max-widthmax-height の指定がない場合は動作しない。

しかし、flex item (flex box の子要素) の場合はなぜか幅の指定がなくても縦横中央揃え可能になる。

.parent {
  display: flex;
}
.test {
  background-color: aqua;
  margin: auto;
}
<div class="parent">
  <div class="test">hoge</div>
</div>

これは幅の指定の有無以外は、最初のコード例と同一になるので、親の大きさに合わせて縦横中央揃え可能になる。

こうすれば 500px の正方形の中で縦横中央揃えになる

.parent {
  display: flex;
  width: 500px;
  height: 500px;
}
.test {
  background-color: aqua;
  margin: auto;
}

画面全体に対して縦横中央揃えする場合は、親自体を広げれば OK

.parent {
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

ちなみに、margin: auto を使わずにこの指定でも問題ない

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

どちらがベストなのかは分からない。参考リンク↓

stackoverflow.com

モブプログラミングのモブのときに意識していること

前提

  • モブプログラミング歴 9 ヶ月程度
  • 参加者は全員リモートワークで、最小2人、最大でも4人
  • 自分がモブになるかドライバーになるかは事前に分からない(抽選)
  • 何をモブプログラミングするかは事前にある程度分かっている

モブプログラミングをする前にやっていること

正直毎回予習しているわけではなく、ちょっと今日の開発は難しそうだなと思ったら準備する(場合もある)

  • ドキュメントを軽く読んでおく
    • 使用する言語やライブラリに慣れていない、使う予定の外部サービス(AWS, Google Analytics, Repro etc)に詳しくない場合
  • 開発対象の既存コードを軽く読んでおく
    • 該当箇所の既存コードを触ったことも見たこともない場合
  • 大体の開発の進め方や議論して決めないといけないことをイメージしてみる
    • 想定通りにならないことも多いが、なんとなく考えてみる

モブのときにやっていること

助ける

  • 実装で悩んでいたら助ける

    • 自分もすぐには分からないときは、ググって URL を共有する
    • 例えば、言語、ライブラリのドキュメントや、既存コードで似たような修正を行ったプルリクとか。
  • 先読みして助ける

    • 何となくコードを書いていく流れが見えてきたら事前に障害になりそうな箇所についてググる、既存実装がないか調査するなど
    • 例えば、文字列を数値に変換しないといけないことが明らかだったら、事前にググって型変換の良さげな方法を把握しておくとか。

進行する

  • 悩みすぎて作業が止まってしまっていたら前に進める

    • 命名、現段階では正解が分からない実装方針、個人の趣味の問題でしかないこと、誰かに質問した方が早いこと、議論の堂々巡りなど
    • 大体は「とりあえず今はこれにして、後でまた考えましょう」とか「この人に後で聞きましょう」とか発言すると解消されることが多い
  • 休憩をするように促す

    • ドライバーをしていると、夢中になりすぎていたりするのでモブの人から休憩を提案する
    • 疲労がコミュニケーションの軋轢になったりする
  • 全員でやらなくてもいいことを切り分ける

    • 何となく流れで単純な置換作業とかドキュメントの編集をしてしまうこともあるが、後で1人でできることなら後回しにしてモブプログラミングの効率を高める

質問する

  • ドライバーや他のモブの人と認識がズレている、何をしようとしているのか分からなくなったら質問する

    • 分かったふりで進行してしまうとモブプログラミングをしている価値が下がってしまう
    • 実は全員の考慮漏れで重要なことだったりもする(会話しながら考えていると、パターンの考慮漏れとかはけっこうある印象)
  • 本筋と関係ないが、ショートカットキーや知らないコマンド、機能などがあったら質問する

    • 流れ的に質問しにくい場合もあるが、けっこう学びになることがあるので質問してみると良い
    • 逆にドライバーが自発的に説明するのは「いや、知ってるが...」みたいな空気になると嫌なので勇気がいると思う(相当マニアックなことなら良いが)

丁寧に会話する

  • 口頭で説明できないことを無理に説明しない

    • 図やコードで示したほうが早いことは、自分がドライバーでなくても一旦画面共有させてもらう等してコミュニケーションを効率化する
  • 高圧的にならない

    • 自分の方がよく理解している実装や分野の場合やコミュニケーションが上手くできないときに、もどかしい気持ちを感じたりするかもしれないが HRT を意識してコミュニケーションする。

記録する

  • 考えたこと・学んだこと・やったことを書記として記録する
    • モブプログラミングのログを残し、後から参照可能にする
    • 決定事項だけでなく、思考や議論の過程とか、途中で悩んだこととかも書いておくと良い
    • Scrapbox を使って全員が同時に読み書きできるようにしている

モブのときにやらない方がいいこと

  • 画面を見てはいるが、一緒には考えていない、ついていけてない、同時に別の作業をしている
    • モブプログラミングに参加している意義が薄くなる
  • 音声を聞き取りにくい、画面の文字が見えにくい等環境面の我慢
    • 遠慮せずに伝えたほうが全員のためになる。逆に指摘されたら素直に対応する。(音声の問題は自分でどうにもならないこともあるが)