Skip to content

Commit

Permalink
add nextjs-8-serverless sample app (#1640)
Browse files Browse the repository at this point in the history
  • Loading branch information
praveenweb authored and shahidhk committed Feb 21, 2019
1 parent d3b9948 commit 5fc2df2
Show file tree
Hide file tree
Showing 15 changed files with 6,920 additions and 0 deletions.
83 changes: 83 additions & 0 deletions community/sample-apps/nextjs-8-serverless/.gitignore
@@ -0,0 +1,83 @@

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

125 changes: 125 additions & 0 deletions community/sample-apps/nextjs-8-serverless/README.md
@@ -0,0 +1,125 @@
# nextjs-8-serverless

> Boilerplate to get started with Next.js 8 Serverless Mode, Hasura GraphQL engine as CMS and postgres as database.
# Tutorial

- Deploy Postgres and GraphQL Engine on Heroku:

[![Deploy to heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/hasura/graphql-engine-heroku)

Please checkout our [docs](https://docs.hasura.io/1.0/graphql/manual/deployment/index.html) for other deployment methods

- Get the Heroku app URL (say `my-app.herokuapp.com`)

- Create `author` table:

Open Hasura console: visit https://my-app.herokuapp.com on a browser
Navigate to `Data` section in the top nav bar and create a table as follows:

![Create author table](../gatsby-postgres-graphql/assets/add_table.jpg)

- Insert sample data into `author` table:

![Insert data into author table](../gatsby-postgres-graphql/assets/insert_data.jpg)

Verify if the row is inserted successfully

![Insert data into author table](../gatsby-postgres-graphql/assets/browse_rows.jpg)

- Clone this repo:
```bash
git clone https://github.com/hasura/graphql-engine
cd graphql-engine/community/sample-apps/nextjs-8-serverless
```

- Install npm modules:
```bash
npm install
```

- Open `lib/init-apollo.js` and configure Hasura's GraphQL Endpoint as follows:

```js

function create (initialState) {
return new ApolloClient({
connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
link: new HttpLink({
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql', // Server URL (must be absolute)
credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
}),
cache: new InMemoryCache().restore(initialState || {})
})
}

```
Replace the `uri` with your own Hasura GraphQL endpoint.

In this example, we integrate Apollo with Next by wrapping our *pages/_app.js* inside a higher-order component HOC. Using the HOC pattern we're able to pass down a central store of query result data created by Apollo into our React component hierarchy defined inside each page of our Next application.

On initial page load, while on the server and inside `getInitialProps`, we invoke the Apollo method, [`getDataFromTree`](https://www.apollographql.com/docs/react/features/server-side-rendering.html#getDataFromTree). This method returns a promise; at the point in which the promise resolves, our Apollo Client store is completely initialized.

- We have defined the graphql query in `components/AuthorList.js`.

```graphql

query author($skip: Int!) {
author(offset: $skip, limit: 5) {
id
name
}
author_aggregate {
aggregate {
count
}
}
}

```

- Run the app:
```bash
npm run dev
```
- Test the app
Visit [http://localhost:3000](http://localhost:3000) to view the app

# Serverless Mode

With Next.js 8, each page in the `pages` directory becomes a serverless lambda. To enable `serverless` mode, we add the `serverless` build `target` in `next.config.js`.

```
module.exports = {
target: "serverless",
};
```

That's it! Now build the serverless app by running the following command:

```
npm run build
```

In the `.next` folder, you will see a `serverless` folder generated after the build. Inside that there is a `pages` folder, which will have outputs of lambda per page.

```
pages/index.js => .next/serverless/pages/index.js
pages/about.js => .next/serverless/pages/about.js
```

# Deploy to now.sh

Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download)):

```bash
npm install -g now
now
```
Note: Older versions of now-cli doesn't support serverless mode.
Once the deployment is successful, you will be able to navigate to pages `/` and `/about`, with each one internally being a lambda function which `now` manages.




42 changes: 42 additions & 0 deletions community/sample-apps/nextjs-8-serverless/components/App.js
@@ -0,0 +1,42 @@
export default ({ children }) => (
<main>
{children}
<style jsx global>{`
* {
font-family: Menlo, Monaco, 'Lucida Console', 'Liberation Mono',
'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New',
monospace, serif;
}
body {
margin: 0;
padding: 25px 50px;
}
a {
color: #22bad9;
}
p {
font-size: 14px;
line-height: 24px;
}
article {
margin: 0 auto;
max-width: 650px;
}
button {
align-items: center;
background-color: #22bad9;
border: 0;
color: white;
display: flex;
padding: 5px 7px;
}
button:active {
background-color: #1b9db7;
transition: background-color 0.3s;
}
button:focus {
outline: none;
}
`}</style>
</main>
)
109 changes: 109 additions & 0 deletions community/sample-apps/nextjs-8-serverless/components/AuthorList.js
@@ -0,0 +1,109 @@
import { Query } from 'react-apollo'
import gql from 'graphql-tag'

export const authorQuery = gql`
query author($skip: Int!) {
author(offset: $skip, limit: 5) {
id
name
}
author_aggregate {
aggregate {
count
}
}
}
`
export const authorQueryVars = {
skip: 0,
}

export default function AuthorList () {
return (
<Query query={authorQuery} variables={authorQueryVars}>
{({ loading, error, data: { author, author_aggregate }, fetchMore }) => {
if (error) return <ErrorMessage message='Error loading authors.' />
if (loading) return <div>Loading</div>

const areMoreAuthors = author.length < author_aggregate.aggregate.count
return (
<section>
<ul>
{author.map((a, index) => (
<li key={a.id}>
<div>
<span>{index + 1}. </span>
<a>{a.name}</a>
</div>
</li>
))}
</ul>
{areMoreAuthors ? (
<button onClick={() => loadMoreAuthors(author, fetchMore)}>
{' '}
{loading ? 'Loading...' : 'Show More'}{' '}
</button>
) : (
''
)}
<style jsx>{`
section {
padding-bottom: 20px;
}
li {
display: block;
margin-bottom: 10px;
}
div {
align-items: center;
display: flex;
}
a {
font-size: 14px;
margin-right: 10px;
text-decoration: none;
padding-bottom: 0;
border: 0;
}
span {
font-size: 14px;
margin-right: 5px;
}
ul {
margin: 0;
padding: 0;
}
button:before {
align-self: center;
border-style: solid;
border-width: 6px 4px 0 4px;
border-color: #ffffff transparent transparent transparent;
content: '';
height: 0;
margin-right: 5px;
width: 0;
}
`}</style>
</section>
)
}}
</Query>
)
}

function loadMoreAuthors (author, fetchMore) {
fetchMore({
variables: {
skip: author.length
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return previousResult
}
return Object.assign({}, previousResult, {
// Append the new results to the old one
author: [...previousResult.author, ...fetchMoreResult.author]
})
}
})
}
@@ -0,0 +1,13 @@
export default ({ message }) => (
<aside>
{message}
<style jsx>{`
aside {
padding: 1.5em;
font-size: 14px;
color: white;
background-color: red;
}
`}</style>
</aside>
)

0 comments on commit 5fc2df2

Please sign in to comment.