cloverfield-tools / universal-react-boilerplate

A simple boilerplate Node app.
MIT License
904 stars 97 forks source link

Roadmap #4

Open ericelliott opened 9 years ago

ericelliott commented 9 years ago

Universal React Boilerplate

This is a universal JavaScript application boilerplate using Express & React.

Learn JavaScript with Eric Elliott

The Universal React Boilerplate was written for the "Learn JavaScript with Eric Elliott" courses. A series of courses to teach people how to build great JavaScript apps for production. Don't just learn JavaScript. Learn how to build amazing things.

Universal JavaScript

Universal (aka "isomorphic") means that it's designed to run a lot of the same code on both the client and the server. Typically that includes a lot of rendering and domain logic.

There are many advantages to building apps this way, but the primary advantages are:

I'm planning to put a lot of love into this and make it an essential resource for anybody interested in building production Node and Universal JavaScript applications. It's already very useful as-is, but we've been rewriting a lot of these things over and over again for every app, or searching through the haystack that is npm and spending too much time on tech selection instead of knowing what the best, most well-tested solutions are and running with them.

This boilerplate will eventually demonstrate a very simple production ready application, including:

In other words, everything you'd want to reuse in most production-ready applications -- all done for you using years worth of tried and true best practices.

Help wanted

Let me know in the comments if you'd like to help with any of these items.

Courses

Students will get a series of short videos, lots of interactive lessons explaining concepts in-depth, the ability to help and learn from each other, and a lot more.

eejs-screenshot

zebulonj commented 9 years ago

@ericelliott I'd like to help. I'm currently in the midst of a similar exercise as I work to break a legacy monolith down into micro-services... and as my first attempt at an isomorphic application I'm making up a lot as I go (so I don't pretend to have a lot of clear answers to offer). At the moment, the bit I'm most interested in is the isomorphic templates and rendering.

ericelliott commented 9 years ago

I have purposely not baked in a template system, but I'm considering changing that, using Minimongo, Track, and Blaze to do rendering on both the server and the client. It's a bit of a moving target, though, because the Meteor project doesn't seem to have any interest in maintaining an npm version of those libs.

Alternatively, we could show an example using React and Flux. Maybe those example implementations could be in a different repo which we link to from this one?

I'd love to hear your thoughts.

capaj commented 9 years ago

@ericelliott do you really think browserify is the way to go get trully isomorphic JS? To me it seems JSPM is more up to the task, because it allows for any kind of modules, not just CommonJS. Much more easy to develop with, because there is no need for build steps.

zebulonj commented 9 years ago

Regarding rendering... I'd lean toward React and Flux.

alexbasalyga commented 9 years ago

@capaj I don't think the goal here is to use a technology that supports every kind of module, but simply to use the best technology available (in terms of simplicity of use and how well its maintained) to allow the use of npm as both the server and client package manager. JSPM very well may be the best tool for the job if the job is packaging CommonJS and AMD modules beside each other for the browser, but I think the job at hand is smaller in scope.

ericelliott commented 9 years ago

@capaj We're interested in sharing the same code with the same source files authored in a single module format. JSPM may be a great solution for using ES6 modules in the browser, but I think it's a better fit to use Node style modules for code that is targeted at both Node and the browser, today. (That may change in the future, but it hasn't changed yet).

ericelliott commented 9 years ago

@zebulonj That combo definitely has the mindshare right now. :+1:

Should we be looking at trying to use JSX? Mixing markup into my JavaScript rubs me the wrong way.

I thought it was a great idea when PHP hit the scene. We all know how that played out... It was a bad idea then, and I'm not sure that anything has changed.

Also, if you're mixing markup into the JS, it seems like that puts an artificial limit targeting the output only to the DOM. IMO, one of the most attractive things about react is that it can target more than just the DOM...

zebulonj commented 9 years ago

@ericelliott I'm opening a new issue for this conversation about rendering (#13).

h02e56 commented 9 years ago

@ericelliott thanks for spread your knowledge.:) I've learned just seeing initial code. I would like to help someway. About project, i am more "frontend" but i like going deeper on server side. I have played a little with express, although nowadays i like use tiny modules instead. About put the scripts on place i use to put them on the same node_modules folder, and now i feel weird having 2 node_modules folder. for sure is is just a matter of habit.:) I could give a hand with i18n , or routing with page or client bundling(think is solved)

