Skip to content

Commit

Permalink
docs: nextjs streaming example
Browse files Browse the repository at this point in the history
  • Loading branch information
jayair committed Sep 20, 2024
1 parent 4ce1b9a commit 8456099
Show file tree
Hide file tree
Showing 25 changed files with 407 additions and 1 deletion.
42 changes: 42 additions & 0 deletions examples/aws-nextjs-stream/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# sst
.sst

# open-next
.open-next
36 changes: 36 additions & 0 deletions examples/aws-nextjs-stream/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Binary file added examples/aws-nextjs-stream/app/favicon.ico
Binary file not shown.
Binary file not shown.
Binary file added examples/aws-nextjs-stream/app/fonts/GeistVF.woff
Binary file not shown.
8 changes: 8 additions & 0 deletions examples/aws-nextjs-stream/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f0f8ff;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
33 changes: 33 additions & 0 deletions examples/aws-nextjs-stream/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";

const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
{children}
</body>
</html>
);
}
5 changes: 5 additions & 0 deletions examples/aws-nextjs-stream/app/page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
21 changes: 21 additions & 0 deletions examples/aws-nextjs-stream/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Suspense } from "react";
import Bio from "@/components/bio";
import Friends from "@/components/friends";
import styles from "./page.module.css";

export const dynamic = "force-dynamic";

export default async function Home() {
return (
<div className={styles.container}>
<Bio />

<section>
<h2>Friends from Bikini Bottom</h2>
<Suspense fallback={<div>Loading...</div>}>
<Friends />
</Suspense>
</section>
</div>
);
}
15 changes: 15 additions & 0 deletions examples/aws-nextjs-stream/components/bio.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.section {
background-color: #fff;
padding: 20px;
margin-bottom: 20px;
border-radius: 10px;
}
.content {
display: flex;
align-items: center;
}
.text {
flex: 1;
padding-right: 20px;
}

21 changes: 21 additions & 0 deletions examples/aws-nextjs-stream/components/bio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import styles from "./bio.module.css";

const spongebob = {
name: "SpongeBob SquarePants",
description: "SpongeBob SquarePants is the main character of the popular animated TV series. He's a cheerful sea sponge who lives in a pineapple house in the underwater city of Bikini Bottom. SpongeBob works as a fry cook at the Krusty Krab and loves jellyfishing with his best friend Patrick Star.",
image: "spongebob.png",
};

export default function Bio({ }) {
return (
<section className={styles.section}>
<h1>{spongebob.name}</h1>
<div className={styles.content}>
<div className={styles.text}>
<p>{spongebob.description}</p>
</div>
<img src={spongebob.image} alt={spongebob.name} />
</div>
</section>
);
}
16 changes: 16 additions & 0 deletions examples/aws-nextjs-stream/components/friends.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 20px;
}
.card {
background-color: #fff;
padding: 10px;
border-radius: 5px;
text-align: center;
}
.img {
max-width: 100%;
height: auto;
border-radius: 5px;
}
36 changes: 36 additions & 0 deletions examples/aws-nextjs-stream/components/friends.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import styles from "./friends.module.css";

interface Character {
name: string;
image: string;
}

function friendsPromise() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(
[
{ name: "Patrick Star", image: "patrick.png" },
{ name: "Sandy Cheeks", image: "sandy.png" },
{ name: "Squidward Tentacles", image: "squidward.png" },
{ name: "Mr. Krabs", image: "mr-krabs.png" },
]
);
}, 3000);
});
}

export default async function Friends() {
const friends = await friendsPromise() as Character[];

return (
<div className={styles.grid}>
{friends.map((friend) => (
<div key={friend.name} className={styles.card}>
<img className={styles.img} src={friend.image} alt={friend.name} />
<p>{friend.name}</p>
</div>
))}
</div>
);
}
4 changes: 4 additions & 0 deletions examples/aws-nextjs-stream/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
9 changes: 9 additions & 0 deletions examples/aws-nextjs-stream/open-next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const config = {
default: {
override: {
wrapper: "aws-lambda-streaming",
},
},
};

export default config;
23 changes: 23 additions & 0 deletions examples/aws-nextjs-stream/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "aws-nextjs-stream",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"next": "14.2.12",
"react": "^18",
"react-dom": "^18",
"sst": "3.1.26"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5"
}
}
Binary file added examples/aws-nextjs-stream/public/mr-krabs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/aws-nextjs-stream/public/patrick.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/aws-nextjs-stream/public/sandy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/aws-nextjs-stream/public/spongebob.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/aws-nextjs-stream/public/squidward.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions examples/aws-nextjs-stream/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
import "sst"
export {}
declare module "sst" {
export interface Resource {
"MyWeb": {
"type": "sst.aws.Nextjs"
"url": string
}
}
}
53 changes: 53 additions & 0 deletions examples/aws-nextjs-stream/sst.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// <reference path="./.sst/platform/config.d.ts" />

/**
* ## AWS Next.js streaming
*
* An example of how to use streaming Next.js RSC. Uses `Suspense` to stream an async component.
*
* ```tsx title="app/page.tsx"
* <Suspense fallback={<div>Loading...</div>}>
* <Friends />
* </Suspense>
* ```
*
* For this demo we also need to make sure the route is not statically built.
*
* ```ts title="app/page.tsx"
* export const dynamic = "force-dynamic";
* ```
*
* This is deployed with OpenNext, which needs a config to enable streaming.
*
* ```ts title="open-next.config.ts" {4}
* export default {
* default: {
* override: {
* wrapper: "aws-lambda-streaming"
* }
* }
* };
* ```
*
* You should see the _friends_ section load after a 3 second delay.
*
* :::note
* Safari handles streaming differently than other browsers.
* :::
*
* Safari uses a [different heuristic](https://bugs.webkit.org/show_bug.cgi?id=252413) to
* determine when to stream data. You need to render _enough_ initial HTML to trigger streaming.
* This is typically only a problem for demo apps.
*/
export default $config({
app(input) {
return {
name: "aws-nextjs-stream",
removal: input?.stage === "production" ? "retain" : "remove",
home: "aws",
};
},
async run() {
new sst.aws.Nextjs("MyWeb");
},
});
26 changes: 26 additions & 0 deletions examples/aws-nextjs-stream/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules","sst.config.ts"]
}
Loading

0 comments on commit 8456099

Please sign in to comment.