【大先端の道】React Nativeに基づく三端同構造応用

6175 ワード

前言
V 8エンジンが登場した後、JavaScriptは大爆発的な発展を迎えた.Atwoodの法則(「JSで実現できるものは、結局JSで実現される」)も日常的な論調となっている.HTML 5仕様で定義された新しいインタフェースとWebSocket、WebGLのような新しい技術はブラウザに新しい能力をもたらします.NodeJSの出現は同じ言語で前後のエンドコードを書くことを可能にした.PhoneGapはJSの勢力範囲をモバイルアプリに拡大し、React NativeはJSモバイルアプリの開発を新しい時代に推し進めた.
手持ちの武器がモデルチェンジされると、フロントエンドの開発者も以前より多くの責任を負うに違いない.会社の「明道大フロントエンド」というグループが設立されたとき、将来のフロントエンド開発が本当に明道でこのような重要な役割を果たすとは思わなかった--伝統的なブラウザが応用に富み、バックエンドのマイクロサービスから、プラットフォームをまたぐデスクトップクライアントとモバイルAppまで、微信ウィジェットに至るまで、フロントエンドエンジニアの労働成果は製品の各方面を貫いている.
そこで、この機会に「大フロントエンドの道」のシリーズを書いて、明道フロントエンドの開発過程で出会った様々な問題と収穫を記録するつもりです.
React Nativeベースの三端同構造応用
明道の主なフロントエンド技術スタックはReactフレームワークに基づいて、同構造応用(Universal App、以前はIsomorphic Appと呼ばれていた)はReact生態圏でよく言及されている概念である.Reactの哲学はUI=f(state)であり,同じデータ状態に対して同じReactコードでレンダリングされたUIは同じである.この機能により、プラットフォームに基づいて差別化処理を行う可能性のある同じレンダリングコードを作成し、各エンドで同じ初期データを与えることで、一貫した最終結果を得ることができます.このモードは同構造応用と呼ばれている.
ここでの3つの端は、Webブラウザ端、サービス端、およびオリジナルモバイル端(React Native)を指す.最近,いくつかのきっかけで,明道モバイルページ版(通称H 5版)の開発に着手した.技術選択の段階では、一部のアプリケーションモジュールがReact Nativeバージョンを開発していることを考慮して、このコードをできるだけ多重化し、開発とメンテナンスのコストを削減したいと考えています.最終的な目標は、同じコードを使用して、オリジナルのモバイルアプリケーションを埋め込み、RNの性能の優位性を発揮し、Webページとしてブラウザ内を走ることです.さらに、サービス側のレンダリングがストレートになり、最初の画面の表示速度が速くなります.
RNには独自の特殊なコンポーネントとAPIがあり、Web版端コードをRNコードに変換するのはかなり面倒なので、当然RNコードが優先され、ブラウザに適しています.これには、RNのコンポーネントとインタフェース能力がブラウザで実行できるように、中間層が必要です.この方面はすでに多くの先駆者が探求したことがあって、しかし宝を洗うreact-webの活発度はますます低くなって、携程が必ず吹くCRNは今まで少しもオープンソースのコードの影さえ見ていません.そこで、Twitterのより古いブランドと安定したreact-native-web実装を選択しました.一部の実装されていないコンポーネントとインタフェースについてはant-design-mobileを含むいくつかのライブラリを用いて互換性があり、自分で多くのpolyfillを作った.このライブラリはまた完全なCSS-in-JS実装を提供し,コンポーネントの集約性を強くすることができる.
react-native-webの使用については、「react-native-webを使用してあなたのreact-nativeアプリケーションをH 5化する」という同級生が共有しています.この文章は主に実践中のいくつかの全体的な考え方を紹介する.
いったいこうぞう
大まかなプロジェクト構造は次のとおりです.
MingdaoLite
├─js (JavaScript     )
├─public (              )
├─server
│  └─server.js (   )
├─src (TypeScript    )
│  ├─api
│  ├─assets
│  ├─components
│  ├─utils
│  ├─index.browser.tsx (         )
│  ├─index.server.tsx (        )
│  └─routes.tsx (React Router     )
├─webpack
│  ├─dev.config.js
│  └─prod.config.js
├─.babelrc
├─index.js (   App RN      )
├─package.json
├─tsconfig.json
└─webpack.config.js

言語
言語面では,以前RNプロジェクトが開始されたときに決定されたTypeScriptを選択した.しばらく使用すると、静的タイプによる自動補完、エラーヒントなどの特性が生産性を大幅に向上させます.また、Facebookの自社FlowよりもTSのコミュニティが成熟しており、Reactへのサポートも可能だ.多くのライブラリはタイプ定義を持っており、他のライブラリもサードパーティのタイプ定義を熱心に作成し、npmに独立して公開され、自分で定義を書く苦痛を省いている.
React Nativeのパッケージングプロセスが柔軟ではないため、RNがJavaScriptコードを直接参照できるように、パッケージング前にTypeScriptが持参したtscツールを使用して、srcディレクトリ下のTSソースファイルを全体的にコンパイルし、jsディレクトリ下に出力します.その後、オリジナルアプリケーションRNは、jsのファイル(.babelrcによってbabelトランスコード中のいくつかの動作を構成する)を直接参照し、ウェブ版は、ウェブパックによって予めパッケージ化されて構築される.
ビルド
構築といえば、create-react-app、Nextなどのバカな足場ツールが市販されています.jsなど.しかし、使いやすいと同時に、自由配置の柔軟性も犠牲になった.私たちのニーズは比較的小さいので、webpackプロファイルを最初から作成することにしました.webpackディレクトリの下に保存されているのは関連プロファイルであり、NODE_ENV環境変数によって異なる構成が使用されます.
開発と生産環境の違いに加えて、webpack構成のもう一つの重要な機能はブラウザとサービス側を区別することです.webpack.config.jsのコードを見せてください.
const config = process.env.NODE_ENV === 'production'
    ? require('./webpack/prod.config')
    : require('./webpack/dev.config');