ivanoats commented 9 years ago

"Full-featured build system" - Grunt, Gulp, or stick to NPM scripts? What do you think of Gulp? I could help with that.

ericelliott commented 9 years ago

h02e56: RE 2 node_modules folders -- this solution is much better than scattering relative paths all over the codebase that make refactoring harder than it needs to be.

@ivanoats npm is a placeholder until we have a consensus for Cloverfield. PLEASE DO implement a gulp build in the todotasks repository. See the discussion in the Cloverfield repo.

terakilobyte commented 9 years ago

I'd love to help on this project, and am looking forward to your courses. As an aside, how do you feel about babeljs?

ericelliott commented 9 years ago

Babel and similar projects that let us use future language features are awesome. Bonus if it exports node-compatible modules so you can require() with Node and Browserify.

ericelliott commented 9 years ago

By the way, did you see the announcement? The first course has landed! We're letting students in and adding content. We're off and running. =)

ivanoats commented 9 years ago

@ericelliott I'd be happy to help but to clarify your request to implement gulp - isn't it already here? https://github.com/ericelliott/todotasks/tree/master/implementations/gulp

ericelliott commented 9 years ago

Oops! I completely forgot. Do you want to look it over and raise any issues or suggestions in that repo?

For now we're sticking with npm here unless / until we come to some consensus in Cloverfield. If you have anything to add to the Cloverfield taskrunner discussions, please add them.

One thing I like about a gulp implementation is that we have a better potential to make all the tasks completely cross-platform. I know we have some windows compatibility issues it might help resolve.

Then again, Broccoli might do the same thing for us, and it may have some advantages over Gulp... but the Broccoli vs Gulp vs x debate belongs in the Cloverfield discussion thread, so we can concentrate on isomorphic / Node / Express issues here. =)

Do you want to create a gulp implementation branch here that reproduces all the functionality in a way that is more Windows friendly? I might be willing to merge it if it clearly works better than our current implementation.

h02e56 commented 9 years ago

@ericelliott node_modules i was meaning putting them inside root node_modules node_modules/app/server node_modules/app/client

ericelliott commented 9 years ago

@h02e56 We don't put them into root node_modules because if you commit those to your repository, any time dependencies change, you get a ton of vendor noise in your pull requests, and code review becomes a bit of a nightmare.

I personally prefer that you make it easy to rm -rf node_modules if anything goes wrong with dependency updates. If you mix your modules with vendor modules, make changes in your modules, forget to commit, and then update dependencies, and something breaks, it can be hard to figure out what the working state was.

If your modules are not mixed with vendor modules and something goes wrong with a dependency update, you can safely rm -rf node_modules && npm install to get back to your working state -- even if you've made a bunch of changes and haven't committed them, yet.

That said, you should still commit often. ;)

ericelliott commented 9 years ago

Also, putting them in app/node_modules means that instead of typing require('app/lib/foo'); you can just type require('lib/foo');

Just a few keystrokes per require, but it adds up.

h02e56 commented 9 years ago

:+1: "That said, you should still commit often." thats a true "como la copa de un pino" as we say here

SOSANA commented 9 years ago

are we using a flux pattern with react.js?

nkbt commented 9 years ago

Until there is a Relay, Flux is the way to go if you as me. I've just rebuilt one of our angular modules during this sprint and first have done it without Flux at all. The code was boilerplaty as hell. Then added Flux and cleaned up to 30% of that mess right away. So I can't see any reasons not to use it as a default way to tackle data/app-state. No matter if it is React or angular.

Important question is if this particular boilerplate targets higher scope then just low-level-no-shared-state reusable React component or wants to handle more complex components? @ericelliott what's your idea on this?

SOSANA commented 9 years ago

