React App(別名React Scripts)を作成し、Reduxとルーターでサーバーレンダリング

この記事のコメントから、非常に多くの人々がCreate Reactアプリのエコシステム(別名React Scripts)に傾いていることが明らかになりました。 これはかなり合理的です これは最も一般的で使いやすい製品であり(Reactコミュニティの主要な人々からの構成とサポートが不足しているため)、さらに、アセンブリ、開発モード、テスト、カバレッジ統計など、必要なほぼすべてを備えています。 不足しているのは、サーバー側のレンダリングです。







公式ドキュメントの方法の1つとして、初期データをテンプレートに入れるか、 静的キャストを使用することが提案されています。 最初のアプローチでは、検索エンジンが静的HTMLに通常のインデックスを作成できません。2番目のアプローチでは、HTML以外の初期データの転送をサポートしていません( ドキュメントのフレーズ :これは、マークアップに含まれているもの以外の状態を渡しません)。 したがって、Reduxを使用する場合は、レンダリングに別のものを使用する必要があります。







Create React Appで使用するために記事の例を修正しました。現在はCreate React Serverと呼ばれ、次のコマンドでサーバーレンダリングを起動できます。







create-react-server --createRoutes src/routes.js --createStore src/store.js
      
      





この起動では、特別な構成は必要ありません。すべてはコマンドラインオプションで実行されます。 必要に応じて、独自のテンプレートとハンドラーを同じ方法でスリップできます。







少し叙情的な余談。 React Router作者が言うように 、彼らのサイトは問題なく、サーバーレンダリングなしでGoogleによってインデックスされています。 たぶんそう。 しかし、主な問題の1つはGoogleだけでなく、ユーザーへのコンテンツの高速配信であり、これはだまされる可能性のあるインデックス作成よりも重要です。







設置



まず、この例に必要なパッケージをインストールします。







 npm install create-react-server --save-dev
      
      





.babelrc



ファイルまたはbabel



セクションをpackage.json



ファイルに追加します



 { "presets": [ "react-app" ] }
      
      





babel-preset-react-app



react-scripts



とともにbabel-preset-react-app



れますが、サーバーレンダリングのために明示的に参照する必要があります。







ページ(React Router Endpoint)



前と同じように、サーバーレンダリングの本質は非常に簡単です。サーバーでは、ルーターのルールに基づいて、ページに表示するコンポーネントを決定し、機能する必要があるデータを見つけ、このデータを要求し、HTMLをレンダリングし、このHTMLをデータと共に送信する必要があります顧客ごと。







サーバーは最終コンポーネントをgetInitialProps



し、そのコンポーネントでgetInitialProps



を呼び出します。このコンポーネント内で、Reduxアクションのディスパッチを行い、初期セットのprops



を返すことができます(Reduxが使用されない場合)。 このメソッドは、クライアントとサーバーの両方で呼び出されるため、データの初期ロードが大幅に簡素化されます。







 // src/Page.js import React, {Component} from "react"; import {connect} from "react-redux"; import {withWrapper} from "create-react-server/wrapper"; import {withRouter} from "react-router"; export class App extends Component { static async getInitialProps({location, query, params, store}) { await store.dispatch(barAction()); return {custom: 'custom'}; //     props   }; render() { const {foo, bar, custom, initialError} = this.props; if (initialError) return (<pre>   getInitialProps: {initialError.stack}</pre>); return ( <div>Foo {foo}, Bar {bar}, Custom {custom}</div> ); } } //   Redux Provider   App = connect(state => ({foo: state.foo, bar: state.bar})(App); //   WrapperProvider,   initialProps   App = withWrapper(App); //     React Router App = withRouter(App); export default App;
      
      





変数initialError



は、 getInitialProps



関数でエラーが発生した場合に重要になります。クライアントまたはサーバー上の動作は同じです。







404エラーのスタブとして使用されるページには、静的notFound



