If you want to build a full stack web app with an HTML frontend, there are few ways faster and more flexible than Node.js. Be warned though, you’ll run into issues eventually if:
- The backend server needs to do anything CPU-heavy in Javascript
- The codebase won’t grow beyond a medium size (~10k lines of code).
Node.js is single threaded so doing any real math is generally a bad idea in a single-threaded language, and Javscript being untyped, is a pretty unreliable way to safely build huge codebases. You can get around both of these issues at times as many CPU-heavy Node.js libraries are actually proxies for multi-threaded C++ code. There’s also a surprising number of Typescript libraries for use, to the point where large, type-safe Javascript codebases actually become practical. The last big downside is learning to think in a non-blocking, asynchronous way, which is difficult for most developers at first. Python and PHP allow similar benefits without requiring out-of-order async thinking.
With the cons out of the way, we can now build a js frontend and backend app using mostly the same tools. That means less to learn, less to mess up, and much quicker dev cycles.
Quickstart: Picking a boilerplate
There’s seldom a reason to start a Node.js project from scratch as communities like github have literally thousands of maintained Node boilerplate setups. Having recently shopped among them, you should be most conscious of the following decisions to make:
- Pick an IDE. Don’t be that guy that builds it all in vim. I love vim, but there’s a reason those purists have beards they haven’t had time to cut since they learned it in 1978. If you can afford Webstorm, IntelliJ products are top-notch. Don’t laugh, but I still love Netbeans with an old Node.js plugin!
- A web framework. Express still seems to be a minimalistic favorite with a flexible “middleware” plugin framework within for app-specific customization like OAuth user authentication.
- A frontend framework. Please don’t use Angular. Just don’t. I try not to be opinionated but having led 2 similar web apps built on both, there’s little reason to use Angular anymore. React.js/JSX is queaky clean and highly encourages true event-driven architecture. When paired with Redux, you can follow the “Facebook Flux” UI pattern (I don’t know how they stole name credit for this old pattern, but they did). This pattern is more or less the best architecture for UI clients period, with very few exceptions like super-tiny projects. If your frontend needs to hide a button and that’s about it, just use jQuery and call it a day.
- Unit testing framework. If this is even remotely a production service, you need to have unit tests for nearly every module you build. This is even truer for Node than most other languages, since many Node frameworks like Express give you nearly free rein in code organization. Stick with Mocha or another widely-accepted test library.
- Pick a Javascript preprocessor. There’s maybe hundreds of compilers which take a “better” language and compiles it to js. You can pick from Flow, Typescript, Coffeescript and others. I personally prefer to keep it simple and use an ES6 or ES7 (official versions of js) compiler which then dumbs your code down to ES5 so it can run in old browsers. If you find yourself typing the word “function”, you’re doing it wrong. At least use ES6 for your own sanity.
- Optional – Pick a CSS preprocessor. I love SASS, and if you’re going to write CSS for more than just a few pages, learning it is worth the investment. SASS is what CSS should have been and compiles to regular CSS. LESS is good too.
- Optional – Server side rendering. Some React.js based boilerplate projects also include React’s “Server Side Rendering”. This is really quite powerful and improves the user experience since you can even cache pre-rendered React apps, giving both client and server little to do on each page load.
Keeping Scale in Mind
After taking a few minutes to get a boilerplate hello world app running, you’ll most likely want to store stuff like users or content. Node.js has amazing support for every major database you can imagine, and using a JSON-based database like MongoDB can make your app even simpler since you won’t need to write serialization code for communicating between Express and your database. If you can manage to store all of your app state either on the client’s browser or in your database, then congratulations, your app state is detached from your webserver so now you can spin up a whole lotta Node servers for lots of traffic. At this point your database becomes your main bottleneck as per usual.
So just how long will this take?
I’ve seen 3 man mobile client teams take 3x the time that it’s taken an amateur Javascript dev to deploy both a Node server and a full React frontend, without knowing either beforehand. The main trade-off here often comes later though as the complexity of the growing js app starts to crush a poorly thought out app architecture. Highly-tested, well-factored Node.js code with a Facebook Flux frontend needs to be enforced early on to avoid code complexity issues. Part of why Flux is great is that it makes it easy to test your frontend services layer without getting any UI code involved. The ever-common, lazy merger of business logic code with UI code is the #1 reason client devs don’t typically bother writing unit tests (because it’s nearly impossible!).