cloverfield-tools/universal-react-boilerplate

Roadmap

ericelliott opened this issue · 72 comments

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:

  • Cross-functional teams. Since everything is written in JavaScript, it's easier to build teams who know how to work on both the client and server sides of the app.
  • Write once, run everywhere. With the exception of a few library substitutions and browser polyfills, the code is shared, which means you have to write about half the code you'd write working on a non-universal app.
  • More productive developers. Since the app is more consistent across the stack, there's no context switching when you need to maintain application behavior on both sides of the stack. Write the behavior once, and you're done. Context switching slows developers down significantly.

Roadmap

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

@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.

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.

@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.

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

@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.

@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).

@zebulonj That combo definitely has the mindshare right now. 👍

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...

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

@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)

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

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.

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

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.

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. =)

@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

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.

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

@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. ;)

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.

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

are we using a flux pattern with react.js?

nkbt commented

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?

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

nkbt commented

@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

Interesting, I'll check it out

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.

@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...

Give it a few days..

nkbt commented

👍 yep. I'll be watching it closely. :)

@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?

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: reduxjs/redux#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.

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.

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.

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 :)

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
#4 (comment)
.

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

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
#4 (comment)
.

nkbt commented

@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. =)

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.

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
#4 (comment)
.

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

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

What about cache busting?

nkbt commented

@vasco3 yes. Proxy for node server.

Yep. Everywhere I've pushed Node into production, we've had nginx & or haproxy, or both set up to reverse-proxy to our Node instances -- even for my smallest personal website deployment, I used nginx as a reverse proxy layer so I could route to different services easily.

Is it possible to have multiple versions of the boilerplate? From most simple to advanced.

It's not only possible, it's likely. =)

What are we considering for CSS?
I've used https://github.com/sass/node-sass successfully.
or maybe we could leverage the webpack css loader

What about code coverage with codeCov.io ? 😃

nkbt commented

@vasco3 I prefer coveralls and use it for all my projects. Works well, but requires some minimal extra manual setup (set ENV vars in CI)

@nkbt does Coveralls use xml like CircleCI or json? I had that discrepancy with CircleCI + CodeCov eg. https://github.com/vasco3/Oracul/blob/master/circle.yml#L18-L19
btw great job with the tap-xunit + CircleCI implementation

nkbt commented

Thanks, @vasco3!
Yep it does. Not XML, but normal lcov.info

- cat ${CIRCLE_ARTIFACTS}/coverage/lcov.info | ./node_modules/.bin/coveralls

https://github.com/nkbt/react-component-template/blob/master/circle.yml

I use || true so coverage report does not break build in case of service is down or something. But it could be removed of course

@nkbt how do you like isparta over babel-istanbul?

nkbt commented

Used isparta before babel-istanbul was there, works well, so I feel no need to swap it to something else for now.

Hey guys, do you plan to include Redux in the project? If that so, I can help you including redux-devtools and the config for react hot reloading and reducers hot reloading.

react-kickstart uses hot-module-replacement (babel-plugin-react-transform + react-transform-hmr)

Yes, I plan to use Redux + HMR.

nkbt commented

HMR is added by #67

I think for react HMR you need this babel plugin: react-transform-hmr, with this config: .babelrc.

nkbt commented

@gacosta89 that is how it is done in #67 =)

:( sorry.

nkbt commented

@gacosta89 no worries 👌

What about writing a test for the reducers that have been added recently? Would be a great feature to show the users a good example on how the reducer can be tested (simple functions). Might have some time for it this week.

What about writing a test for the reducers that have been added recently? Would be a great feature to show the users a good example on how the reducer can be tested (simple functions). Might have some time for it this week.

Sure. Please use tape and keep them simple.

Hey guys! what do you thing of i18next for translations? I used it along with react-i18next in production. It has a very nice defaults and overrides system for keys.

nkbt commented

We used it in our prod app and moved to node-gettext for several reasons
(one of those - inability to do plurals in-place, so we had to have en.js
file, which is essentially wrong, and overall awkward syntax for templates
and plurals). In general I would recommend to stick to a standard
implementation - gettext. If you want some friendlier gettext solution,
check 'jed'
On Tue., 18 Oct. 2016 at 03:42, gacosta89 notifications@github.com wrote:

Hey guys! what do you thing of i18next http://i18next.com/ for
translations? I used it along with react-i18next
https://github.com/i18next/react-i18next in production. It has a very
nice defaults and overrides system for keys.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#4 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKsoDPknB8KHkh94sxlmLriDKDioHcIks5q06VagaJpZM4Dd88f
.