Skip to content

xiaoyunyang/looseleaf-node

Repository files navigation

LooseLeaf - Node.js App

Getting Started

We are going to use the following stack:

  • Platform: node
  • Framework: express
  • CSS Framework: materialize
  • CSS Preprocessor: SASS
  • JavaScript Framework: React with react-router v4 and react-router-config
  • Build Tool: webpack
  • Unit Testing: mocha, chai
  • Integration Testing: SuperTest and cheerio.
  • Database: mongodb
  • Authentication: facebook, email, google, github, twitter
  • Deployment: digitalOcean

Tools

Authentication and Database Middleware

  • mongoose - object modeling for our MongoDB database
  • passport - help us authenticating with different methods

Automated Testing

  • mocha sets up the unit test, while chai helps you accomplish a unit test using asserts.
  • SuperTest spools up your Express server and sends requests to it.Once the requests come back, you can make assertions about the response.
  • cheerio is jQuery for Node. It'll help your server code parse HTML.

Baseline App

Take the following steps to create a baseline app:

  1. Follow this tutorial to set up a create-react-app with react-hot-loader

    React Hot Loader allows you to tweak React components in real time.

  2. Follow this tutorial to set up the rest of the create-react-app project to use react-router. We are going to use Version 4.x of the React Router, which is a complete rewrite of Versions 3.x and prior.

    Warning: Implementing the Build, Run & Develop section in the second tutorial could cause react-hot-loader to not work so this section wasn't implemented in the baseline app, which is available for download on Github.

  3. FullStackReact's Tutorial and Sample Project - A create-react-app with server example

    • Pro: Builds a client app to run concurrently with a server app.
    • Con: This helps you build a single page application. If you want to build a isomorphic webapp, proceed with the next step.
  4. Isomorphic Webapp Book Chapter 2 Sample Code Learning

Docs

File Structure

$ tree -l 3 --ignore 'node_modules'
looseleaf-node
├───package.json
├───.babelrc
├───.env <== #C
├───server
│   ├───server.js <== #B
│   ├───start-client.js	 
│   ├───run.js <== #A
│   ├───build
│   ├───data <== #A
│   ├───assets <== #A
│   └───api
|   	 └───api1.js <== #A and #B
├───test
├───client
│   ├───package.json
│   ├───config
│   ├───public
|   |   └───favicon.ico
|   |   └───index.html  <== #B
│   ├───src
│   |   └───shared
|   |   |   ├───Profile
|   |   |   |   ├── App.js <== #A
|   |   |   |   ├── HTML.js <== #A
|   |   |   |   ├── Header.js
|   |   |   |   ├── Home.js
|   |   |   |   ├── Main.js
|   |   |   |   ├── NotFound.js
|   |   |   |   └── routes.js <== #A
|   |   |   └───Recipe
|   |   |       ├── App.js
|   |   |       ├── HTML.js
|   |   |       └── ...
│   |   ├───AppUser.js <== #B
│   |   └───index.js <== #B
│   |   └───main.js <== #A
|   ├───iso-middleware
|   |   ├── renderRoute.jsx <== #D
|   |   └── renderView.jsx <== #D

Notes

  • Lots of extraneous folders and files were omitted from the file structure map above because they are auto-generated when you first set up your project or after when you build the project
  • #A: These files are the entry points for the isomorphic webapp.
  • #B: These files are associated with the create-react-app, which includes HMR and react-hot-loader for better development work flow. index.js and index.html are the entry points. index.js renders component that attaches to the root componnent identified in the index.html file.
  • #C: These files are omitted from the github repo because they contain authentication ids, secrets, etc that are application-specific
  • #D: These files are used by the server to render html pages using React code shared with the client.

Tutorial

  • React Express

    Facebook provides a command-line utility called create-react-app which automatically sets up a new React project with a sensible default project structure and feature set. This is the best way to get started as a beginner.

    You'll likely outgrow this option pretty quickly as you get a better grasp of React and want to customize your stack. Fortunately, create-react-app offers an eject option to export your app, so you're not locked in.

  • create-react-app

Create React App is agnostic of the backend, and just produces static HTML/JS/CSS bundles.

Running the App

Before running the app, you have to set up a few things:

  1. From the project directory, run the command:

    $ npm install && cd client && npm install && cd ..
    $ mkdir server/build
    

    This installs all the dependencies in your package.json from for both the server and the client. Everytime you make changes to package.json, npm install needs to be run so that the dependencies defined in the file would get downloaded by npm. The dependencies gets downloaded into a folder called node_modules.

  2. Set up your database for the app:

    MongoDB

    • Install MongoDB: $ brew install mongodb

    • Create the data directory: $ sudo mkdir -p /data/db

    • Set permissions for the data directory:

       $ sudo chown -R `whoami` /data/db
      
    • Run MongoDB server: $ mongod

    • Run MongoDB shell in a separate terminal: $ mongo

    • Some useful commands to run in the mongo shell

       > use test $ switch to db test
       > show collections $ list all collections inside current db
       users
       > db.users.find() $ in the users collection, return all documents
       > db.users.remove( { } ) $ remove all documents in the users collection
       > db.users.remove( { index } )
       > db.users.dropIndexes()
      

Check out Azat Marda's Cheatsheet, Quick Reference, and Little Mongo Handbook for more useful commands.

  1. If you are developing on the client side only, $ cd client then $ npm run build or $ yarn build - Build the project. For production builds, you'll want to use npm run build to build an optimized bundle and transpiled down to ES5, which will be saved to the filesystem. If you don't have hot reloading enabled, you have to run this after making changes to your source code to allow the changes to take effect next time you start the client server. This is undesirable and there are a few workarounds, in particular, nodemon and react-hot-reloader, which will be discussed in more detail below.

  2. For developing an integrated client and server app, we want to run the isomorphic webapp with the following command line:

    $ npm start
    

    This will give us access to:

    $ npm build-client
    
  3. For developing an server and client separately

    • To run both the server and client in separately, do the following, which starts the server to automomatically listen on port 3001 (http://localhost:3001/) and the client to automomatically listen on port 3000 (http://localhost:3000/).

       $ npm start-dev
      

      If the single page application doesn't render correctly on the server, you need to do this:

       # npm build-client
      

      The npm start-dev script is equivalent to running npm run start-server and npm run start-client concurrently. We learn how to do that from FullStackReact's Tutorial and Sample Project.

    • To run just the server app, do

       $ npm run start-server
      
    • To run both the client and server app, do

       $ npm start-dev
      
    • To run the client app, do

       $ npm run start-client
      

      Alternatively,

       $ cd client && npm start
      

      In this mode, you can use react-hot-loader to make changes to react components in runtime.

      Just go to http://localhost:3001/api/hello to see change being made.

      If you want to run on other ports, like 9000, 8000, 8080, just specify the port you want:

       $ PORT=9000 npm start
      
    • To run the server to serve static content:

       $ yarn global add serve
       $ serve -s build
      

      In this mode, you can't use react-hot-loader because the client app is rendered on the server side.

  4. Stop the database server when you are done:

    • Stop the postgres database
    $ pg_ctl -D /usr/local/var/postgres stop
    
    • Or if you use mongo: control+C

Redux

redux is a manager of global variables for React components.

Middleware

  • redux-thunk - allows you to write action creators that return a function instead of an action. redux-thunk allows you to delay the dispatch of an action or to dispatch only if a certain condition is met. A thunk is a function that wraps an expression to delay its evaluation.
  • redux-promise - receives a promise, dispatch the resolved value of the promise, but will not dismatch anything if the promise rejects.
  • redux-logger - logging tool that lets you replay problems as if they happened in your own browser.
  • react-redux - We need to use connect from react-redux to connect a React component to a Redux store.

Express

  • morgan - log every request to the console
  • body-parser - get information from html forms

Authentication

See the tutorial for how to set up passport and postgresql with your react-node app.

We also need to create a controller for creating the User object after the user enters all the required information:

$ mkdir controllers
$ touch controllers/user.js

The user controller will include logic for creating a new user and authenticating a returning user. The user controller relies on the User model for creating a new User. The user controller requires the following dependencies:

  • async - We will be using async.waterfall a lot, which:

    Runs the tasks array of functions in series, each passing their results to the next in the array. However, if any of the tasks pass an error to their own callback, the next function is not executed, and the main callback is immediately called with the error.

  • nodemailer - a module for Node.js applications to allow easy as cake email sending.

  • jsonwebtoken

  • moment - is a lightweight Javascript date library for parsing, validating, manipulating, and formatting dates.

  • request - Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.

  • querystring - Node's utilities for parsing and formatting URL query strings.

Oauth

  1. Install dependencies
    • moment, which is a lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
    • react-cookie, which lets you load and save cookies with React.

CSS

We are using materialize-css, which depends on jquery. Add the following to the client project:

$ cd client
$ npm install --save materialize-css
$ npm install --save jquery
$ touch src/assets/index.css

The index.css is where the custom styles for you app go. This will override the materialize-css style if you add the following imports to your index.js (or whatever the main entry point of your client app is):

// src/index.js

import 'materialize-css'
import 'materialize-css/dist/css/materialize.min.css';
import './assets/index.css';

To use materialize components in your react components, import jquery and add the script in componentDidMount:

// src/components/Header.js
import React from 'react'
import { Link } from 'react-router-dom'
import $ from 'jquery'

class Header extends React.Component {
  componentDidMount() {
    $(".dropdown-button").dropdown()
  }
  render() {
    // TODO: nav and dropdown menu
  }

What about CSS javascripts? Read the full stack react tutorial for more on that.

DevTools

  • morgan - quest logger middleware for node.js
  • webpack
  • babel
  • immer - a tiny package that allows you to work with immutable state in a more convenient way. It is based on the copy-on-write mechanism.
  • mobx - Simple, scalable state management

Resources