プロパティが必要です。







 // src/NotFound.js import React, {Component} from "react"; import {withWrapper} from "create-react-server/wrapper"; class NotFound extends Component { static notFound = true; render() { return ( <div>404 Not Found</div> ); } } export default withWrapper(NotFound);
      
      





ルーター



createRoutes



関数はルーターのルールを返す必要があり、非同期ルートもサポートされますが、簡単にするために、ここではこれを省略します。







 // src/routes.js import React from "react"; import {IndexRoute, Route} from "react-router"; import NotFound from './NotFound'; import App from './Page'; export default function(history) { return <Route path="/"> <IndexRoute component={App}/> <Route path='*' component={NotFound}/> </Router>; }
      
      





Redux



createStore



関数は、パラメーターとして初期状態を取り、新しいStore



を返す必要があります。







 // src/store.js import {createStore} from "redux"; function reducer(state, action) { return state; } export default function (initialState, {req, res}) { if (req) initialState = {foo: req.url}; return createStore( reducer, initialState ); }
      
      





サーバーで関数が呼び出されると、2番目のパラメーターにはNodeJSからのRequestオブジェクトとResponseオブジェクトが含まれます。一部の情報を抽出して、初期状態にすることができます。







メインエントリポイント



すべてをまとめて、サーバーからinitialProps



を取得する特別なラッパーを追加しましょう。







 // src/index.js import React from "react"; import {render} from "react-dom"; import {Provider} from "react-redux"; import {browserHistory, match, Router} from "react-router"; import {WrapperProvider} from "react-router-redux-middleware/wrapper"; import createRoutes from "./routes"; import createStore from "./store"; const Root = () => ( <Provider store={createStore(window.__INITIAL_STATE__)}> <WrapperProvider initialProps={window.__INITIAL__PROPS__}> <Router history={browserHistory}>{createRoutes()}</Router> </WrapperProvider> </Provider> ); render((<Root/>), document.getElementById('root'));
      
      





コンソールユーティリティを使用した単純なサーバーの起動



package.json



ファイルのscripts



セクションにスクリプトを追加します。







 { "build": "react-scripts build", "server": "create-react-server --createRoutes src/routes.js --createStore src/store.js }
      
      





そして走る







 npm run build npm run server
      
      





ブラウザでhttp://localhost:3000



を開くと、サーバー上に準備されたページが表示されます。







このモードでは、サーバーアセンブリの結果はどこにも保存されず、毎回その場で計算されます。







APIを介してサーバーを起動し、アセンブリ結果を保存する



コマンドライン機能が不足している場合、またはサーバーアセンブリの結果を保存する場合は、CLIではなくAPIを使用していつでもサーバーを作成できます。







以前のbabel-cli



に加えて、それをbabel-cli



し、サーバーをビルドするために必要になります。







 npm install babel-cli --save-dev
      
      





package.json



ファイルのscripts



セクションにスクリプトを追加します。







 { "build": "react-scripts build && npm run build-server", "build-server": "NODE_ENV=production babel --source-maps --out-dir build-lib src", "server": "node ./build-lib/server.js" }
      
      





したがって、クライアントパーツは引き続きReact Appの作成(React Scripts)によって収集され、サーバーパーツはBabelを使用して収集されます。Babelはすべてとsrc



を取得してbuild-lib



ます。







 // src/server.js import path from "path"; import express from "express"; import {createExpressServer} from "create-react-server"; import createRoutes from "./createRoutes"; import createStore from "./createStore"; createExpressServer({ createRoutes: () => (createRoutes()), createStore: ({req, res}) => (createStore({})), outputPath: path.join(process.cwd(), 'build'), port: process.env.PORT || 3000 }));
      
      





実行:







 npm run build npm run server
      
      





ここで、ブラウザーでhttp://localhost:3000



再度開くと、サーバー上に同じページが準備されていることがわかります。







完全なサンプルコードは、 https//github.com/kirill-konshin/react-router-redux-middleware/tree/master/examples/create-react-appにあります








All Articles