xiaoyunyang / looseleaf-node

Website built on the MERN stack (with react-router v4).
https://looseleafapp.com
12 stars 7 forks source link
express mongodb nodejs react-router-v4 reactjs

LooseLeaf - Node.js App

Getting Started

We are going to use the following stack:

Tools

Authentication and Database Middleware

Automated Testing

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

Tutorial

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.

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

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

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

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

Express

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:

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

Resources