Skip to content

Instantly share code, notes, and snippets.

@panacholn
Last active May 12, 2017 02:22
Show Gist options
  • Save panacholn/44e9af99ad93a4d43b42473c9c658bb2 to your computer and use it in GitHub Desktop.
Save panacholn/44e9af99ad93a4d43b42473c9c658bb2 to your computer and use it in GitHub Desktop.
SSR Workshop
Part 1 : Config Server
// ไฟล์ src/server/server.js
1. import ไฟล์ตามนี้
const createMemoryHistory = require('react-router/lib/createMemoryHistory');
const configureStore = require('../common/stores').default;
const { syncHistoryWithStore } = require('react-router-redux');
const { RouterContext, match } = require('react-router');
const routes = require('../common/routes').default;
const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
const { Provider } = require('react-redux');
const React = require('react');
2. สร้าง function สำหรับ render html template
const renderHTML = renderedComponent => (`
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://bootswatch.com/flatly/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/dist/styles.css" />
</head>
<body>
<div id="root">${renderedComponent}</div>
</body>
<script src="/dist/bundle.js"></script>
</html>
`);
3. แก้ใน app.get ให้เป็น
const memoryHistory = createMemoryHistory(req.originalUrl);
const store = configureStore(memoryHistory);
const history = syncHistoryWithStore(memoryHistory, store);
match({
location: req.originalUrl,
routes: routes(store, history),
}, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.redirect(302, `${redirectLocation.pathname}${redirectLocation.search}`);
} else if (renderProps) {
const renderedComponent = renderToStaticMarkup(
<Provider store={store} key="provider">
<RouterContext {...renderProps} />
</Provider>,
);
res.status(200).send(renderHTML(renderedComponent));
} else {
res.status(404).send('Not Found');
}
});
Part 2 : Babel / CSS
// ไฟล์ src/server/index.js
1. เพิ่ม babel-register กับ css-modules-require-hook
require('babel-register');
const hook = require('css-modules-require-hook');
hook({ extensions: '.scss' });
Part 3 : Prefetch Data
// ไฟล์ src/common/containers/CommentList.js
1. เพิ่มโค้ดตามนี้
CommentList.prefetchAction = [
() => getList(),
];
// สร้างไฟล์ src/server/prefetchData.js
2. เพิ่มโค้ดตามนี้
export default function prefetchData(dispatch, components, renderProps) {
const prefetchActions = components
.filter(component => component)
.reduce((prev, current) => {
const wrappedComponent = current.WrappedComponent;
return (current.prefetchAction || [])
.concat((wrappedComponent && wrappedComponent.prefetchAction) || [])
.concat(prev);
}, []);
return Promise.all([...new Set(prefetchActions)].map(prefetchAction => dispatch(prefetchAction(renderProps))));
}
// ไฟล์ src/server/server.js
3. เพิ่ม import ไฟล์
const prefetchData = require('./prefetchData').default;
4. แก้ใน else if (renderProps)
const { components } = renderProps;
prefetchData(store.dispatch, components, renderProps)
.then(() => {
const renderedComponent = renderToStaticMarkup(
<Provider store={store} key="provider">
<RouterContext {...renderProps} />
</Provider>,
);
res.status(200).send(renderHTML(renderedComponent));
});
Part 4 : Remove Duplicate Request
// ไฟล์ src/server/server.js
1. แก้โค้ด function renderHTML ให้รับ preloadState
const renderHTML = (renderedComponent, preloadState)
2. เพิ่ม preloadState ใน HTML template
<script>window.preloadState = ${JSON.stringify(preloadState)}</script>
<script src="/dist/bundle.js"></script>
3. ส่ง state เข้า function renderHTML
res.status(200).send(renderHTML(renderedComponent, store.getState()));
// ไฟล์ src/client/index.js
4. แก้โค้ดให้รับ state จาก HTML และ set เข้า store
const preloadState = window.preloadState || {};
const Store = store(browserHistory, preloadState);
// ไฟล์ src/common/containers/CommentList.js
5. แก้ให้ function เช็คว่ามีข้อมูลรึเปล่าก่อนจะ fetch ข้อมูล
componentDidMount() {
if (this.props.list.length === 0) {
this.props.onGetList();
}
}
@aofleejay
Copy link

part1:

const createMemoryHistory = require('react-router/lib/createMemoryHistory');
const configureStore = require('../common/stores').default;
const { syncHistoryWithStore } = require('react-router-redux');
const { RouterContext, match } = require('react-router');
const routes = require('../common/routes').default;
const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
const { Provider } = require('react-redux');
const React = require('react');

@aofleejay
Copy link

part2: ข้อ 3 ที่รับ parameter preload state ใน store ไม่ต้องแก้ละ เพิ่มไปใน step 0 แล้ว

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment