├── .gitignore ├── LICENSE.md ├── Procfile ├── README.md ├── client ├── package.json ├── public │ ├── favicon.ico │ └── index.html └── src │ ├── App.js │ ├── DB.js │ ├── index.css │ └── index.js ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kevin Schaich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node server.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Full-Stack Starter Kit 2 | 3 | Full-stack React boilerplate using [`create-react-app`](https://github.com/facebookincubator/create-react-app), [Babel](https://babeljs.io/), [Node.js](https://nodejs.org/en/), and [express](https://expressjs.com/). Plays nicely with DB connectors such as [MongoDB](https://www.npmjs.com/package/mongodb), [Mongoose](https://www.npmjs.com/package/mongoose), [MySQL](https://www.npmjs.com/package/mysql) and many others. 4 | 5 | Fully-updated for ES6 syntax. 6 | 7 | Loosely Based on [Fullstack React's demo](https://github.com/fullstackreact/food-lookup-demo), just leaned-out. Check out their [blog post](https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/) for details on how the proxy setup allows a concurrent client/server side. 8 | 9 | ## Installation/Usage 10 | 11 | **Run the following in your terminal:** 12 | 13 | ```bash 14 | git clone https://github.com/kevinschaich/react-full-stack-starter 15 | cd react-full-stack-starter 16 | npm install 17 | 18 | cd client 19 | npm install 20 | 21 | cd .. 22 | npm start 23 | ``` 24 | 25 | Visit [http://localhost:3000](http://localhost:3000) in your browser to see the server running! 26 | 27 | **Note for Windows Users:** If you encounter errors during installation, I recommend giving [CMDer](http://cmder.net/) a try. 28 | 29 | ## Example DB Connection with MongoDB 30 | 31 | #### Install MongoDB 32 | 33 | Make sure you have [MongoDB installed](https://docs.mongodb.com/manual/installation/). If you don't have any databases set up, you can run this command to populate a few rows (be sure to change `db-name` and `collection-name`): 34 | 35 | `mongo db-name --eval 'db.collection-name.insert({"name": "John Doe"}, {"name": "Jane Doe"})'` 36 | 37 | Run the following in the **root directory** of the repository: 38 | 39 | `npm install --save mongodb` 40 | 41 | #### Configure MongoDB 42 | 43 | In the top of `server.js`, add the following lines to import Mongo and set the database URI. Be sure to replace `database-name-here` with the name of your database in Mongo. 44 | 45 | ```javascript 46 | const MongoClient = require('mongodb').MongoClient; 47 | const url = 'mongodb://localhost:27017/database-name-here'; 48 | ``` 49 | #### Retrieve objects from DB 50 | 51 | Now, near the bottom of `server.js`, update the `app.get('/api'...)` route to retrieve data from your DB. Be sure to replace `collection-name-here` with the name of your collection in Mongo. 52 | 53 | ```javascript 54 | app.get('/api', (req, res) => { 55 | MongoClient.connect(url).then(db => { 56 | const cursor = db.collection('collection-name-here') 57 | .find({}) 58 | .limit(5) 59 | .toArray() 60 | .then((data) => { 61 | res.json(data); 62 | }); 63 | }).catch(err => { 64 | console.log(err); 65 | }); 66 | }); 67 | ``` 68 | 69 | Your server should be pulling items from the database when it receives a call to `/api`. You can test this by visiting [http://localhost:3001/api](http://localhost:3001/api) and see if the response is displayed properly. 70 | 71 | #### Update Client Code 72 | 73 | Back on the client side, in `client/src/App.js`, you need to update your `render` method to match the format of objects in MongoDB. For example, if your stored objects in Mongo look like the following: 74 | 75 | ```json 76 | [ 77 | {"name": "Person1", "age": 38}, 78 | {"name": "Person2", "age": 27}, 79 | ] 80 | ``` 81 | 82 | You could change the mapping to populate the `name` field of each item on the page like so: 83 | 84 | ```jsx 85 | const items = this.state.items.map( 86 | (item, i) => (

{item.name}

) 87 | ); 88 | ``` 89 | 90 | Run the server using `npm start` -- you should see items from your DB being populated on the page! 91 | 92 | 93 | ## Deploying to Heroku 94 | **Install the Heroku CLI and set up your account if you haven't already.** 95 | [Follow the instructions here.](https://devcenter.heroku.com/articles/heroku-cli) 96 | 97 | **Run the following in your terminal** 98 | ``` 99 | # cd into client folder and run the build script 100 | cd client 101 | npm run build 102 | cd .. 103 | 104 | # commit the changes to git 105 | git add . 106 | git commit -m "build for deployment" 107 | 108 | # create the heroku app and deploy 109 | heroku create 110 | git push heroku master 111 | ``` 112 | 113 | ## Contributing/Pull Requests 114 | 115 | Please feel free to submit issues/pull requests! I welcome any corrections or suggestions that could make the repository better for others to use and build off of as well. 116 | 117 | ## License 118 | 119 | MIT © [Kevin Schaich](https://kevinschaich.io) 120 | 121 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-full-stack-starter-client", 3 | "version": "0.0.1", 4 | "private": true, 5 | "proxy": "http://localhost:3001/", 6 | "devDependencies": { 7 | "react-addons-test-utils": "15.4.0", 8 | "react-scripts": "0.8.5" 9 | }, 10 | "dependencies": { 11 | "react": "15.4.0", 12 | "react-dom": "15.4.0" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinschaich/react-full-stack-starter/f042586f1b48736ff7f8bb29dea0492c96463283/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | Full-Stack React Page 17 | 18 | 19 |
20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /client/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DB from './DB'; 3 | 4 | class App extends React.Component { 5 | state = {items: []}; 6 | 7 | componentDidMount() { 8 | const search_value = 'your-search-terms-here'; 9 | DB.search(search_value, (items) => { 10 | this.setState({items: items}); 11 | }); 12 | } 13 | 14 | render() { 15 | const items = this.state.items.map( 16 | (item, i) => (

{item.name}

) 17 | ); 18 | return ( 19 |
20 | {items} 21 |
22 | ); 23 | } 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /client/src/DB.js: -------------------------------------------------------------------------------- 1 | const parseJSON = (response) => { 2 | return response.json(); 3 | } 4 | 5 | const checkStatus = (response) => { 6 | if (response.status >= 200 && response.status < 300) { 7 | return response; 8 | } 9 | const error = new Error(`HTTP Error ${response.statusText}`); 10 | error.status = response.statusText; 11 | error.response = response; 12 | console.log(error); 13 | throw error; 14 | } 15 | 16 | const search = (query, cb) => { 17 | return fetch('api', { 18 | accept: 'application/json', 19 | }).then(checkStatus) 20 | .then(parseJSON) 21 | .then(cb); 22 | } 23 | 24 | const DB = { search }; 25 | export default DB; 26 | -------------------------------------------------------------------------------- /client/src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinschaich/react-full-stack-starter/f042586f1b48736ff7f8bb29dea0492c96463283/client/src/index.css -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import './index.css'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root'), 9 | ); 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-full-stack-starter-server", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "babel-cli": "6.14.0", 7 | "babel-core": "6.14.0", 8 | "express": "4.13.3" 9 | }, 10 | "scripts": { 11 | "start": "concurrently \"npm run server\" \"cd client && npm start\"", 12 | "server": "babel-watch server.js", 13 | "dev": "echo \"This command has been deprecated. Use 'npm start'\" && exit 1", 14 | "lint": "eslint ." 15 | }, 16 | "devDependencies": { 17 | "babel-watch": "^2.0.6", 18 | "concurrently": "3.1.0", 19 | "eslint": "3.15.0", 20 | "eslint-config-airbnb": "14.1.0", 21 | "eslint-plugin-import": "2.2.0", 22 | "eslint-plugin-jsx-a11y": "4.0.0", 23 | "eslint-plugin-react": "6.9.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const fs = require('fs'); 3 | 4 | const app = express(); 5 | 6 | app.set('port', (process.env.PORT || 3001)); 7 | 8 | // Express only serves static assets in production 9 | if (process.env.NODE_ENV === 'production') { 10 | app.use(express.static('client/build')); 11 | } 12 | 13 | app.get('/api', (req, res) => { 14 | // Place code to fetch items from DB here 15 | res.json([ 16 | {name: 'Person1', age: 38}, 17 | {name: 'Person2', age: 27}, 18 | ]); 19 | }); 20 | 21 | app.listen(app.get('port')); 22 | --------------------------------------------------------------------------------