@ericelliott @nkbt have you guys checked out https://github.com/optimizely/nuclear-js ? its a Flux architecture built with ImmutableJS data structures.

nkbt commented 9 years ago

Sure thing. Check Redux by Dan Abramov, please

ericelliott commented 9 years ago

@SOSANA @nkbt as per the "state management" item on the Roadmap, we're going with cerebral for the time being to manage state for container components. Stateless components for UI primitives (buttons, comboboxes, toggle switches, etc...)

Why Cerebral?

  1. It's built on immutables
  2. It features an integrated time-travel debugger
  3. It uses the single store pattern - closer to Relay / GraphQL ready than multi-store implementations
nkbt commented 9 years ago

Thanks. Sounds good

SOSANA commented 9 years ago

Interesting, I'll check it out

guifromrio commented 9 years ago

I would also vote for NuclearJS, as it seems far more mature than Cerebral, also relies heavily on ImmutableJS and does everything with little-to-no new concepts. Very lean, indeed.

ericelliott commented 9 years ago

@firstdoit @SOSANA I'm looking for a solution that has a working time-travel debugger -- not necessarily in the same module, but as part of a cohesive system. Nuclear's console.log() based debugging is cool, but seems considerably less convenient than the cerebral debugger.

Because it's based on Immutable.js, it's conceivable that you could add a debugger like that to Nuclear, but AFAIK, that hasn't happened yet.

Redux is another state management library worth watching. It has features and architecture similar to Nuclear, and the author has hinted at a time travel debugger on Twitter, but so far no details. =)

I'm on pins and needles...

gaearon commented 9 years ago

Give it a few days..

ericelliott commented 9 years ago

=)

nkbt commented 9 years ago

Redux is now in alpha. Probably the most FP-kind of flux. Give it a look https://github.com/gaearon/redux/releases/tag/v1.0.0-alpha @gaearon is doing very impressive job on that one.

ericelliott commented 9 years ago

:+1: yep. I'll be watching it closely. :)

guifromrio commented 9 years ago

@gaearon and @ericelliott, I appreciate the work on Redux greatly: a hot loadable flux implementation is pretty terrific. However, I feel it imposes lots of new concepts which the README does not explain that clearly. On the other hand, NuclearJS stores are really simple, with only two methods (getInitialState and initialize), and the only introduced concept is Getters, which are also fairly simple. @gaearon do you think redux could gravitate towards an API more similar to Nuclear? Or am I just missing the point here?

gaearon commented 9 years ago

However, I feel it imposes lots of new concepts which the README does not explain that clearly

The proper docs will be a focus in the next couple of weeks. The current README wasn't intended to be this way; it's just the project got way more popular faster than I expected.

There is also a work progress in updating the API and terminology to make more sense: https://github.com/gaearon/redux/pull/195. Unfortunately the docs aren't updated there either. I'll have more time to work on that after the conference tomorrow.

On the other hand, NuclearJS stores are really simple, with only two methods (getInitialState and initialize),

That sounds pretty fun to me, consider that “stores” in Redux are just functions. How can an object with two particular methods be simpler than a pure function? Especially considering that NuclearJS is tied to ImmutableJS, but Redux lets you use plain objects.

do you think redux could gravitate towards an API more similar to Nuclear?

The way I see see it, the API of Redux is simpler than the NuclearJS API. That's precisely the reason I started writing it, as I wasn't satisfied with the verbosity, the opinionatedness and the need to wrap everything in NuclearJS. In Redux, there is no createThisStuff, createOtherStuff, etc. Most of the time all you write are pure functions.

The docs are the real problem right now. We'll solve that. But I'd really love to hear your opinion on why you see the NuclearJS API being simpler than Redux.

zebulonj commented 9 years ago

My two-cents, I've found NuclearJS to be more complex (and definitely more opinionated) than either Redux or Cerebral.

More importantly... I'd like to see this conversation focus as much on how the available options help to solve hard problems related to complex application state, as on what the API looks like. One of the most valuable contributions I see in Cerebral—and I say this without advocating for its adoption—is that it helps to address hard problems like state syncing.

