Skip to content

Commit

Permalink
introduce apollo
Browse files Browse the repository at this point in the history
  • Loading branch information
arthur791004 committed Aug 16, 2019
1 parent d46fc5a commit c54f347
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 91 deletions.
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GITHUB_TOKEN=
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const config = {
es6: true,
},
globals: {
window: true,
document: true,
fetch: true,
},
Expand All @@ -24,6 +25,7 @@ const config = {
'import/prefer-default-export': 0,
'no-else-return': 0,
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'react/jsx-one-expression-per-line': 0,
'react/jsx-props-no-spreading': 0,
'react/jsx-wrap-multilines': [
'error',
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

# misc
.DS_Store
.env*
.env

# debug
npm-debug.log*
Expand Down
9 changes: 9 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require('dotenv').config();

const config = {
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
},
};

module.exports = config;
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
"lint-eslint": "eslint --ignore-path .gitignore"
},
"dependencies": {
"@apollo/react-hooks": "~3.0.1",
"@apollo/react-ssr": "~3.0.1",
"apollo-boost": "~0.4.4",
"apollo-link-context": "~1.0.18",
"dotenv": "~8.0.0",
"graphql": "~14.4.2",
"isomorphic-unfetch": "~3.0.0",
"next": "9.0.3",
"react": "16.9.0",
"react-dom": "16.9.0",
Expand Down
33 changes: 31 additions & 2 deletions pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
import React from 'react';
import App from 'next/app';
import Head from 'next/head';
import { ApolloProvider } from '@apollo/react-hooks';
import { getDataFromTree } from '@apollo/react-ssr';
import { createApolloClient } from '@/services/apollo';
import GlobalStyle from '@/components/GlobalStyle';

const getInitialApolloState = async (AppTree, props) => {
const client = createApolloClient();

await getDataFromTree(<AppTree {...props} apolloClient={client} />);

// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind();

return client.extract();
};

export default class MyApp extends App {
static async getInitialProps(context) {
const { AppTree } = context;
const props = App.getInitialProps ? await App.getInitialProps(context) : {};
const apolloState = await getInitialApolloState(AppTree, props);

return { ...props, apolloState };
}

constructor(props) {
super(props);
this.apolloClient = createApolloClient(props.apolloState);
}

render() {
const { Component, pageProps } = this.props;

return (
<>
<ApolloProvider client={this.apolloClient}>
<GlobalStyle />
<Component {...pageProps} />
</>
</ApolloProvider>
);
}
}
130 changes: 47 additions & 83 deletions pages/index.js
Original file line number Diff line number Diff line change
@@ -1,91 +1,55 @@
import React from 'react';
import Link from 'next/link';
import Head from 'next/head';
import Nav from '../components/nav';
import { gql } from 'apollo-boost';
import { useQuery } from '@apollo/react-hooks';

const Home = () => (
<div>
<Head>
<title>Home</title>
</Head>
const QUERY_REPOSITORIES = gql`
query repositories($type: SearchType!, $query: String!, $first: Int) {
search(type: $type, query: $query, first: $first) {
nodes {
... on Repository {
id
nameWithOwner
description
updatedAt
url
stargazers {
totalCount
}
}
}
}
}
`;

<Nav />
const variables = {
type: 'REPOSITORY',
query: 'blog',
first: 10,
};

<div className="hero">
<h1 className="title">Welcome to Next.js!</h1>
<p className="description">
To get started, edit <code>pages/index.js</code> and save to reload.
</p>
const Home = () => {
const { loading, error, data } = useQuery(QUERY_REPOSITORIES, { variables });

<div className="row">
<Link href="https://github.com/zeit/next.js#getting-started">
<a className="card">
<h3>Getting Started &rarr;</h3>
<p>Learn more about Next.js on GitHub and in their examples</p>
</a>
</Link>
<Link href="https://github.com/zeit/next.js/tree/master/examples">
<a className="card">
<h3>Examples &rarr;</h3>
<p>Find other example boilerplates on the Next.js GitHub</p>
</a>
</Link>
<Link href="https://github.com/zeit/next.js">
<a className="card">
<h3>Create Next App &rarr;</h3>
<p>Was this tool helpful? Let us know how we can improve it!</p>
</a>
</Link>
</div>
</div>
if (loading) {
return <div>Loading...</div>;
} else if (error) {
return <div>Oop...{error.toString()}</div>;
}

<style jsx>{`
.hero {
width: 100%;
color: #333;
}
.title {
margin: 0;
width: 100%;
padding-top: 80px;
line-height: 1.15;
font-size: 48px;
}
.title,
.description {
text-align: center;
}
.row {
max-width: 880px;
margin: 80px auto 40px;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.card {
padding: 18px 18px 24px;
width: 220px;
text-align: left;
text-decoration: none;
color: #434343;
border: 1px solid #9b9b9b;
}
.card:hover {
border-color: #067df7;
}
.card h3 {
margin: 0;
color: #067df7;
font-size: 18px;
}
.card p {
margin: 0;
padding: 12px 0 0;
font-size: 13px;
color: #333;
}
`}</style>
</div>
);
return (
<div>
{data.search.nodes.map(
({ id, nameWithOwner, description, updatedAt, url }) => (
<div key={id}>
<div>{nameWithOwner}</div>
<div>{description}</div>
<div>{updatedAt}</div>
<div>{url}</div>
</div>
)
)}
</div>
);
};

export default Home;
47 changes: 47 additions & 0 deletions services/apollo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ApolloClient, InMemoryCache, HttpLink } from 'apollo-boost';
import { setContext } from 'apollo-link-context';
import fetch from 'isomorphic-unfetch';
import { getIsBrowser } from '@/utils';

const GRAPHQL_URL = 'https://api.github.com/graphql';
const isBrowser = getIsBrowser();

let client = null;

const httpLink = new HttpLink({
uri: GRAPHQL_URL,
fetch: !isBrowser && fetch, // eslint-disable-line global-require
});

const authLink = setContext((_, { headers }) => {
const token = process.env.GITHUB_TOKEN;
const authorization = token ? `Bearer ${token}` : '';

return {
headers: {
...headers,
authorization,
},
};
});

const create = initialState =>
new ApolloClient({
ssrMode: !isBrowser,
link: authLink.concat(httpLink),
cache: new InMemoryCache().restore(initialState || {}),
});

export const createApolloClient = initialState => {
// create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (!isBrowser) {
return create(initialState);
}

if (!client) {
client = create(initialState); // eslint-disable-line no-underscore-dangle
}

return client;
};
1 change: 1 addition & 0 deletions utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const getIsBrowser = () => typeof window === 'undefined';
Loading

0 comments on commit c54f347

Please sign in to comment.