New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wanted: Server-side rendering #1103
Comments
(NB just so that it is known, SSR seems to mix well with GraphQL. Relay, Apollo and Relate all seem to support it. E.g. the in-development Relax CMS created and uses Relate which has SSR, seems pretty neat. And I write this in brackets, because GraphQL clients are still on the experimental side 😉 see #1041 for more GraphQL discussion.) |
I've implemented SSR on some React projects and I plan to do that on my boilerplate (https://github.com/diegohaz/arc). I'll see if I can do that in |
if it helps, I have a project (much simpler than this, but still fully tested) which add SSR. It shows how to add SSR using Koa or Express: |
Looks like react-starter-kit provides SSR. |
It also looks like hjs-webpack provides SSR (but really I never configured SSR so don't know what I'm talking about). And anyway looks like a nice way to simplify the webpack configuration, automatically comes with dev server, transpiling, HMR, minifying and publishing. My only concern is lack of activity since 2 months. |
I guess Koa is the preferred server technology as it is more active? or are there others we should be looking into? |
That's how Este does server-side rendering with React Router 4. It's not only about a server-side rendering but also server-side data fetching. |
I'm self promoting here, but I just made a solution for this exact scenario, React checksums included: https://www.prerender.cloud/ |
After receiving a few responses over email, I realized it's probably better to discuss it publicly. So, if you are interested in helping, please respond here with:
Fyi, @miksago. Note that we plan to pay whoever builds this through react-boilerplate open collective. As in, we'd donate to opencollective.com/react-boilerplate (or help get the funds from others if it's beyond our budget). And then you can invoice that collective directly. |
@asood123 FYI a very interesting article (retweeted by Reactjs) on whether SSR is actually needed for SEO (do make sure to read the ongoing comments below as well). So although not having SSR might impact search rankings, it's at least inaccurate to say that it just isn't indexed at all, they might just not wait for async data. There's the "Fetch as Google" tool to check how your site is actually indexed. You could maybe give it a try? As for the performance aspect, I wonder how impactful SSR is compared to the other benefits already in RBP (e.g code splitting)? @mxstbr do you have production-grade websites based on RBP to share, so that people can see with their own eyes how fast the rendering already is? |
@asood123 I might be wrong, but I'm not sure if there is a "best" way to do SSR for any given React+Redux app. I've worked on some apps that use redux-saga to perform data tasks, and resolves using saga mechanisms. For other apps I've checked out a few libraries like redux-async-connect, and I've also wrote my own (react-transact -- excuse the lack of docs, but there are examples). The main problems for SSR are:
Luckily 3 and 4 are dead simple with Redux. However, I'd be hesitant to push for a single solution to do 1 and 2. Not sure what @mxstbr thinks of this? I don't mind sharing some ideas, just don't know if any solution is generic enough to be part of the boilerplate. In general, I'd avoid SSR if possible. It does add some performance gains (especially on mobile networks), and I'm sure SEO would improve, but it comes at the cost of added complexity. |
@jaysoo Sorry for spamming here, but this is already solved in Este: Waiting for the final render with timeout etc. Example in one component. Sure we can use the same pattern in every other component. Simple, elegant, battle tested, universal. |
@steida No worries about spamming. I still don't quite see how this addresses the issue universally though. Counter example When using redux-saga, you may have data tasks defined using generator functions. // using redux-saga
import { call, put, take } from 'redux-saga/effects'
function* requestThing() {
yield take('REQUEST_THING')
const data = call(fetch, ...)
yield put({ type: 'RESOLVED_THING', payload: data })
} This means components will only dispatch request actions, and the return type is Note: It is possible to run a root saga only for the SSR case that will await all data tasks to complete before resolve its promise object. Just need a convention for what this looks like. |
You don't believe me it works? It works for server side rendering and React Native both. Run Este on your computer and check this: |
@steida Not arguing it doesn't work for those cases. I've built several React apps with SSR myself, so I know the solution of provider+decorator+queue/manager works. I'm just bringing up another case that I don't think would work (without modification). Say I have a component like this: class MyPosts extends Component {
static contextTypes = { store: React.PropTypes.object }
componentWillMount() {
this.context.store.dispatch({
type: 'posts/REQUEST_POSTS'
})
}
render () { ... }
} Where the function* watchForRequestPosts() {
while (true) {
yield take('posts/REQUESTED_POSTS')
const posts = yield call(fetch, '/posts')
yield put({ type: 'posts/LOADED_POSTS', payload: posts })
}
} In this case, the Of course, there are many ways to get this to work with SSR, and I've done it before, it's just a matter of.
Since RPB recommends redux-saga, it is probably worth the consideration for SSR. |
Actually, didn't notice that RPB adds |
@jaysoo @steida I've just implemented this on this project using redux-saga: https://github.com/diegohaz/arc/tree/universal-redux Actions: export const postList = {
request: (limit, resolve, reject) => ({ type: POST_LIST_REQUEST, limit, resolve, reject }),
success: (list) => ({ type: POST_LIST_SUCCESS, list }),
failure: (error) => ({ type: POST_LIST_FAILURE, error })
} Saga: export function* listPosts (limit, resolve = fn, reject = fn) {
try {
const params = { _limit: limit }
const { data } = yield call(api.get, '/posts', { params })
resolve(data)
yield put(postList.success(data))
} catch (e) {
reject(e)
yield put(postList.failure(e))
}
}
export function* watchPostListRequest () {
while (true) {
const { limit, resolve, reject } = yield take(POST_LIST_REQUEST)
yield call(listPosts, limit, resolve, reject)
}
}
export default function* () {
yield fork(watchPostListRequest)
} Container component: class SamplePageContainer extends Component {
static post ({ req, store }) {
return Promise.all([
this.get({ store }),
store.dispatch(submit(config, req.body))
])
}
static get ({ store }) {
return new Promise((resolve, reject) => {
store.dispatch(postList.request(15, resolve, reject))
})
}
render () {
return <SamplePage />
}
} Server: app.use((req, res, next) => {
// ...
match({ history, routes, location: req.url }, (error, redirectLocation, renderProps) => {
// ...
const fetchData = () => new Promise((resolve, reject) => {
const method = req.method.toLowerCase()
const { params, location, components } = renderProps
let promises = []
components.forEach((component) => {
if (component) {
while (component && !component[method]) {
component = component.WrappedComponent
}
// try to call Component.method where method is the HTTP method name
component &&
component[method] &&
promises.push(component[method]({ req, res, params, location, store }))
}
})
Promise.all(promises).then(resolve).catch(reject)
})
// ...
fetchData().then(() => {
render(configureStore(store.getState(), memoryHistory))
}).catch((err) => {
console.log(err)
res.status(500).end()
})
})
}) |
@diegohaz That's pretty elegant, thanks for sharing! I guess generally if a request action is dispatched, there should be a resolve and reject handler that can be invoked by the corresponding saga. |
@asood123 I'll take a look at the RBP code today to see how long I can do this and give you an answer. 😊 |
Hi, @asood123, It will cost me about 3 working days. I will ask $750 for it. |
FYI there's |
I'll let @diegohaz take a stab at it. I will be on vacation soon for 3 weeks, and I have other work queued up at the moment. Happy to provide any support in terms of advice, etc. @sedubois That could be interesting approach for static sites. I'd also look at https://zeit.co/blog/next for inspiration. |
@diegohaz that sounds pretty reasonable. When will you be able to start? And React-boilerplate will pay out the invoice when ssr is merged into master. |
@asood123 I'll start a PR this monday. 😊 |
Not to interrupt your negotiations, but is this feature even wanted by the maintainers? I thought it was a conscious decision not to put ssr in the master branch? |
yes, we have been talking to @mxstbr. He'd like to get SSR support as well. |
Great @diegohaz. I believe in its current state, the DLL Bundle for this project gets compiled for In order to make SSR work, you will need to create the DLL Bundle for the JS |
I still have not managed to find the time to solve the problems I encountered and probably will not have time for this anytime soon. @tomazy contacted me and It seems he has a working solution. Just posting here to ensure that there is no problem if he (or another person) takes this in my place. |
I've created a new PR for this feature (#1236). There are still a few small things to be solved but in general it works. I'd appreciate if you guys could spend a minute on reviewing it to check if I don't make any design mistakes. |
Last I talked to @mxstbr, this was going to merged into master... |
I better understood the need for server-side rendering with this article: http://rauchg.com/2014/7-principles-of-rich-web-applications/#server-rendered-pages-are-not-optional |
Any estimate on when this will get merged in? @mxstbr We wanted to start using react-boilerplate, but SSR is a must have for us. Thanks! |
@WhatIfWeDigDeeper If you look at #1236 you can see there was activity a few hours ago. |
Thanks for the update. |
Please use the PR branch and let us know where it breaks so we can fix it before releasing it! The one reason I haven't merged the PR yet is that I don't know if it works for everything. The only way to find that out is by having people use it! So please use the PR branch by @tomazy and let us know how it goes! |
@mxstbr Its been a while since any activity here. Are you going to merge it? |
is the SSR effort abandoned? |
@hadifarnoud unfortunately there is currently no plan to land SSR support in react-boilerplate :( please see #1236 and #1776 for more information. specifically, please follow #1236 as there may be a maintained SSR fork that you can use... i am leaving this issue open for visibility until next release |
if there is a working pull request, why not merge it since a lot of people seem to want this feature? |
@diegohaz Thanks for sharing the example. I have implemented something similar to that in React Universal. I am using While I have everything working properly as I want, There seems to be a re-fetching in case of using the All up till the console.log is working with axios. Just Let me know if anything can be done about it to prevent re-fetching! Here is my
Thanks |
Is there any interest in taking another shot at this? I recently implemented SSR in my own fork of |
@smspillaz It was decided not to include SSR. we had the same issue as @asood123 and used this fork (had problems along the way but it works). It would be fantastic if @mxstbr helps the effort and allow that fork or any other implementation to merge. This is very important to many. btw, I'm interested to learn what is the difference between your fork and @tomazy. |
remembering back to the original conversation - i think the decision was to keep this project as a client-side only boilerplate. The hope being that it would help focus future changes and keep it simpler. You might come up against the same push-back that happened last time. I think if your PR enables client-side only and a SSR option, then you're on to a winner, especially if the changes to either are minimal. |
I agree heavily with @peter-mouland, couldn't have said it better. Having an SSR option in addition to client side only would be ideal. Adding in my two cents: I feel that SSR should be a decision based on project scopes and doesn't belong in a boilerplate. SSR can take a big toll on performance if you don't have a well thought-out project scope for both front and back end, and those alone open up large cans of worms that wouldn't be fair to put on the shoulders of a boilerplate. If anyone wants to restart the ball rolling with adding an SSR option, please feel free, as long as it is truly an option. See #2129 for a short list of what I'm currently working on, it may have a place in there as well. |
@smspillaz |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Hi! I work on OpenCollective - we help other open source projects (including react-boilerplate get funding.
We'd like to rebuild our frontend using React-boilerplate. But, Server-side rendering is a must for us - mostly for search crawlers and faster performance.
We are willing to pay someone to implement SSR in react-boilerplate and help the community out in the process. Would anyone be interested? You can reply on this issue.
Needless to say that whatever you build has to meet @mxstbr's approval and be merged into react-boilerplate to be considered complete.
Update: removed my email address. Prefer to discuss this publicly.
The text was updated successfully, but these errors were encountered: