Closed gaearon closed 9 years ago
What if npm start
printed a message like Run "npm run dev" for development, and "npm run prod" for production
? npm run dev
would launch both server and WebpackDevServer, npm run prod
would use compiled assets. Does this make any sense?
cc @erikras @davezuko who have experience with universal examples
That could work. I'm tweaking some my stuff in #642 around the port numbers and what it prints to screen when booting up.
As for the last point, it's implied that everything except client.js
and server.js
is universal stuff. But I'm ambivalent about it. I personally keep everything top-level (following @erikras's lead on that), but don't mind reorganizing if that's more standard.
Let's reorganize.
Also, a few things:
<Root>
component'root'
instead of 'app'
for consistency with other examplesapi
folder. Let's remove 'Increment async' because it's counter intuitive what it does in the context of this example?api
folder actually is a good example of something that would go in server/
folder because it's not used on client.
Just addressed the first two bullet points in this issue in my other PR. I don't think we should worry about production usage, because there are too many assumptions about setup there. Running a universal app in production on Heroku and your own Ubuntu box is drastically different.
api
isn't universal in this example, but would be in other contexts. Take a blogging engine. That would have a way to fetch the posts on the page, which would apply to the initial server-side render and then as you browse around. I'd want to hint at that so people don't end up writing two versions of the same thing.
@timdorr
api isn't universal in this example, but would be in other contexts.
In this case we need "increment" action to work through server, otherwise its role is confusing. Bonus point: optimistic update.
I guess my point is: we have two places with setTimeout
calls. actions
and api
confuse me because they look very similar and the relationship is obscured. I'd assume api
is what runs on server (actual REST-like API), and actions
is how I access it, both on client and server.
Hmm, I didn't want to get into a real API example, since that starts touching on things way outside of the realm of redux (a HTTP client like superagent
or whatwg-fetch
and more express coding). Hence the fake async via a setTimeout
. I figure those looking for a more sophisticated example could check out awesome-redux or react-redux-universal-hot-example.
But yeah, we can get rid of the async increment action. That was some copy pasta on my part.
Oh! I could, rather than wrapping the initial render in a promise to prefetch data, instead just use redux-promise
to issue an initial action and hook into the .then
returned from dispatch
to send the response once it resolves. That would make it so the entire prefetch is redux-based.
Yes, or you could use redux-thunk
which we use in Reddit example for the same purpose.
A bit late to the party, but I really like that dev vs. prod approach @gaearon; it's something I've been toying with integrating into the react-redux-starter-kit, since right now the server essentially just acts like your prod
example.
I originally thought just having a prod
mode would suffice, and didn't really want to have to run babel/register against the server, but after looking at the universal Redux example it definitely seems more convenient to be able to differentiate between serving a live vs. compiled app.
I do have a question about the existing universal example, though. Since only one webpack bundle gets compiled, how would non-js imports be handled? Currently the application is able to render on the server because it makes use of babel/register
, but once you get into importing any of the things that make webpack awesome (images, styles, etc.), I'm not sure how well this method holds up.
I was temporarily avoiding this issue by never running a non-compiled application from the server, but that makes server development fairly tedious. I'm at a loss for how the current example would accommodate these features. Does anybody have experience with this?
Again, I didn't want to make any decisions about how someone might use it in production. There a eleventy bajillion ways of doing it and many options to consider (Data uri images or static files? Hash cache busting? etc etc.). Those are an exercise in how you might set up webpack, which has nothing to do with redux and how you use it with server rendering.
I was temporarily avoiding this issue by never running a non-compiled application from the server, but that makes server development fairly tedious. I'm at a loss for how the current example would accommodate these features. Does anybody have experience with this?
One way is to just use Webpack for Node server. Not everybody would be on board with this though.
I agree with @timdorr regarding keeping the scope to minimum. That said,
redux-thunk
(even just initially)should be covered because it's related to universal rendering.
@hedgerh and I had talked about that in the PR on his repo. I think those sort of "next steps" items should be put in an advanced recipe. Possibly a sort of "Tying It All Together" recipe.
Do you have a sense of when react-router is going to land a 1.0 (or at least 1.0-rc)? There look to be substantial changes upcoming, so it might be a good idea to wait a bit to avoid having to re-write such an article later on.
1.0 isn't likely to change much from betas. 2.0 will be interesting but it'll take more time.
I'd keep it open because there's still api
/ actions
weirdness. Let's close when we refactor it to use async actions all the way.
OK, sounds good.
What do you think about refactoring around react-transform
and webpack-hot-middleware
(since we're already using Express)?
What do you think about refactoring around react-transform and webpack-hot-middleware (since we're already using Express)?
Sounds good to me, but this would need to be done for all examples at once.
Well, in light of #690, I can focus on just the hot-middleware conversion. Shouldn't be that much work.
What about including the efforts of #721 in the universal example? Or is that too much stuff in one place? I worry it might be getting too specific and guiding new users towards having to set up all this stuff just to get started with redux (rather than starting minimally and tacking on features as needed)
Wouldn't #721 actually simplify the universal example by doing everything via Express?
I mean more in terms of adding devTools into the mix. It's becoming the kitchensink
example instead of the universal
example :smile:
No, I don't want to add DevTools there.
OK, I'll just do hot-middleware and call it a day.
@timdorr it is understandably out of scope of the redux documentation to go into how to run a universal example in production, but it also is a little annoying coming across "in production you wouldn't do this and it's out of scope to talk about what you should do". I've been incredibly impressed by the redux documentation and think it would be awesome if there was an "advanced recipe" like you mentioned, or just resources where people new to universal apps can learn more about them.
The only mention of scope comes with the handling of static files. That's entirely a configuration thing that you would handle with nginx or whatever frontend webserver you have. That's something left to your sysadmin (which may be yourself!) to determine how to handle.
Nonetheless, that section of the docs was removed in #766 and will be put into the next documentation rebuild.
Outside of that, I do all of the things in the universal example in my real world production apps. There might be a slight change here or there, but it's almost entirely the same thing. This is production-ready code.
@timdorr good to know, thanks!
Here's a few issues I'd like to see addressed:
localhost:8080
in it instead oflocalhost:3000
. I'd rather change it to be the other way: put app server at3000
and use something like3001
for WebpackDevServer. This way you don't have to memorize which example you are running.npm start & npm run client
in universal example. I struggled with non-working example for 15 minutes before figuring that out. This is obvious to someone experienced with server rendering, but wasn't obvious to me. I missed that part in the doc, and I'm sure a lot of people willnpm start
and expect things to happen.client
,server
anduniversal
folder structure at the very top, which signals which modules are related to which part. Lots of universal examples follow that structure and we should do it too.