Ryan Doyle
Posted on April 15, 2019
For those of you following along, sorry it been nearly a month since the last post in this series! I did start the series having everything already completed and it became evident that I still had some learning to do! Good for learning, bad for regular blog posts. I wrote this post because of all the learning:
Article No Longer Available
Let's Get started!
Getting Ready for the Frontend
Ok. The first thing we need to do is some housekeeping. (If you've been following along with me, we've got everything set up in a single folder. What I am going to be doing now is moving everything to a structure where the current files for the backend are in a "backend" folder while I have a separate "frontend" folder for all of that.
So, in the root of my project I added a backend folder and a frontend folder, then dropped everything that existed into the backend folder. I had to update all the require('') statements accordingly, but in VS Code it all happened automatically for me.
So now we've got this structure:
You should be able to go into backend/ in your terminal and make sure everything is working still by running nodemon index.js
.
If everything is still good, I like to add a script in my package.json so I don't have to remember that command. In package.json, go ahead and add the following code. It will allow you to start up the backend server by typing npm run dev
opposed to the nodemon index.js
.
"scripts": {
"dev": "nodemon index.js"
},
Frontend with Next.js
For this project I will be using Next.js. It's a really robust framework that offers a lot of nice things like server-side rendering for React. It's also easy to get started with because it has features like a pages folder, where all component in that folder become pages you can navigate to. It also has a nice way to link to other pages that's super easy so it's great for this purpose.
Set up Next.js
First, we need to go into our frontend folder, and we are going to install Next, React, and React DOM. In addition, we also make a folder for our components, the pages, and a lib folder for a high order component.
npm init -y
npm install --save react react-dom next
mkdir pages components lib
With Next installed, we can now do a number of things!
- Create a High Order Component for Apollo to work
- Create a custom _app.js component (Main app that gets passed to the Apollo Client component)
- Create a custom _document.js component (Overrides the normal document creation for server-side rendering.
Create a High Order Component
First, we need to install a few more things.
npm i --save next-with-apollo apollo-boost
Next With Apollo: This is basically a component that we pass our Apollo Client to which will eventually wrap up our entire application.
Apollo Boost: Apollo Boost is just a package that contains the most-used Apollo client packages. Essentially there a many individual packages you can use, but most people use a core set, so they have them all as apollo-boost.
To make the HOC component, I created ApolloHOC.js in my lib folder.
import withApollo from 'next-with-apollo';
import ApolloClient from 'apollo-boost';
function createClient({ headers }) {
return new ApolloClient({
uri: process.env.NODE_ENV === 'development' ? `http://localhost:4000` : `http://localhost:4000`,
request: operation => {
operation.setContext({
fetchOptions: {
credentials: 'include',
},
headers,
});
},
});
}
export default withApollo(createClient);
So, let's walk through the code above. First we import next-with-apollo and apollo-boost.
Next we are creating the function createClient, which accepts headers (for SSR) and returns an instance of the Apollo Client. To that, we pass in the endpoint of our backend (the localhost:4000) as well as set the requests to include the header credentials with all requests, and also pass along those headers.
Basically, we need to pass the headers along with all requests (this is something happening from next-with-apollo) and also set credential to "include" so our app could do authentication if we wanted to. Overkill for this tutorial, but a good starting place for other projects.
Finally, we export the HOC withApollo
that we require from next-with-apollo, passing in out Apollo Client.
Create our custom _app.js
Next, we need to create a custom _app.js file in out pages directory. This is pretty well documented in the Next.js docs but it essentially is where we wrap up our entire app with the withApollo component to expose our entire frontend to the Apollo Client. My custom _app.js is as follows.
import App, { Container } from 'next/app';
import { ApolloProvider } from 'react-apollo';
import withApollo from '../lib/ApolloHOC';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
render() {
const { Component, pageProps, apollo } = this.props;
return (
<Container>
<ApolloProvider client={apollo}>
<Component {...pageProps} />
</ApolloProvider>
</Container>
);
}
}
export default withApollo(MyApp);
Basically, the only difference between mine (above) and the example provided in the Next.js docs is that I also destructure apollo
from the props and that gets put in the ApolloProvider as props. I don't actually remember where I found these examples, but the docs for the Apollo Provider explains wrapping your app. Alright, so now our components should have access to the Apollo Client!
Create custom _document.js
Another thing that I do is create a custom _document.js. The custom document is to "Is used to change the initial server-side rendered document markup". Basically, I mostly use this to hook up Styled Components, but it seems like for server-side rendering it has a lot of uses.
import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet();
const page = renderPage(App => props => sheet.collectStyles(<App {...props} />));
const styleTags = sheet.getStyleElement();
return { ...page, styleTags };
}
render() {
return (
<html>
<Head>{this.props.styleTags}</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
I got his custom _document.js from the Next.js Examples with Styled Components
A Few more Installs
If you try and start everything up right now, you'll get some errors due to some peer dependencies going on. I also have styled-components
required in the _document.js so, let's install the following:
npm i --save styled-components graphql react-apollo
Basic Pages
To get ready for making out first graphQL query & mutation, we'll need a few basic pages. Go ahead and create the files addItem and viewItems in your pages directory and put in the following:
addItem.js
import React from 'react';
const addItem = () => {
return (
<div>
<p>Add item form will go here</p>
</div>
);
};
export default addItem;
viewItems.js
import React from 'react';
const viewItems = () => {
return (
<div>
<p>Items will show here!</p>
</div>
);
};
export default viewItems;
Check That Everything Works!
Ok, before checking that everything works, I will (same as the backend) go to my package.json in the frontend and add the script "dev":"next"
and that will allow me to just type in npm run dev
to start up the frontend.
You can now run npm run dev
within the frontend and backend directories and be up and running! You should be able to navigate to localhost:3000/addItem to see "Add item form will go here" from our paragraph tag in the addItem.js
file, and similarly for to localhost:3000/viewItems to see "Items will show here!".
All Set Up!
Hopefully, everything should be good to go now! In the next post, I'll look at creating a GraphQL Query!
Posted on April 15, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.