♻️ spaces

This commit is contained in:
Sergey Yarkov 2020-03-02 22:41:26 +03:00
parent aff870be16
commit c5fb489720
12 changed files with 1772 additions and 217 deletions

View File

@ -7,6 +7,6 @@ const ARTICLES_QUERY = gql`
title
}
}
`;
`
export default ARTICLES_QUERY
export default ARTICLES_QUERY

View File

@ -2,25 +2,25 @@ import Link from 'next/link'
import classes from './Header.module.scss'
const Header = () => (
<header className={classes.Header}>
<ul>
<li>
<Link href='/'>
<a>Index</a>
</Link>
</li>
<li>
<Link href='/about'>
<a>About</a>
</Link>
</li>
<li>
<Link href='/articles'>
<a>Articles</a>
</Link>
</li>
</ul>
</header>
<header className={classes.Header}>
<ul>
<li>
<Link href='/'>
<a>Index</a>
</Link>
</li>
<li>
<Link href='/about'>
<a>About</a>
</Link>
</li>
<li>
<Link href='/articles'>
<a>Articles</a>
</Link>
</li>
</ul>
</header>
)
export default Header
export default Header

View File

@ -1,14 +1,14 @@
import Header from '../Header/Header'
const Layout = props => {
return (
<>
<Header />
<main>
{props.children}
</main>
</>
)
return (
<>
<Header />
<main>
{props.children}
</main>
</>
)
}
export default Layout
export default Layout

View File

@ -1,17 +1,19 @@
import { useQuery } from '@apollo/react-hooks'
const Query = ({ children, query, id }) => {
const { data, loading, error } = useQuery(query, {
variables: {id}
})
const { data, loading, error } = useQuery(query, {
variables: { id }
})
if (loading) return (
<div className="uk-container">
<p>loading...</p>
</div>
if (loading) {
return (
<div className="uk-container">
<p>loading...</p>
</div>
)
if (error) return <p>Error: {JSON.stringify(error)}</p>
return children({ data })
}
if (error) return <p>Error: {JSON.stringify(error)}</p>
return children({ data })
}
export default Query
export default Query

View File

@ -5,13 +5,13 @@ import Head from 'next/head'
*/
const SEO = props => {
const { pageTitle } = props
const { pageTitle } = props
return (
<Head>
<title>{pageTitle}</title>
</Head>
)
return (
<Head>
<title>{pageTitle}</title>
</Head>
)
}
export default SEO
export default SEO

View File

@ -6,9 +6,9 @@ import fetch from 'isomorphic-unfetch'
const GRAPHQL_URL = process.env.BACKEND_URL || 'http://localhost:3000/api/graphql'
let apolloClient = null
let apolloClient = null
/**
/**
* Creates and provides the apolloContext
* to a next.js PageTree. Use it by wrapping
* your PageComponent via HOC pattern.
@ -16,117 +16,117 @@ const GRAPHQL_URL = process.env.BACKEND_URL || 'http://localhost:3000/api/graphq
* @param {Object} [config]
* @param {Boolean} [config.ssr=true]
*/
export function withApollo (PageComponent, { ssr = true } = {}) {
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
const client = useMemo(
() => apolloClient || initApolloClient(apolloState),
[]
)
return (
<ApolloProvider client={client}>
<PageComponent {...pageProps} />
</ApolloProvider>
)
}
// Set the correct displayName in development
if (process.env.NODE_ENV !== 'production') {
const displayName =
export function withApollo (PageComponent, { ssr = true } = {}) {
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
const client = useMemo(
() => apolloClient || initApolloClient(apolloState),
[]
)
return (
<ApolloProvider client={client}>
<PageComponent {...pageProps} />
</ApolloProvider>
)
}
// Set the correct displayName in development
if (process.env.NODE_ENV !== 'production') {
const displayName =
PageComponent.displayName || PageComponent.name || 'Component'
if (displayName === 'App') {
console.warn('This withApollo HOC only works with PageComponents.')
}
WithApollo.displayName = `withApollo(${displayName})`
if (displayName === 'App') {
console.warn('This withApollo HOC only works with PageComponents.')
}
// Allow Next.js to remove getInitialProps from the browser build
if (typeof window === 'undefined') {
if (ssr) {
WithApollo.getInitialProps = async ctx => {
const { AppTree } = ctx
let pageProps = {}
if (PageComponent.getInitialProps) {
pageProps = await PageComponent.getInitialProps(ctx)
}
// Run all GraphQL queries in the component tree
// and extract the resulting data
const apolloClient = initApolloClient()
try {
// Run all GraphQL queries
await require('@apollo/react-ssr').getDataFromTree(
<AppTree
pageProps={{
...pageProps,
apolloClient
}}
/>
)
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// Handle them in components via the data.error prop:
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
console.error('Error while running `getDataFromTree`', error)
}
// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind()
// Extract query data from the Apollo store
const apolloState = apolloClient.cache.extract()
return {
...pageProps,
apolloState
}
WithApollo.displayName = `withApollo(${displayName})`
}
// Allow Next.js to remove getInitialProps from the browser build
if (typeof window === 'undefined') {
if (ssr) {
WithApollo.getInitialProps = async ctx => {
const { AppTree } = ctx
let pageProps = {}
if (PageComponent.getInitialProps) {
pageProps = await PageComponent.getInitialProps(ctx)
}
// Run all GraphQL queries in the component tree
// and extract the resulting data
const apolloClient = initApolloClient()
try {
// Run all GraphQL queries
await require('@apollo/react-ssr').getDataFromTree(
<AppTree
pageProps={{
...pageProps,
apolloClient
}}
/>
)
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// Handle them in components via the data.error prop:
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
console.error('Error while running `getDataFromTree`', error)
}
// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind()
// Extract query data from the Apollo store
const apolloState = apolloClient.cache.extract()
return {
...pageProps,
apolloState
}
}
}
return WithApollo
}
/**
return WithApollo
}
/**
* Always creates a new apollo client on the server
* Creates or reuses apollo client in the browser.
* @param {Object} initialState
*/
function initApolloClient (initialState) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (typeof window === 'undefined') {
return createApolloClient(initialState)
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = createApolloClient(initialState)
}
return apolloClient
function initApolloClient (initialState) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (typeof window === 'undefined') {
return createApolloClient(initialState)
}
/**
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = createApolloClient(initialState)
}
return apolloClient
}
/**
* Creates and configures the ApolloClient
* @param {Object} [initialState={}]
*/
function createApolloClient (initialState = {}) {
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
const isBrowser = typeof window !== 'undefined'
return new ApolloClient({
connectToDevTools: isBrowser,
ssrMode: !isBrowser, // Disables forceFetch on the server (so queries are only run once)
link: new HttpLink({
uri: GRAPHQL_URL, // Server URL (must be absolute)
credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
// Use fetch() polyfill on the server
fetch: !isBrowser && fetch
}),
cache: new InMemoryCache().restore(initialState)
})
}
function createApolloClient (initialState = {}) {
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
const isBrowser = typeof window !== 'undefined'
return new ApolloClient({
connectToDevTools: isBrowser,
ssrMode: !isBrowser, // Disables forceFetch on the server (so queries are only run once)
link: new HttpLink({
uri: GRAPHQL_URL, // Server URL (must be absolute)
credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
// Use fetch() polyfill on the server
fetch: !isBrowser && fetch
}),
cache: new InMemoryCache().restore(initialState)
})
}

1556
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,5 +21,15 @@
"optimize-css-assets-webpack-plugin": "^5.0.3",
"react": "16.13.0",
"react-dom": "16.13.0"
},
"devDependencies": {
"eslint": "^6.8.0",
"eslint-config-node": "^4.0.0",
"eslint-config-standard-jsx": "^8.1.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-standard": "^4.0.1"
}
}

View File

@ -1,5 +1,5 @@
import '../assets/css/global.scss'
export default function Application({ Component, pageProps }) {
return <Component {...pageProps} />
export default function Application ({ Component, pageProps }) {
return <Component {...pageProps} />
}

View File

@ -1,17 +1,17 @@
import Document, { Html, Head, Main, NextScript } from 'next/document'
class CustomDocument extends Document {
render() {
return (
<Html lang='en'>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
render () {
return (
<Html lang='en'>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default CustomDocument
export default CustomDocument

View File

@ -1,11 +1,11 @@
import { gql, ApolloServer } from 'apollo-server-micro'
const Articles = [
{id: 1, title: 'Article 1'},
{id: 2, title: 'Article 2'},
{id: 3, title: 'Article 3'},
{id: 4, title: 'Article 4'},
{id: 5, title: 'Article 5'}
{ id: 1, title: 'Article 1' },
{ id: 2, title: 'Article 2' },
{ id: 3, title: 'Article 3' },
{ id: 4, title: 'Article 4' },
{ id: 5, title: 'Article 5' }
]
const typeDefs = gql`
@ -17,27 +17,16 @@ const typeDefs = gql`
id: ID
title: String
}
`;
`
const resolvers = {
Query: {
articles: (_parent, _args, _context) => Articles
}
};
const apolloServer = new ApolloServer({
typeDefs,
resolvers
});
const handler = apolloServer.createHandler({
path: "/api/graphql"
});
export const config = {
api: {
bodyParser: false
}
Query: {
articles: (_parent, _args, _context) => Articles
}
}
export default handler
const apolloServer = new ApolloServer({ typeDefs, resolvers })
const handler = apolloServer.createHandler({ path: '/api/graphql' })
export const config = { api: { bodyParser: false } }
export default handler

View File

@ -1,36 +1,34 @@
import Layout from '../components/Layout/Layout'
import SEO from '../components/SEO/SEO'
import Query from '../components/Query/query'
import ARTICLES_QUERY from '../apollo/queries/articles/articles';
import { withApollo } from '../lib/apollo';
import ARTICLES_QUERY from '../apollo/queries/articles/articles'
import { withApollo } from '../lib/apollo'
const Articles = () => {
return (
<>
<SEO pageTitle='Articles page' />
<Layout>
<h1>Articles page</h1>
<div>
<Query query={ARTICLES_QUERY}>
{({ data: { articles } }) => {
return articles.map(art => {
return (
<div key={art.id}>
<p>
title: {art.title} <br />
id: {art.id}
</p>
</div>
)
})
}}
</Query>
</div>
</Layout>
</>
)
return (
<>
<SEO pageTitle='Articles page' />
<Layout>
<h1>Articles page</h1>
<div>
<Query query={ARTICLES_QUERY}>
{({ data: { articles } }) => {
return articles.map(art => {
return (
<div key={art.id}>
<p>
title: {art.title} <br />
id: {art.id}
</p>
</div>
)
})
}}
</Query>
</div>
</Layout>
</>
)
}
export default withApollo(Articles)