![ユニバーサルコア](https://habrastorage.org/getpro/habr/post_images/aa5/93e/0ab/aa593e0ab706ce2e62348625507615fe.jpg)
現在、普遍的な(同形の)コードをめぐる多くの論争があり、賛否両論があります。
サーバーとクライアントのレンダリングを最大限に活用できるため、将来はユニバーサル(同形)コードにあると考えています。
開発中に、私たちのチームは良いボイラープレートを手に入れ、それを共有することにしました。 コードはここにあります 。
このトピックに関する非常に良いチュートリアルがあるので、私は水を注ぎたくありません:
- React.js:同形/ユニバーサルアプリケーションをゼロから構築します。 パート1
- React.js:同形/ユニバーサルアプリケーションをゼロから構築します。 パート2
- React.js:同形/ユニバーサルアプリケーションをゼロから構築します。 パート3
コアとは:
- Koajs 2.0:新世代フレームワークの新世代
- ES2017のスタイルでKoaJS 2のマイクロサービスを作成しています。 パートI:そのような異なる非同期性
- ES2017のスタイルでKoaJS 2のマイクロサービスを作成しています。 パートII:最小限のREST
開発用プロジェクトの開始:
git clone https://github.com/BoryaMogila/koa_react_redux.git; npm install; npm run-script run-with-build;
url:localhost(127.0.0.1):4000 / app /でテスト実行を確認できます
実動用のプロジェクトの開始:
// npm run-script build-production; // npm run-script run-production;
サーバースクリプトが収集され、遅延ロードを使用する場合、ルートの最初の要求はコード変換のために戻るのに約2秒かかるため、babel-registerは使用されません。
クライアントスクリプトも、gzip形式の実稼働アセンブリ用にアセンブルされます。 スクリプトを配布するには、koa-serve-static(非常に便利)の代わりにnginxを使用することを強くお勧めします。 サーバーコードはappフォルダーにあり、isomorphicおよびclientはsrcフォルダーにあります。
apiのコントローラーをフォルダーkoa_react_redux / app / controllers /に書き込みます。
//koa_react_redux/app/controllers/getPostsController.js export default async function(ctx) { // . //................ // json ctx.body = [ { title: 'React', text: 'React is a good framework' }, { title: 'React + Redux', text: 'React + Redux is a cool thing for isomorphic apps' }, { title: 'React + Redux + React-router', text: 'React + Redux + React-router is a cool thing for isomorphic flexible apps' } ] }
タイプ別にファイルkoa_react_redux / app / routes / index.jsにサーバールートを登録します。
import getPosts from '../controllers/getPostsController'; router.get('/getPosts/', getPosts);
ファイルkoa_react_redux / src / routes.jsにユニバーサルルートを記述します。
import React from 'react'; import Route from 'react-router/lib/Route' import IndexRoute from 'react-router/lib/IndexRoute' import App from './components/App'; // lazy-loading const getPosts = (nextState, callback) => require.ensure( [], (require) => { callback(null, require("./containers/Posts").default) } ), getPost = (nextState, callback) => require.ensure( [], (require) => { callback(null, require("./containers/Post").default) } ); function createRoutes() { return ( <Route path="/app/" component={App}> // lazy-loading, // <IndexRoute omponent={/**/}/> <IndexRoute getComponent={getPosts}/> <Route path='post/:id' getComponent={getPost}/> </Route> ) } export default createRoutes
reduxの一般的なミドルウェアは、koa_react_redux / src / storeCinfigurator.jsファイルで標準として接続されています
import { createStore, combineReducers, compose, applyMiddleware } from 'redux' import promiseErrorLogger from './middlewares/promiseErrorLogger' createStore( combineReducers({ ...reducers }), initialState, compose( applyMiddleware( promiseErrorLogger, ) ) )
koa_react_redux / src / index.jsファイルのクライアントミドルウェア:
import promiseErrorLogger from './middlewares/promiseErrorLogger' import { configureStore} from './storeCinfigurator' configureStore(browserHistory, window.init, [promiseErrorLogger]);
ファイルkoa_react_redux / app / controllers / reactAppController.jsのサーバーサイドの例え。
非同期アクション:
import {GET_POSTS} from './actionsTypes' import superagentFactory from '../helpers/superagentFactory' const superagent = superagentFactory(); export function getPosts(){ return { type: GET_POSTS, payload: superagent .get('/getPosts/') .then(res => res.body) } }
非同期アクションレデューサーの場合:
import {GET_POSTS, PENDING, SUCCESS, ERROR} from '../actions/actionsTypes'; export default function(state = [], action = {}){ switch (action.type){ case GET_POSTS + SUCCESS: return action.payload; case GET_POSTS + PENDING: return state; case GET_POSTS + ERROR: return state; default: return state; } }
reduxのリデューサーは、ファイルkoa_react_redux / src / reducers / index.jsで接続されています。
import { combineReducers } from 'redux'; import { routerReducer } from 'react-router-redux' import posts from './postsReducer' const rootReducer = { posts, routing: routerReducer }; export default rootReducer;
koa_react_redux / config /フォルダー内のconfig jsと同様に、一般的な構成を記述し、同形使用のための独自のラッパーを作成しました。
サーバー構成は次のように記述します。
const config = { // }; // for cut server-side config if (typeof cutCode === 'undefined') { Object.assign(config, { // }); } module.exports = config;
SEOの場合、チームはヘルメットライブラリを使用します))))( 反応ヘルメット )
次のように機能します。
// import Helmet from "react-helmet"; <div className="application"> <Helmet htmlAttributes={{"lang": "en", "amp": undefined}} // amp takes no value title="My Title" titleTemplate="MySite.com - %s" defaultTitle="My Default Title" base={{"target": "_blank", "href": "http://mysite.com/"}} meta={[ {"name": "description", "content": "Helmet application"}, {"property": "og:type", "content": "article"} ]} link={[ {"rel": "canonical", "href": "http://mysite.com/example"}, {"rel": "apple-touch-icon", "href": "http://mysite.com/img/apple-touch-icon-57x57.png"}, {"rel": "apple-touch-icon", "sizes": "72x72", "href": "http://mysite.com/img/apple-touch-icon-72x72.png"} ]} script={[ {"src": "http://include.com/pathtojs.js", "type": "text/javascript"}, {"type": "application/ld+json", innerHTML: `{ "@context": "http://schema.org" }`} ]} onChangeClientState={(newState) => console.log(newState)} /> ... </div>
ルートで接続するコンテナにサーバーレンダリング用のデータを書き込みます。
import {getPosts} from '../actions' class Posts extends Component { constructor(props) { super(props); } // static fetchData(dispatch, uriParams, allProps = {}) { const promiseArr = [ dispatch(getPosts()), ]; // return Promise.all(promiseArr); } render(){ return ( // ); } }
PSインシデントと信頼性を回避するために、個々のプロジェクトにapiとスクリプトを配布することをお勧めします。 あなたのコメントやコメントを聞いてうれしいです。