Nate's Work
- Got my front end with most of my nested routes set up this week.
- Used this blog post as a reference for setting up nested routes: https://tylermcginnis.com/react-router-nested-routes/
- Used this video as a reference for properly setting up react router v4 with create-react-app: https://egghead.io/lessons/react-run-the-react-router-v4-examples-with-create-react-app and this one https://reacttraining.com/react-router/web/guides/quick-start
- Used this article as a reference in better understanding how my app works https://www.fullstackreact.com/articles/deploying-a-react-app-with-a-server/
- Set up my server and front-end to successfully talk to each-other via http fetch requests
Explanation of File Structure and how my App is setup in development and production
- Below is a screenshot of my project directory. It's essentially a boilerplate rails app without any views. Instead, a client folder is nested inside with a boilerplate react app generated by create-react-app. Right now my dependency list is pretty minimal. Here's the package.json:
{
"name": "client",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3001",
"dependencies": {
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2",
"react-scripts": "1.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
- I added react-router-dom for routing purposes. It's a package that lets me decide which component is being rendered based on the url.
- I also added the line: "proxy": "http://localhost:3001, which tells the react development server to proxy requests to my rails server running on port 3001. This allows me to make http requests in development without generating cross-origin errors. This will be removed in production.
- In development I've set up a rake task using foreman that starts my webpack-dev-server at port 3000 and my rails server at port 3001. They both update as changes are made.
start.rake
namespace :start do
task :development do
exec 'foreman start -f Procfile.dev'
end
procfile.dev
web: cd client && PORT=3000 npm start
api: PORT=3001 && bundle exec rails s
- There's a bit of magic happening behind react-scripts start and react-scripts test. Here's an example of the dev dependencies in a project I made without create-react-app:
"devDependencies": {
"enzyme": "^3.1.0",
"jasmine-core": "^2.8.0",
"jasmine-enzyme": "^4.0.1",
"karma": "^1.7.1",
"karma-cli": "^1.0.1",
"karma-jasmine": "^1.1.0",
"karma-phantomjs-launcher": "^1.0.4",
"karma-webpack": "^2.0.5",
"phantomjs-prebuilt": "^2.1.15",
"react-addons-test-utils": "^15.6.2",
"react-test-renderer": "^16.0.0",
"webpack-dev-server": "^2.9.3"
}
- Lots of packages to set up the testing environment that are entirely encapsulated in "react-scripts: test". In my case I was using enzyme and jasmine to set up the mocking and testing library, using karma-webpack as the run-time environment and phantomjs as the headless browser. Create-react-app is set up to use jest which is billed to be all-inclusive.
- I believe "start": "react-scripts start" essentially just boots up the webpack-dev-server.
- Upon deployment "build": "react-scripts build" will get executed and export everything into a static, deployable bundle. There are two ways I'm considering deploying the app.
- One is to host my bundled react code as a static site on a service like amazon s3... or the apache server on my linnode, then host my rails back-end in a more responsive environment, either on heroku or with a bit more work, on my linnode. The user would download the static bundle of JS/CSS/HTML that make up react and that bundle would make requests to my API server.
- The other is to host them together in one environment and set it up so my rails server serves up my bundled JS/CSS/HTML at the root directory "/" and serves up the properly requested data at api/v1/classrooms and associated addresses. An example of one request can be seen here:
componentDidMount() {
fetch(`/api/v1/classrooms`, {
credentials: 'same-origin',
method: 'GET',
headers: { 'Content-Type': 'application/json' }
})
.then(response => {
if (response.ok) {
return response;
} else {
let errorMessage = `${response.status} (${response.statusText})`,
error = new Error(errorMessage);
throw(error);
}
})
.then(response => response.json())
.then(body => {
this.setState({classroomArray: body.classrooms})
})
.catch(error => console.error(`Error in fetch: ${error.message}`));
}