はい、なんか出てきました。「react-native-windowsなら前からあったじゃん」と思ったのですが、どうやら大幅にリライトしたみたいなので、本家とどのくらい違うのか、簡単に流し読みしてみました。雑に読んだだけなので、たぶん勘違いを多分に含んでます。眉に唾をつけて読んでください。ちゃんと知りたい人はコード読んでください。
三行で
- VC++使った結果、言語をブリッジするレイヤーがひとつ減ったのは面白い
- フォルダ構成は大きく変わったけど、たぶん妥当
- 開発者が使うときのAPIだけ本家と共通なら、内部実装の方針は多少本家と違ってても大丈夫なはず(ほんとか?)
前提
React Native製のアプリは、ざっくり分けると、次の3つのレイヤーで構成されます。
- 開発者が作成したJavaScript製Reactアプリケーション
- JavaScriptライブラリとしてのReact Native(
'react-native'
モジュール) - 「JavaScript実行環境+ネイティブブリッジ」によるミドルウェアとしてのReact Native
「ミドルウェアとしてのReact Native」がWebViewのような役割を果たしつつ、DOM APIの代わりとなるReact Native Rendererにアクセスできる「JavaScriptライブラリとしてのReact Native」を私たちが利用することで、アプリを組み上げていく形です。
「ミドルウェアとしてのReact Native」には、C++ライブラリであるJavaScriptCoreが含まれており、この中でJavaScriptが動いています。さらにC++とObjective-C/Javaをつなぐコードも用意されているので、全体としては次のような構成になっています。
JavaScript ↕️ (JavaScriptCore) C++ ↕️ (Objective-C++ / Android NDK) Objective-C / Java
このへんを軸に話をしていきます。
今までのreact-native-windows
まずは従来のreact-native-windows*1がどうなっていたのかを確認しておきましょう。現在のmasterである 4798c610
では、currentフォルダに旧実装が格納されています。
割とReact Native本家に近い構成になっています。ミドルウェアのiOS実装である React
フォルダや、Android実装である ReactAndroid
フォルダの代わりに、 ReactWindows
フォルダが用意されている形です。中身は次のような感じ。
ChakraBridge
フォルダがあるので、JavaScriptCoreの代わりにChakraを使ってるんですかね(未確認)。ChakraBridgeの中はC++ですが、他のフォルダはだいたいC#で書いてあるようです。
ここまで来ると、だいぶC#プロジェクトっぽい見た目になってますね。
ざっくりとは次のような構成になっていると思われます。
JavaScript ↕️ (Chakra?) C++ ↕️ (Visual C++?) Visual C#
ぶっちゃけWindows文化圏の開発環境に詳しくないので間違っていそうな気もする・・・
新しいreact-native-windows
それでは今回発表された、新しいReact Native for Windowsのほうを見てみましょう。 4798c610
のvnextフォルダに新しい実装が格納されています。
ごそっと増えました。ざっくり見た感じでは、次の点が変わっています。
- ReactWindowsフォルダの中身をトップレベルに移した
- ReactWindowsフォルダにまとめられていたネイティブ実装をUWP実装とWindows Desktop実装に分けた
- C#製のネイティブ実装を(おそらくすべて)C++で再実装した
たぶん他にも色々あると思うのですが、私のWindows力が足りない……
C++版をmasterにマージした際のコメントに細かいコミットコメントがまとめられてるっぽいので、興味がある方はどうぞ。
この変更で、「ミドルウェアとしてのReact Native」は次のような構成になったのかなと想像しています。
JavaScript ↕️ (Chakra?) Visual C++
これもWindows素人の想像なので、違うっぽかったらご指摘ください!
「ミドルウェアとしてのReact Native」の大変革については、後述の「感想 > 全面C++リライト」で感想を述べます。
「JavaScriptライブラリとしてのReact Native」はまだポーティングを進めている最中という感じでした。このへんはおいおい実装されていくと思います。ミドルウェアに合わせてJavaScript側の実装も最適化*2されていますが、コンポーネント名とPropsの型は本家に準拠してるっぽいので、普通に使っている分にはそんなに問題にはならないでしょう(たぶん)。JavaScriptCoreとChakraの差異とかのほうがよっぽどやばそう。
感想
というわけで本題です。疲れたので簡潔にいきます。
全面C++リライト
React Nativeは「ミドルウェアとしてのReact Native」が必ず持っている C++で書かれた処理
を そのプラットフォームで本来使われているGUI開発言語
に繋げないといけない性質上、「他言語とのブリッジ」という複雑な機構を持たざるをえませんでした。C++とJavaを繋ぐためにAndroid NDKのJNI機構が使われていますし、C++とObjecitve-Cを繋ぐためにObjective-C++が使われています。
さて、Java/KotlinやObjective-C/Swiftを使わずに画面を作ることはできるでしょうか。Android NDKでUIを書くことは可能ですが、あまり一般的ではありません。Objective-C++からUIKitを触るのは……できたっけ?(うろ覚え)もできます*3が、煩雑になりやすいため、やはり一般的ではないようです。
では、Windowsアプリケーションの開発ではどうかというと、Visual C++で画面を開発するのは、そこそこ一般的だったと記憶しています。POSレジのアプリがVC++ランタイムで動いているのを見たことがありますし。古い記憶なので今では廃れつつあるのかもしれませんが。そのへんよくしらない。
Windows向けの実装として考えた場合に、ブリッジを1段階廃して、最初からC++で書くというのは、パフォーマンスの面では良い選択であるように思えました。
C#でネイティブモジュールを作っていた人達からすると「何してくれてんのォ!?」という感じかもしれない……どうなんだろう……C++からC#を呼び出すブリッジコードみたいなのを足せば既存のモジュールも動くのかな……そこだけ心配……
フォルダ構成の変更
本家とこんなにフォルダ構成変えちゃって大丈夫なの?というのは思いますが、これはこれでありなのかなーと思えてきました。
本家は「AndroidとiOSの両方に対応する」という制約があるので、iOS向け実装とAndroid向け実装を別々に管理する必要がありましたし、各プラットフォーム向けのファイルがトップレベルに漏れ出すのは可能な限り避けられていました。しかし、react-native-windowsはWindowsのことだけ考えていればいいので、トップレベルにWindows向けの都合が漏れ出しても、そんなにまずくはありません。それどころか、UWP版とWinDesktop版の実装を分けるにあたっては、このくらいのフォルダ構成にしておいたほうが見通しが良くなるくらいかもしれないです。
本家との挙動の違いについて
本家側の修正に追従しようとしたときにしんどそうじゃない?という疑問は湧いてきますよね。
まあそもそも、本家側もiOSとAndroidで挙動が同じなのかという話がありまして、コントリビューターたちが頑張って似たような挙動になるようにしているだけで、別に挙動を同じにする仕組みがあるわけではないのです。
なので、Windows版の挙動も頑張って合わせていく感じになるんだろうなあと思います。
ひとまず「JavaScriptライブラリとしてのReact Native」を私たちが触るときのAPIさえ本家と同じ型なら、割り切って使うことはできそうです。本家のAPIについてはOpen Source Roadmapで語られたとおり、React Native 1.0を目指してStableなAPIにしていくそうなので、react-native-windowsもそこに追従してくれれば、多少内部実装が違っても使う側としては「これはこれで」になるのかなと。
まとめ
Windows素人の雑な感想でした。
たぶんこれからOfficeやSkypeなどで実用しながらブラッシュアップされていくと思うので、見守っていきたいと思います。
*1:たぶんWindows版のSkypeとかOfficeがこれを使ってる
*2:Android向けワークアラウンドを消したり
*3:https://twitter.com/omochimetaru/status/1125698058337964032