Too often, I have chosen a framework based on API and a list of features (immutability, functional style,...), then found myself in the woods trying to solve those hard problems that don't emerge until you get past the TodoMVC level of complexity.

ericelliott commented 9 years ago

It's much easier for me to wrap my head around building undo/redo/history scrub features on an API of pure functions than NuclearJS methods. I'll be really excited to see the upcoming Redux talk and reworked docs. I'm willing to work with cerebral in the meantime for existing projects.

guifromrio commented 9 years ago

What I meant by simplicity was actually being easier to use, as in "there's more functionality/opinion baked in". I understand, now, that redux means to be very very agnostic, so everything should happen on userland (action dispatching, for example, via bindActionCreators). That's interesting and valid, but I wouldn't call it "simpler" for a newbie :)

terakilobyte commented 9 years ago

Just to chime in, I've been using Este as a jumping point for a few personal projects. It might be worth looking at to take some ideas from. https://github.com/steida/este

On Thu, Jul 2, 2015 at 8:31 PM Guilherme Rodrigues notifications@github.com wrote:

What I meant by simplicity was actually being easier to use, as in "there's more functionality/opinion baked in". I understand, now, that redux means to be very very agnostic, so everything should happen on userland (action dispatching, for example, via bindActionCreators). That's interesting and valid, but I wouldn't call it "simpler" for a newbie :)

— Reply to this email directly or view it on GitHub https://github.com/ericelliott/universal-react-boilerplate/issues/4#issuecomment-118005039 .

vasco3 commented 9 years ago

What about including gzip support for html, js and css files ? I implemented that in express without middleware, very leanly. Using unix after the npm build https://github.com/vasco3/Apollo/blob/master/package.json#L10

And adding a route with proper encoding https://github.com/vasco3/Apollo/blob/master/app/app.js#L65-L69

Compression of ~75%

nkbt commented 9 years ago

Isn't it something should be done on level of nginx/apache? I am personally quite certain it should not exist on app level.

vasco3 commented 9 years ago

well its not on the app level.. its on express which is the server.

On Tue, Aug 4, 2015, 9:15 AM Nik Butenko notifications@github.com wrote:

Isn't it something should be done on level of nginx/apache? I am personally quite certain it should not exist on app level.

— Reply to this email directly or view it on GitHub https://github.com/cloverfield-tools/universal-react-boilerplate/issues/4#issuecomment-127662740 .

nkbt commented 9 years ago

Better not to use node as production server for various reasons. For dev - ok, but gzip is not needed for dev (usually)

ericelliott commented 9 years ago

@vasco3 Express has officially supported gzip middleware:

var compress = require('compression');

app.use(compress()); 

I think if we're going to include compression, that's how it should be done. It's easy to see @nkbt's perspective, too, but I don't see the harm in adding two lines to the sourcecode. I do see the harm in ignoring gzip altogether. If we don't at least mention it, people will forget about it. And that would not be good. =)

ericelliott commented 9 years ago

I don't feel strongly about it, so I'd accept a PR that adds those two lines, or I'd accept a PR that adds a mention in the README and links to detailed instructions for both nginx and haproxy.

vasco3 commented 9 years ago

will the compression middleware be compressing on every request? Or do we still need to compress on npm run build?

On Tue, Aug 4, 2015 at 4:08 PM Eric Elliott notifications@github.com wrote:

I don't feel strongly about it, so I'd accept a PR that adds those two lines, or I'd accept a PR that adds a mention in the README and links to detailed instructions for both nginx and haproxy.

— Reply to this email directly or view it on GitHub https://github.com/cloverfield-tools/universal-react-boilerplate/issues/4#issuecomment-127791337 .

therealklanni commented 9 years ago

It makes more sense to me to do this at the nginx level. It's probably faster at it, too.

vasco3 commented 9 years ago

@therealklanni do you mean using nginx as a proxy for Node express server?

vasco3 commented 9 years ago

What about cache busting?

nkbt commented 9 years ago

@vasco3 yes. Proxy for node server.