本日、React Native 0.79 をリリースできることをお知らせします!このリリースでは、多方面にわたるパフォーマンス改善と複数のバグ修正を含みます。主な変更点として、Metro の起動が deferred hashing により高速化され、package exports の安定サポートが導入されました。Android の起動時間も JS バンドル圧縮の変更などにより改善されています。
ハイライト
- 新しい Metro の機能
- JSC のコミュニティパッケージへの移行
- iOS: Swift 互換の Native Modules 登録方式
- Android: 起動時間の短縮(JS バンドルの非圧縮出荷)
- Remote JS Debugging の削除 など
新しい Metro 機能
Metro: 起動の高速化と package exports の安定サポート
このリリースには Metro 0.82 が含まれます。Metro 0.82 は deferred hashing を採用しており、通常の yarn start の初回起動速度を一般的に 3x 以上向上させます(大規模プロジェクトやモノレポではさらに効果が大きくなります)。これにより、日常の開発体験や CI ビルドが高速化されます。
また、Metro 0.82 では package.json の "exports" と "imports" フィールドの解決を安定機能として昇格させました。"exports" の解決は React Native 0.72 で導入され、"imports" のサポートはコミュニティ貢献で追加されました。これらは React Native 0.79 でデフォルトで有効化され、最新の npm 依存関係との互換性が向上し、プロジェクト構成の標準準拠な方法が利用可能になります。
破壊的変更(注意)
package.json の "exports" を有効化する切り替えは、一部のパッケージやプロジェクト構成で互換性の問題を引き起こす可能性があります。特に、Firebase や AWS Amplify のような人気パッケージで報告された互換性問題を把握しており、これらはソース側で修正を進めています。
問題が発生した場合の回避策:
- Metro 0.81.5 の hotfix に更新する
- もしくは resolver.unstable_enablePackageExports = false を設定して無効化する
影響のあるパッケージや今後の更新については expo/expo#36551 を参照してください。
JSC をコミュニティパッケージへ移行
React Native の API surface を縮小する取り組みの一環として、JavaScriptCore (JSC) をコミュニティ管理のパッケージへ移行しています: @react-native-community/javascriptcore
- Hermes を使用しているユーザーへの影響はありません。
- React Native 0.79 からは、readme に記載されたインストール手順に従うことでコミュニティサポートの JSC を使用できます。
- React Native コアが提供する JSC は 0.79 では引き続き利用可能ですが、近い将来削除する予定です。
JSC をコミュニティ管理に移すことで JSC のバージョンをより頻繁に更新し、最新機能を提供できるようになります。コミュニティ版 JSC は React Native 本体とは別のリリーススケジュールに従います。
iOS: Swift 互換の Native Modules 登録
今回、Native Module を React Native ランタイムに登録する方法を刷新しました。新しいアプローチは公式ドキュメントにあるコンポーネントの方法と同様です。React Native 0.79 以降では、package.json を修正してモジュールを登録できます。
package.json に ios の新しい modulesProvider フィールドを導入しました:
"codegenConfig": {
"ios": {
"modulesProvider": {
"JS Name for the module": "ObjC Module provider for the pure C++ TM or a class conforming to RCTTurboModule"
}
}
}
Codegen は package.json から必要なコードを生成します。純粋な C++ Native Module を使用する場合は、C++ Native Module とアプリの残りの部分をつなぐ ObjectiveC++ クラスを追加する必要があります。推奨される構成例:
CppNativeModuleProvider.h
# import Foundation / Foundation . h >
# import ReactCommon / RCTTurboModule . h >
NS_ASSUME_NONNULL_BEGIN
@interface YourNativeModule > Provider : NSObject RCTModuleProvider >
@end
NS_ASSUME_NONNULL_END
CppNativeModuleProvider.mm
# import " Provider.h"
# import ReactCommon / CallInvoker . h >
# import ReactCommon / TurboModule . h >
# import " .h"
@implementation NativeSampleModuleProvider
- ( std : : shared_ptr facebook : : react : : TurboModule > ) getTurboModule : ( const facebook : : react : : ObjCTurboModule : : InitParams & ) params {
return std : : make_shared facebook : : react : : NativeSampleModule > ( params . jsInvoker ) ;
}
この新しい方式により、アプリ開発者とライブラリメンテナの両方で Native Modules の登録方法が統一されます。ライブラリは同じプロパティを package.json に指定すれば、Codegen が残りを自動処理します。
また、0.77 で導入した Swift の AppDelegate と純粋な C++ Native Module が登録できないという制約は解消されました。これらの変更は AppDelegate を変更する必要がなく、Swift 実装・Objective-C 実装の両方で生成コードが動作します。
Android: 起動時間の短縮
Android の起動時間を大幅に改善する変更を出荷します。今回から、APK 内で JavaScript バンドルを圧縮して出荷しないことにしました。以前は Android システムが APK 内で圧縮されたバンドルを展開してからアプリ起動を進める必要があり、起動時に大きな遅延が発生していました。
このリリース以降、デフォルトで JavaScript バンドルは非圧縮で出荷されるため、Android アプリの起動が高速化します。ただし、非圧縮で保存するとユーザー端末上のアプリの占有容量は増える点に注意してください。容量が問題となる場合は、app/build.gradle の enableBundleCompression で動作を切り替えられます。
app/build.gradle の例:
react {
enableBundleCompression = true
enableBundleCompression = false
}
Margelo チームはこの機能を Discord アプリでテストし、Samsung A14 上で Discord の time-to-interactive (TTI) が 400ms 短縮(約 12% の高速化)することを確認しました。
補足: APK 自体のダウンロード時にはネットワーク上で APK が圧縮されるため、今回の変更によるダウンロード時の追加コストは発生しませんが、端末上のインストール後サイズは増加します。
破壊的変更
Remote JS Debugging の削除
デバッグ体験の改善の一環として、Chrome を使った Remote JS Debugging を削除しました。この古いデバッグ方法は React Native 0.73 で非推奨化され、ランタイムのオプトインに移行済みでした。現代的で信頼できるデバッグには React Native DevTools を使用してください。
この変更により、react-native-debugger コミュニティプロジェクトとの互換性はなくなりました。Redux DevTools などサードパーティのデバッグ拡張を使用したい場合は、Expo DevTools Plugins の利用やそれらツールのスタンドアロン版統合を推奨します。詳細は専用ポストを参照してください。
内部モジュールの export 構文への更新
JavaScript コードベースのモダン化の一環として、react-native 内の実装モジュールの多くを module.exports から一貫して export 構文に更新しました。合計で約 46 の API を更新しており、変更点は changelog に記載されています。
この変更は既存のインポートに微妙な影響を及ぼします。例:
ケース 1: デフォルトエクスポート
const ImageBackground = require('react-native/Libraries/Image/ImageBackground');
const ImageBackground = require('react-native/Libraries/Image/ImageBackground').default;
import ImageBackground from 'react-native/Libraries/Image/ImageBackground';
import {ImageBackground} from 'react-native';
ケース 2: セカンダリエクスポート
const BlobRegistry = require('react-native/Libraries/Blob/BlobRegistry');
const {register, unregister} = require('react-native/Libraries/Blob/BlobRegistry');
import BlobRegistry from 'react-native/Libraries/Blob/BlobRegistry';
import * as BlobRegistry from 'react-native/Libraries/Blob/BlobRegistry';
import {register, unregister} from 'react-native/Libraries/Blob/BlobRegistry';
import {BlobRegistry} from 'react-native';
この変更は、TypeScript で import 構文を使用しているプロジェクトではほとんど影響がないと予想していますが、型エラーがないか確認してコードを更新してください。
tip: ルートの 'react-native' インポートを強く推奨します
ルート 'react-native' パスからインポートすることで、将来の深いインポートに伴う余計な破壊的変更を回避できます。次回リリースでは deep imports を非推奨化し、React Native の公開 JavaScript API をより明確に定義する予定です(RFC を参照)。
その他の破壊的変更(要確認)
- box-shadow と filter における単位なしの長さを無効化しました。これは CSS/Web 規格への準拠のためで、例えば
1 1 black のような単位なしの指定は描画されなくなります。代わりに 1px 1px black のように単位を指定してください。
- normalize-color から不正な hwb() 構文サポートを削除しました。歴史的に React Native はカンマ区切り(例:
hwb(0, 0%, 100%))をサポートしていましたが、これを廃止しスペース区切り(例: hwb(0 0% 100%))へ移行してください。詳細は関連ページを参照してください。
- Libraries/Core/ExceptionsManager のエクスポートを更新しました。ExceptionsManager は default エクスポートとして ExceptionsManager オブジェクトを、SyntheticError はセカンダリエクスポートとしてエクスポートされます。
謝辞
React Native 0.79 は 100 名のコントリビューターによる 944 以上のコミットを含みます。貢献してくださった皆さん、ありがとうございます。特に以下の方々に感謝します:
- Marc Rousavy — “Android: Faster App Startup” 機能の開発と文書化
- Kudo Chien、Oskar Kwaśniewski — @react-native-community/javascriptcore パッケージの作業と“JSC moving to Community Package” セクション執筆
- James Lawson — Metro の import サブパス解決サポート追加
- 文書化に協力したその他の方々: Rob Hogan(New Metro Features)、Alex Hunt(Removal of Remote JS Debugging と Internal modules updated to export syntax)、Riccardo Cipolleschi(iOS Native Module registration)
0.79 へのアップグレード
既存プロジェクトの React Native バージョン間のコード差分を確認するには React Native Upgrade Helper を使用し、Upgrading docs を合わせて参照してください。
新規プロジェクトを作成するには:
npx @react-native-community/cli@latest init MyProject --version latest
Expo を使用している場合、React Native 0.79 は今後の Expo SDK 53 でデフォルトの React Native バージョンとしてサポートされます。
情報: 0.79 は現在の最新の安定版であり、0.76.x はサポート対象外になります。詳細は React Native のサポートポリシーを参照してください。近いうちに 0.76 の最終的な EOL アップデートを公開する予定です。