module.exports = [config('browser'), config('server')];

最終的には、ターゲットコードが2つ生成され、ブラウザにロードされ、サービス側にレンダリングされます.2つの環境のwebpack構成の違いは、次のとおりです.
  • targetが異なります.サービス側は'node'、ブラウザ側は'web'
  • である.
  • output.libraryTargetが異なります.サービス側は'commonjs'、ブラウザ側は'umd'
  • である.
  • pluginsリストに差があります.ブラウザ側はサービス側よりも特定のwebpackプラグイン
  • を多く使用しています.
  • resolve.extensionsが異なります.これは比較的重要な選択肢です.異なるプラットフォームの異化については,コードで判断する小さな違いがあり,大きな違いについては異なるプラットフォームで異なるファイルを使用する.extensionsというパラメータは、異なる拡張子に従ってロードを可能にする.この配列に拡張子が対応するファイルを順番にロードする配列です.サービス側は['.server.js', '.web.js', '.js', '.android.js', '.ios.js']、クライアントは['.browser.js', '.web.js', '.js', '.android.js', '.ios.js']である.このようにパッケージ化すると、webpackはブラウザやサービス側の対応するファイルを優先的に検索し、なければwebバージョンの特定のファイルを検索し、なければ共通のjsファイルを検索します.次の2つは、少数のアンドロイドまたはiOS固有のサードパーティライブラリを互換化するためです.
  • url-loaderemitFileパラメータ.サービス側着信falseについては、関連ファイル
  • は生成されない.
    もう1つ注意しなければならないのは、通常node_modulesディレクトリのファイルは生成された最終ファイルなので、追加のローダを使用する必要はありません.しかし、多くのReact Nativeの3つのライブラリにはES 6とJSXコードが含まれており(RNが直接サポートしているため)、これらのライブラリにはbabel-loaderを使用して1回回転する必要があります.react-native-animatable,react-native-storageなど
    サービス側
    サービス側ではkoaフレームワークを使用しています.このプロジェクトのバックエンドは薄いレンダリングレイヤにすぎず、マスタインタフェースを直接呼び出し、複雑な論理が少なく、koaの簡潔さが必要とされています.さらに、asyncおよびawaitのサポートにより、非同期プログラミングが大幅に簡素化されます.
    ルート
    ルーティングライブラリはreact-router v 4を使用する.この版は以前のバージョンに比べて大きく変更され、主に以前のいわゆる「静的ルーティング」から「動的ルーティング」に変更された.新しい使用方法では、ルーティングは1つの場所で統一的に構成されるのではなく、通常のコンポーネントのように必要な場所でレンダリングされます.
    しかし、このようにすると、サービス側レンダリングは使用できません.したがって、公式に提供されているreact-router-configライブラリを使用しても、統一的な構成を使用しています.
    サービス側レンダリングの詳細は、後で説明する時間があります.
    に質問
    プロジェクトアーキテクチャの剣が偏っているため、一連の穴に遭遇することは避けられない.まだ解決されていないものもありますが、ここで簡単に列挙します.
  • 回転アニメーション.react-routerにはreact-navigationのような回転アニメーションはありません.これはweb側にはそれほど重要ではありませんが、モバイルApp体験に大きな影響を与えます.まだ解決していないので、後で投入してみる必要があります.
  • パッケージ化されたリソースが大きすぎます.モバイルブラウザのような寸土寸金の場所では、この一連のフレームワークとツールライブラリにアプリケーションコードを加えることで、圧縮後でも数MBに達する.しかし、これはリッチアプリケーションでは避けられないことであり、サービス側レンダリングもこの問題を緩和するためだ.また、パッケージの最適化とキャッシュポリシーも一連行い、後で詳しく説明します.
  • サービス側のグローバル状態汚染問題.新しく追加されたアプリケーションモジュールはreduxを使用しており、すべてのステータスデータがreduxのstoreに存在し、問題は大きくありません.しかし、以前のRNコードはmobxに基づいていたが、当時mobxが発表されたばかりでベストプラクティスがなく、プロジェクトには多くのグローバルなmobx storeが使用されていた.これらのグローバル状態は、サービス側のrenderの各ラウンドで実際には同じ変数であり、セキュリティ上の危険性をもたらしています.一時的な解決策は、レンダリング前にアプリケーションコードを再ロードするたびに、パフォーマンスに大きな悪影響を及ぼしますが、コードレベルから再構築して根本的な問題を解決する必要があります.
  • JSモジュールの非同期ロードはまだ解決されていません.react-router-configの統一構成を使用しているため、コード分割、非同期ロードの実現方法はまだ考えられていません(解決しました.時間を見つけて紹介します).