first commit
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled

This commit is contained in:
Arian Tron
2026-03-10 19:37:31 +03:30
commit 61f56f997c
27684 changed files with 2784175 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
{
"trailingComma": "all",
"singleQuote": false,
"semi": true
}

40
examples/active-class-name/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,25 @@
# activeClassName example
ReactRouter has a convenience property on the `Link` element to allow an author to set the _active_ className on a link. This example replicates that functionality using Next's own `Link` component with the new app router.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/active-class-name&project-name=active-class-name&repository-name=active-class-name)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example active-class-name active-class-name-app
```
```bash
yarn create next-app --example active-class-name active-class-name-app
```
```bash
pnpm create next-app --example active-class-name active-class-name-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/app/building-your-application/deploying)).

View File

@@ -0,0 +1,17 @@
"use client";
import { usePathname } from "next/navigation";
import Nav from "../../components/Nav";
const SlugPage = () => {
const pathname = usePathname();
return (
<>
<Nav />
<p>Hello, I'm the {pathname} page</p>
</>
);
};
export default SlugPage;

View File

@@ -0,0 +1,10 @@
import Nav from "../../components/Nav";
const AboutPage = () => (
<>
<Nav />
<p>Hello, I'm the about page</p>
</>
);
export default AboutPage;

View File

@@ -0,0 +1,16 @@
export const metadata = {
title: "Next.js",
description: "Generated by Next.js",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

View File

@@ -0,0 +1,10 @@
import Nav from "../../components/Nav";
const News = () => (
<>
<Nav />
<p>Hello, I'm the news page</p>
</>
);
export default News;

View File

@@ -0,0 +1,10 @@
import Nav from "../components/Nav";
const IndexPage = () => (
<>
<Nav />
<p>Hello, I'm the index page</p>
</>
);
export default IndexPage;

View File

@@ -0,0 +1,60 @@
"use client";
import Link, { LinkProps } from "next/link";
import React, { PropsWithChildren, useEffect, useState } from "react";
import { usePathname } from "next/navigation";
const getLinkUrl = (href: LinkProps["href"], as?: LinkProps["as"]): string => {
// Dynamic route will be matched via props.as
// Static route will be matched via props.href
if (as) return as.toString();
return href.toString();
};
type ActiveLinkProps = LinkProps & {
className?: string;
activeClassName: string;
};
const ActiveLink = ({
children,
activeClassName,
className,
...props
}: PropsWithChildren<ActiveLinkProps>) => {
const pathname = usePathname();
const [computedClassName, setComputedClassName] = useState(className);
useEffect(() => {
if (pathname) {
const linkUrl = getLinkUrl(props.href, props.as);
const linkPathname = new URL(linkUrl, location.href).pathname;
const activePathname = new URL(pathname, location.href).pathname;
const newClassName =
linkPathname === activePathname
? `${className} ${activeClassName}`.trim()
: className;
if (newClassName !== computedClassName) {
setComputedClassName(newClassName);
}
}
}, [
pathname,
props.as,
props.href,
activeClassName,
className,
computedClassName,
]);
return (
<Link className={computedClassName} {...props}>
{children}
</Link>
);
};
export default ActiveLink;

View File

@@ -0,0 +1,45 @@
"use client";
import ActiveLink from "./ActiveLink";
const Nav = () => (
<nav>
<style jsx global>{`
.nav-link {
text-decoration: none;
}
.active:after {
content: " (current page)";
}
`}</style>
<ul className="nav">
<li>
<ActiveLink activeClassName="active" className="nav-link" href="/">
Home
</ActiveLink>
</li>
<li>
<ActiveLink activeClassName="active" className="nav-link" href="/about">
About
</ActiveLink>
</li>
<li>
<ActiveLink activeClassName="active" className="nav-link" href="/blog">
Blog
</ActiveLink>
</li>
<li>
<ActiveLink
activeClassName="active"
className="nav-link"
href="/dynamic-route"
>
Dynamic Route
</ActiveLink>
</li>
</ul>
</nav>
);
export default Nav;

View File

@@ -0,0 +1,11 @@
/** @type {import('next').NextConfig} */
module.exports = {
async rewrites() {
return [
{
source: "/blog",
destination: "/news",
},
];
},
};

View File

@@ -0,0 +1,20 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint ."
},
"dependencies": {
"next": "latest",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"typescript": "^5.5.3"
}
}

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,3 @@
# Secrets like the one below should go into `.env.local` instead to avoid pushing
# them to a repository, this is an exception for the sake of the example
TOKEN_SECRET="this-is-a-secret-value-with-at-least-32-characters"

View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,27 @@
# Apollo Server and Client Auth Example
[Apollo](https://www.apollographql.com/client/) is a GraphQL client that allows you to easily query the exact data you need from a GraphQL server. In addition to fetching and mutating data, Apollo analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run. The integration with Next and Apollo Server is implemented using the [apollo-server-integration-next](https://github.com/apollo-server-integrations/apollo-server-integration-next) community package.
In this simple example, we integrate Apollo seamlessly with [Next.js data fetching methods](https://nextjs.org/docs/basic-features/data-fetching) to fetch queries in the server and hydrate them in the browser.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server-and-client-auth&project-name=api-routes-apollo-server-and-client-auth&repository-name=api-routes-apollo-server-and-client-auth)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-apollo-server-and-client-auth api-routes-apollo-server-and-client-auth-app
```
```bash
yarn create next-app --example api-routes-apollo-server-and-client-auth api-routes-apollo-server-and-client-auth-app
```
```bash
pnpm create next-app --example api-routes-apollo-server-and-client-auth api-routes-apollo-server-and-client-auth-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,54 @@
import { useMemo } from "react";
import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
import { SchemaLink } from "@apollo/client/link/schema";
import { schema } from "../apollo/schema";
import merge from "deepmerge";
let apolloClient;
function createIsomorphLink() {
if (typeof window === "undefined") {
return new SchemaLink({ schema });
} else {
return new HttpLink({
uri: "/api/graphql",
credentials: "same-origin",
});
}
}
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === "undefined",
link: createIsomorphLink(),
cache: new InMemoryCache(),
});
}
export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient();
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// get hydrated here
if (initialState) {
// Get existing cache, loaded during client side data fetching
const existingCache = _apolloClient.extract();
// Merge the existing cache into data passed from getStaticProps/getServerSideProps
const data = merge(initialState, existingCache);
// Restore the cache with the merged data
_apolloClient.cache.restore(data);
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === "undefined") return _apolloClient;
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
}

View File

@@ -0,0 +1,53 @@
import { createUser, findUser, validatePassword } from "../lib/user";
import { setLoginSession, getLoginSession } from "../lib/auth";
import { removeTokenCookie } from "../lib/auth-cookies";
import { GraphQLError } from "graphql";
export const resolvers = {
Query: {
async viewer(_root, _args, context, _info) {
try {
const session = await getLoginSession(context.req);
if (session) {
return findUser({ email: session.email });
}
} catch (error) {
throw new GraphQLError(
"Authentication token is invalid, please log in",
{
extensions: {
code: "UNAUTHENTICATED",
},
},
);
}
},
},
Mutation: {
async signUp(_parent, args, _context, _info) {
const user = await createUser(args.input);
return { user };
},
async signIn(_parent, args, context, _info) {
const user = await findUser({ email: args.input.email });
if (user && (await validatePassword(user, args.input.password))) {
const session = {
id: user.id,
email: user.email,
};
await setLoginSession(context.res, session);
return { user };
}
throw new GraphQLError("Invalid email and password combination");
},
async signOut(_parent, _args, context, _info) {
removeTokenCookie(context.res);
return true;
},
},
};

View File

@@ -0,0 +1,8 @@
import { makeExecutableSchema } from "@graphql-tools/schema";
import { typeDefs } from "./type-defs";
import { resolvers } from "./resolvers";
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
});

View File

@@ -0,0 +1,39 @@
import { gql } from "@apollo/client";
export const typeDefs = gql`
type User {
id: ID!
email: String!
createdAt: Int!
}
input SignUpInput {
email: String!
password: String!
}
input SignInInput {
email: String!
password: String!
}
type SignUpPayload {
user: User!
}
type SignInPayload {
user: User!
}
type Query {
user(id: ID!): User!
users: [User]!
viewer: User
}
type Mutation {
signUp(input: SignUpInput!): SignUpPayload!
signIn(input: SignInInput!): SignInPayload!
signOut: Boolean!
}
`;

View File

@@ -0,0 +1,17 @@
export default function Field({ name, label, type, autoComplete, required }) {
return (
<div>
<label id={[name, "label"].join("-")} htmlFor={[name, "input"].join("-")}>
{label} {required ? <span title="Required">*</span> : undefined}
</label>
<br />
<input
autoComplete={autoComplete}
id={[name, "input"].join("-")}
name={name}
required={required}
type={type}
/>
</div>
);
}

View File

@@ -0,0 +1,41 @@
import { serialize, parse } from "cookie";
const TOKEN_NAME = "token";
export const MAX_AGE = 60 * 60 * 8; // 8 hours
export function setTokenCookie(res, token) {
const cookie = serialize(TOKEN_NAME, token, {
maxAge: MAX_AGE,
expires: new Date(Date.now() + MAX_AGE * 1000),
httpOnly: true,
secure: process.env.NODE_ENV === "production",
path: "/",
sameSite: "lax",
});
res.setHeader("Set-Cookie", cookie);
}
export function removeTokenCookie(res) {
const cookie = serialize(TOKEN_NAME, "", {
maxAge: -1,
path: "/",
});
res.setHeader("Set-Cookie", cookie);
}
export function parseCookies(req) {
// For API Routes we don't need to parse the cookies.
if (req.cookies) return req.cookies;
// For pages we do need to parse the cookies.
const cookie = req.headers?.cookie;
return parse(cookie || "");
}
export function getTokenCookie(req) {
const cookies = parseCookies(req);
return cookies[TOKEN_NAME];
}

View File

@@ -0,0 +1,29 @@
import Iron from "@hapi/iron";
import { MAX_AGE, setTokenCookie, getTokenCookie } from "./auth-cookies";
const TOKEN_SECRET = process.env.TOKEN_SECRET;
export async function setLoginSession(res, session) {
const createdAt = Date.now();
// Create a session object with a max age that we can validate later
const obj = { ...session, createdAt, maxAge: MAX_AGE };
const token = await Iron.seal(obj, TOKEN_SECRET, Iron.defaults);
setTokenCookie(res, token);
}
export async function getLoginSession(req) {
const token = getTokenCookie(req);
if (!token) return;
const session = await Iron.unseal(token, TOKEN_SECRET, Iron.defaults);
const expiresAt = session.createdAt + session.maxAge * 1000;
// Validate the expiration date of the session
if (Date.now() > expiresAt) {
throw new Error("Session expired");
}
return session;
}

View File

@@ -0,0 +1,13 @@
export function getErrorMessage(error) {
if (error.graphQLErrors) {
for (const graphQLError of error.graphQLErrors) {
if (
graphQLError.extensions &&
graphQLError.extensions.code === "BAD_USER_INPUT"
) {
return graphQLError.message;
}
}
}
return error.message;
}

View File

@@ -0,0 +1,45 @@
import crypto from "crypto";
/**
* User methods. The example doesn't contain a DB, but for real applications you must use a
* db here, such as MongoDB, Fauna, SQL, etc.
*/
const users = [];
export async function createUser({ email, password }) {
// Here you should create the user and save the salt and hashed password (some dbs may have
// authentication methods that will do it for you so you don't have to worry about it):
const salt = crypto.randomBytes(16).toString("hex");
const hash = crypto
.pbkdf2Sync(password, salt, 1000, 64, "sha512")
.toString("hex");
const user = {
id: crypto.randomUUID(),
createdAt: Date.now(),
email,
hash,
salt,
};
// This is an in memory store for users, there is no data persistence without a proper DB
users.push(user);
return user;
}
// Here you should lookup for the user in your DB
export async function findUser({ email }) {
// This is an in memory store for users, there is no data persistence without a proper DB
return users.find((user) => user.email === email);
}
// Compare the password of an already fetched user (using `findUser`) and compare the
// password for a potential match
export async function validatePassword(user, inputPassword) {
const inputHash = crypto
.pbkdf2Sync(inputPassword, user.salt, 1000, 64, "sha512")
.toString("hex");
const passwordsMatch = user.hash === inputHash;
return passwordsMatch;
}

View File

@@ -0,0 +1,28 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@apollo/client": "^3.7.1",
"@apollo/server": "^4.1.1",
"@as-integrations/next": "^1.1.0",
"@graphql-tools/schema": "^9.0.9",
"graphql": "^16.6.0",
"@hapi/iron": "6.0.0",
"cookie": "^0.4.1",
"deepmerge": "4.2.2",
"next": "latest",
"prop-types": "^15.6.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^18.0.2",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,12 @@
import { ApolloProvider } from "@apollo/client";
import { useApollo } from "../apollo/client";
export default function App({ Component, pageProps }) {
const apolloClient = useApollo(pageProps.initialApolloState);
return (
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
);
}

View File

@@ -0,0 +1,9 @@
import Link from "next/link";
export default function About() {
return (
<div>
Welcome to the about page. Go to the <Link href="/">Home</Link> page.
</div>
);
}

View File

@@ -0,0 +1,15 @@
import { ApolloServer } from "@apollo/server";
import { startServerAndCreateNextHandler } from "@as-integrations/next";
import { NextApiRequest, NextApiResponse } from "next";
import { schema } from "../../apollo/schema";
type ExampleContext = {
req: NextApiRequest;
res: NextApiResponse;
};
const apolloServer = new ApolloServer<ExampleContext>({ schema });
export default startServerAndCreateNextHandler(apolloServer, {
context: async (req, res) => ({ req, res }),
});

View File

@@ -0,0 +1,45 @@
import { useEffect } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { gql, useQuery } from "@apollo/client";
const ViewerQuery = gql`
query ViewerQuery {
viewer {
id
email
}
}
`;
const Index = () => {
const router = useRouter();
const { data, loading, error } = useQuery(ViewerQuery);
const viewer = data?.viewer;
const shouldRedirect = !(loading || error || viewer);
useEffect(() => {
if (shouldRedirect) {
router.push("/signin");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [shouldRedirect]);
if (error) {
return <p>{error.message}</p>;
}
if (viewer) {
return (
<div>
You're signed in as {viewer.email}. Go to{" "}
<Link href="/about">about</Link> page or{" "}
<Link href="/signout">signout</Link>.
</div>
);
}
return <p>Loading...</p>;
};
export default Index;

View File

@@ -0,0 +1,74 @@
import { useState } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { gql } from "@apollo/client";
import { useMutation, useApolloClient } from "@apollo/client";
import { getErrorMessage } from "../lib/form";
import Field from "../components/field";
const SignInMutation = gql`
mutation SignInMutation($email: String!, $password: String!) {
signIn(input: { email: $email, password: $password }) {
user {
id
email
}
}
}
`;
function SignIn() {
const client = useApolloClient();
const [signIn] = useMutation(SignInMutation);
const [errorMsg, setErrorMsg] = useState();
const router = useRouter();
async function handleSubmit(event) {
event.preventDefault();
const emailElement = event.currentTarget.elements.email;
const passwordElement = event.currentTarget.elements.password;
try {
await client.resetStore();
const { data } = await signIn({
variables: {
email: emailElement.value,
password: passwordElement.value,
},
});
if (data.signIn.user) {
await router.push("/");
}
} catch (error) {
setErrorMsg(getErrorMessage(error));
}
}
return (
<>
<h1>Sign In</h1>
<form onSubmit={handleSubmit}>
{errorMsg && <p>{errorMsg}</p>}
<Field
name="email"
type="email"
autoComplete="email"
required
label="Email"
/>
<Field
name="password"
type="password"
autoComplete="password"
required
label="Password"
/>
<button type="submit">Sign in</button> or{" "}
<Link href="/signup">Sign up</Link>
</form>
</>
);
}
export default SignIn;

View File

@@ -0,0 +1,27 @@
import { useEffect } from "react";
import { useRouter } from "next/router";
import { gql, useMutation, useApolloClient } from "@apollo/client";
const SignOutMutation = gql`
mutation SignOutMutation {
signOut
}
`;
function SignOut() {
const client = useApolloClient();
const router = useRouter();
const [signOut] = useMutation(SignOutMutation);
useEffect(() => {
signOut().then(() => {
client.resetStore().then(() => {
router.push("/signin");
});
});
}, [signOut, router, client]);
return <p>Signing out...</p>;
}
export default SignOut;

View File

@@ -0,0 +1,69 @@
import { useState } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { gql, useMutation } from "@apollo/client";
import { getErrorMessage } from "../lib/form";
import Field from "../components/field";
const SignUpMutation = gql`
mutation SignUpMutation($email: String!, $password: String!) {
signUp(input: { email: $email, password: $password }) {
user {
id
email
}
}
}
`;
function SignUp() {
const [signUp] = useMutation(SignUpMutation);
const [errorMsg, setErrorMsg] = useState();
const router = useRouter();
async function handleSubmit(event) {
event.preventDefault();
const emailElement = event.currentTarget.elements.email;
const passwordElement = event.currentTarget.elements.password;
try {
await signUp({
variables: {
email: emailElement.value,
password: passwordElement.value,
},
});
router.push("/signin");
} catch (error) {
setErrorMsg(getErrorMessage(error));
}
}
return (
<>
<h1>Sign Up</h1>
<form onSubmit={handleSubmit}>
{errorMsg && <p>{errorMsg}</p>}
<Field
name="email"
type="email"
autoComplete="email"
required
label="Email"
/>
<Field
name="password"
type="password"
autoComplete="password"
required
label="Password"
/>
<button type="submit">Sign up</button> or{" "}
<Link href="/signin">Sign in</Link>
</form>
</>
);
}
export default SignUp;

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/about.js"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,27 @@
# Apollo Server and Client Example
[Apollo](https://www.apollographql.com/client/) is a GraphQL client that allows you to easily query the exact data you need from a GraphQL server. In addition to fetching and mutating data, Apollo analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run. The integration with Next and Apollo Server is implemented using the [apollo-server-integration-next](https://github.com/apollo-server-integrations/apollo-server-integration-next) community package.
In this simple example, we integrate Apollo seamlessly with [Next.js data fetching methods](https://nextjs.org/docs/basic-features/data-fetching) to fetch queries in the server and hydrate them in the browser.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server-and-client&project-name=api-routes-apollo-server-and-client&repository-name=api-routes-apollo-server-and-client)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-apollo-server-and-client api-routes-apollo-server-and-client-app
```
```bash
yarn create next-app --example api-routes-apollo-server-and-client api-routes-apollo-server-and-client-app
```
```bash
pnpm create next-app --example api-routes-apollo-server-and-client api-routes-apollo-server-and-client-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,54 @@
import { useMemo } from "react";
import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
import { SchemaLink } from "@apollo/client/link/schema";
import { schema } from "../apollo/schema";
import merge from "deepmerge";
let apolloClient;
function createIsomorphLink() {
if (typeof window === "undefined") {
return new SchemaLink({ schema });
} else {
return new HttpLink({
uri: "/api/graphql",
credentials: "same-origin",
});
}
}
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === "undefined",
link: createIsomorphLink(),
cache: new InMemoryCache(),
});
}
export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient();
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// gets hydrated here
if (initialState) {
// Get existing cache, loaded during client side data fetching
const existingCache = _apolloClient.extract();
// Merge the existing cache into data passed from getStaticProps/getServerSideProps
const data = merge(initialState, existingCache);
// Restore the cache with the merged data
_apolloClient.cache.restore(data);
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === "undefined") return _apolloClient;
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
}

View File

@@ -0,0 +1,7 @@
export const resolvers = {
Query: {
viewer() {
return { id: 1, name: "John Smith", status: "cached" };
},
},
};

View File

@@ -0,0 +1,8 @@
import { makeExecutableSchema } from "@graphql-tools/schema";
import { typeDefs } from "./type-defs";
import { resolvers } from "./resolvers";
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
});

View File

@@ -0,0 +1,13 @@
import { gql } from "@apollo/client";
export const typeDefs = gql`
type User {
id: ID!
name: String!
status: String!
}
type Query {
viewer: User
}
`;

View File

@@ -0,0 +1,25 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@apollo/client": "^3.7.1",
"@apollo/server": "^4.1.1",
"@as-integrations/next": "^1.1.0",
"@graphql-tools/schema": "^9.0.9",
"deepmerge": "4.2.2",
"graphql": "^16.6.0",
"next": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^18.0.2",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,12 @@
import { ApolloProvider } from "@apollo/client";
import { useApollo } from "../apollo/client";
export default function App({ Component, pageProps }) {
const apolloClient = useApollo(pageProps.initialApolloState);
return (
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
);
}

View File

@@ -0,0 +1,9 @@
import Link from "next/link";
export default function About() {
return (
<div>
This is a static page goto <Link href="/">dynamic</Link> page.
</div>
);
}

View File

@@ -0,0 +1,7 @@
import { ApolloServer } from "@apollo/server";
import { startServerAndCreateNextHandler } from "@as-integrations/next";
import { schema } from "../../apollo/schema";
const apolloServer = new ApolloServer({ schema });
export default startServerAndCreateNextHandler(apolloServer);

View File

@@ -0,0 +1,43 @@
import gql from "graphql-tag";
import Link from "next/link";
import { useQuery } from "@apollo/client";
import { initializeApollo } from "../apollo/client";
const ViewerQuery = gql`
query ViewerQuery {
viewer {
id
name
status
}
}
`;
const Index = () => {
const {
data: { viewer },
} = useQuery(ViewerQuery);
return (
<div>
You're signed in as {viewer.name} and you're {viewer.status} goto{" "}
<Link href="/about">static</Link> page.
</div>
);
};
export async function getStaticProps() {
const apolloClient = initializeApollo();
await apolloClient.query({
query: ViewerQuery,
});
return {
props: {
initialApolloState: apolloClient.cache.extract(),
},
};
}
export default Index;

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,33 @@
# Consume local Apollo GraphQL schema to create Static Generation export
Next.js ships with two forms of pre-rendering: [Static Generation](https://nextjs.org/docs/basic-features/pages#static-generation-recommended) and [Server-side Rendering](https://nextjs.org/docs/basic-features/pages#server-side-rendering). This example shows how to perform Static Generation using a local [Apollo GraphQL Server ](https://www.apollographql.com/docs/apollo-server/) schema within [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching/get-static-props) and [getStaticPaths](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-paths). The end result is a Next.js application that uses one Apollo GraphQL schema to generate static pages at build time and also serve a GraphQL [API Route](https://nextjs.org/docs/api-routes/introduction) at runtime. The integration with Next and Apollo Server is implemented using the [apollo-server-integration-next](https://github.com/apollo-server-integrations/apollo-server-integration-next) community package.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server&project-name=api-routes-apollo-server&repository-name=api-routes-apollo-server)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-apollo-server api-routes-apollo-server-app
```
```bash
yarn create next-app --example api-routes-apollo-server api-routes-apollo-server-app
```
```bash
pnpm create next-app --example api-routes-apollo-server api-routes-apollo-server-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
## Notes
### Static Export
If you wish to export a static HTML + JS version of the site you need to first change the setting in this example in `./pages/[username].js` where `getStaticPaths` has `fallback: true` - this needs to be `false` for static export to work. You can then run `npm run build` and `npm run export` to export the site as a static folder in `./out` directory.
[Read more about fallback option](https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required)

View File

@@ -0,0 +1,24 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@apollo/server": "^4.1.1",
"@as-integrations/next": "^1.1.0",
"@graphql-tools/schema": "^9.0.9",
"graphql": "16.8.1",
"graphql-tag": "^2.12.6",
"next": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^18.0.0",
"@types/react": "^18.0.14",
"@types/react-dom": "^18.0.5",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,46 @@
import queryGraphql from "../shared/query-graphql";
export default function UserProfile({ user }) {
if (!user) {
return <h1>User Not Found</h1>;
}
return (
<h1>
{user.username} is {user.name}
</h1>
);
}
export async function getStaticProps(context) {
const { params } = context;
const { username } = params;
const { user = null } = await queryGraphql(
`
query($username: String) {
user(username: $username) {
name
username
}
}
`,
{ username },
);
return { props: { user } };
}
export async function getStaticPaths() {
const { users } = (await queryGraphql(`
query {
users {
username
}
}
`)) as { users: { username: string }[] };
return {
paths: users.map(({ username }) => ({
params: { username },
})),
fallback: true,
};
}

View File

@@ -0,0 +1,39 @@
import { ApolloServer } from "@apollo/server";
import { startServerAndCreateNextHandler } from "@as-integrations/next";
import { makeExecutableSchema } from "@graphql-tools/schema";
import { gql } from "graphql-tag";
const typeDefs = gql`
type Query {
users: [User!]!
user(username: String): User
}
type User {
name: String
username: String
}
`;
const users = [
{ name: "Leeroy Jenkins", username: "leeroy" },
{ name: "Foo Bar", username: "foobar" },
];
const resolvers = {
Query: {
users() {
return users;
},
user(parent, { username }) {
return users.find((user) => user.username === username);
},
},
};
export const schema = makeExecutableSchema({ typeDefs, resolvers });
const server = new ApolloServer({
schema,
});
export default startServerAndCreateNextHandler(server);

View File

@@ -0,0 +1,32 @@
import Link from "next/link";
import queryGraphql from "../shared/query-graphql";
export default function UserListing({ users }) {
return (
<div>
<h1>User Listing</h1>
<ul>
{users.map((user) => (
<li key={user.username}>
<Link href="/[username]" as={`/${user.username}`}>
{user.name}
</Link>
</li>
))}
</ul>
</div>
);
}
export async function getStaticProps() {
const { users } = await queryGraphql(`
query {
users {
name
username
}
}
`);
return { props: { users } };
}

View File

@@ -0,0 +1,8 @@
import { graphql } from "graphql";
import { schema } from "../../pages/api/graphql";
export default async function queryGraphql(query, variableValues = {}) {
const { data } = await graphql({ schema, source: query, variableValues });
return data || {};
}

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

40
examples/api-routes-cors/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,27 @@
# API Routes Example with CORS
Next.js ships with [API routes](https://nextjs.org/docs/api-routes/introduction) which provides an easy solution to build your own `API`.
This example shows how to create an `API` endpoint with [CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) headers, using the [cors](https://github.com/expressjs/cors) package.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors&project-name=api-routes-cors&repository-name=api-routes-cors)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-cors api-routes-cors-app
```
```bash
yarn create next-app --example api-routes-cors api-routes-cors-app
```
```bash
pnpm create next-app --example api-routes-cors api-routes-cors-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,21 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"cors": "^2.8.5",
"next": "latest",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/node": "^22.10.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,37 @@
import type { NextApiRequest, NextApiResponse } from "next";
import Cors from "cors";
// Initializing the cors middleware
// You can read more about the available options here: https://github.com/expressjs/cors#configuration-options
const cors = Cors({
methods: ["POST", "GET", "HEAD"],
});
// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(
req: NextApiRequest,
res: NextApiResponse,
fn: Function,
) {
return new Promise((resolve, reject) => {
fn(req, res, (result: any) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
// Run the middleware
await runMiddleware(req, res, cors);
// Rest of the API logic
res.json({ message: "Hello Everyone!" });
}

View File

@@ -0,0 +1,9 @@
export default function Index() {
return (
<p>
To test the CORS route, open the console in a new tab on a different
domain and make a POST / GET / OPTIONS request to <b>/api/cors</b>. Using
a different method from those mentioned will be blocked by CORS
</p>
);
}

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

40
examples/api-routes-graphql/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,42 @@
# API routes with GraphQL server
Next.js ships with [API routes](https://nextjs.org/docs/api-routes/introduction), which provide an easy solution to build your own `API`.
This example showcases how to build a lightweight and blazing fast GraphQL API with minimum configuration using GraphQL Yoga.
GraphQL Yoga comes with strong defaults:
- CORS is enabled by default
- Automatically masking unexpected errors and preventing sensitive information from leaking to clients.
- Shipped with GraphiQL
Yoga also brings support (with no additional dependency) for subscriptions, file uploads, and your favorite schema-building library (GraphQL Tools, Pothos, Nexus, TypeGraphQL, SDL first schema-design approaches, graphql-js, Apollo Tools).
More information on all available features are available [on the official documentation](https://www.graphql-yoga.com/docs/quick-start).
Finally, GraphQL Yoga is built on top of Envelop. Envelop is a library that helps build GraphQL API faster and flexibly with plugin-based architecture.
Similar to Express middlewares allowing you to customize requests' behavior, Envelop applies the same idea to GraphQL requests.
More information on [Envelop documentation](https://www.envelop.dev/).
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-graphql&project-name=api-routes-graphql&repository-name=api-routes-graphql)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-graphql api-routes-graphql-app
```
```bash
yarn create next-app --example api-routes-graphql api-routes-graphql-app
```
```bash
pnpm create next-app --example api-routes-graphql api-routes-graphql-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,22 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"graphql-yoga": "^3.2.1",
"graphql": "^16.5.0",
"next": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"swr": "^2.0.0"
},
"devDependencies": {
"@types/node": "^18.0.2",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,36 @@
import { createYoga, createSchema } from "graphql-yoga";
const typeDefs = /* GraphQL */ `
type Query {
users: [User!]!
}
type User {
name: String
}
`;
const resolvers = {
Query: {
users() {
return [{ name: "Nextjs" }];
},
},
};
const schema = createSchema({
typeDefs,
resolvers,
});
export const config = {
api: {
// Disable body parsing (required for file uploads)
bodyParser: false,
},
};
export default createYoga({
schema,
// Needed to be defined explicitly because our endpoint lives at a different path other than `/graphql`
graphqlEndpoint: "/api/graphql",
});

View File

@@ -0,0 +1,39 @@
import useSWR from "swr";
const fetcher = (query: string) =>
fetch("/api/graphql", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({ query }),
})
.then((res) => res.json())
.then((json) => json.data);
type Data = {
users: {
name: string;
}[];
};
export default function Index() {
const { data, error, isLoading } = useSWR<Data>(
"{ users { name } }",
fetcher,
);
if (error) return <div>Failed to load</div>;
if (isLoading) return <div>Loading...</div>;
if (!data) return null;
const { users } = data;
return (
<div>
{users.map((user, index) => (
<div key={index}>{user.name}</div>
))}
</div>
);
}

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,25 @@
# API routes with middleware
Next.js ships with [API routes](https://github.com/vercel/next.js#api-routes), which provide an easy solution to build your own `API`. This example shows how to implement simple `middleware` to wrap around your `API` endpoints.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-middleware&project-name=api-routes-middleware&repository-name=api-routes-middleware)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-middleware api-routes-middleware-app
```
```bash
yarn create next-app --example api-routes-middleware api-routes-middleware-app
```
```bash
pnpm create next-app --example api-routes-middleware api-routes-middleware-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,22 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"cookie": "^0.5.0",
"next": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"swr": "^2.0.0"
},
"devDependencies": {
"@types/cookie": "^0.5.1",
"@types/node": "^18.0.2",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,9 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { setCookie } from "../../utils/cookies";
export default function handler(_req: NextApiRequest, res: NextApiResponse) {
// Calling our pure function using the `res` object, it will add the `set-cookie` header
setCookie(res, "Next.js", "api-middleware!");
// Return the `set-cookie` header so we can display it in the browser and show that it works!
res.end(JSON.stringify(res.getHeader("Set-Cookie")));
}

View File

@@ -0,0 +1,13 @@
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.text());
export default function Index() {
const { data, error, isLoading } = useSWR<string>("/api/cookies", fetcher);
if (error) return <div>Failed to load</div>;
if (isLoading) return <div>Loading...</div>;
if (!data) return null;
return <div>{`Cookie from response: "${data}"`}</div>;
}

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,22 @@
import type { NextApiResponse } from "next";
import { serialize, CookieSerializeOptions } from "cookie";
/**
* This sets `cookie` using the `res` object
*/
export const setCookie = (
res: NextApiResponse,
name: string,
value: unknown,
options: CookieSerializeOptions = {},
) => {
const stringValue =
typeof value === "object" ? "j:" + JSON.stringify(value) : String(value);
if (typeof options.maxAge === "number") {
options.expires = new Date(Date.now() + options.maxAge * 1000);
}
res.setHeader("Set-Cookie", serialize(name, stringValue, options));
};

40
examples/api-routes-rest/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,27 @@
# API routes with REST
Next.js ships with [API routes](https://github.com/vercel/next.js#api-routes), which provide an easy solution to build your own `API`. This example shows how it can be used to create your [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) `API`.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-rest&project-name=api-routes-rest&repository-name=api-routes-rest)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example api-routes-rest api-routes-rest-app
```
```bash
yarn create next-app --example api-routes-rest api-routes-rest-app
```
```bash
pnpm create next-app --example api-routes-rest api-routes-rest-app
```
### Deploy to Vercel
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,4 @@
export type User = {
id: number;
name?: string;
};

View File

@@ -0,0 +1,20 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"swr": "^2.0.0"
},
"devDependencies": {
"@types/node": "^18.0.3",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,25 @@
import type { NextApiRequest, NextApiResponse } from "next";
import type { User } from "../../../interfaces";
export default function userHandler(
req: NextApiRequest,
res: NextApiResponse<User>,
) {
const { query, method } = req;
const id = parseInt(query.id as string, 10);
const name = query.name as string;
switch (method) {
case "GET":
// Get data from your database
res.status(200).json({ id, name: `User ${id}` });
break;
case "PUT":
// Update or create data in your database
res.status(200).json({ id, name: name || `User ${id}` });
break;
default:
res.setHeader("Allow", ["GET", "PUT"]);
res.status(405).end(`Method ${method} Not Allowed`);
}
}

View File

@@ -0,0 +1,13 @@
import type { NextApiRequest, NextApiResponse } from "next";
import type { User } from "../../interfaces";
// Fake users data
const users: User[] = [{ id: 1 }, { id: 2 }, { id: 3 }];
export default function handler(
_req: NextApiRequest,
res: NextApiResponse<User[]>,
) {
// Get data from your database
res.status(200).json(users);
}

View File

@@ -0,0 +1,25 @@
import type { User } from "../interfaces";
import useSwr from "swr";
import Link from "next/link";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export default function Index() {
const { data, error, isLoading } = useSwr<User[]>("/api/users", fetcher);
if (error) return <div>Failed to load users</div>;
if (isLoading) return <div>Loading...</div>;
if (!data) return null;
return (
<ul>
{data.map((user) => (
<li key={user.id}>
<Link href="/user/[id]" as={`/user/${user.id}`}>
{user.name ?? `User ${user.id}`}
</Link>
</li>
))}
</ul>
);
}

View File

@@ -0,0 +1,19 @@
import type { User } from "../../interfaces";
import { useRouter } from "next/router";
import useSwr from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export default function UserPage() {
const { query } = useRouter();
const { data, error, isLoading } = useSwr<User>(
query.id ? `/api/user/${query.id}` : null,
fetcher,
);
if (error) return <div>Failed to load user</div>;
if (isLoading) return <div>Loading...</div>;
if (!data) return null;
return <div>{data.name}</div>;
}

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

40
examples/auth-with-stytch/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

View File

@@ -0,0 +1,3 @@
## Stytch with Next.js
You can follow the guide on the [Stytch documentation](https://stytch.com/docs/sdks/resources/nextjs).

View File

@@ -0,0 +1,3 @@
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
AUTH_SECRET= # https://generate-secret.vercel.app/32

40
examples/auth/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

29
examples/auth/README.md Normal file
View File

@@ -0,0 +1,29 @@
# Authentication
This is an example using NextAuth.js for authentication.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/auth&project-name=auth&repository-name=auth&env=AUTH_GITHUB_ID,AUTH_GITHUB_SECRET,AUTH_SECRET)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), [pnpm](https://pnpm.io), or [Bun](https://bun.sh/docs/cli/bunx) to bootstrap the example:
```bash
npx create-next-app --example auth auth-app
```
```bash
yarn create next-app --example auth auth-app
```
```bash
pnpm create next-app --example auth auth-app
```
```bash
bunx create-next-app --example auth auth-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1 @@
export { GET, POST } from "@/auth";

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,5 @@
html,
body {
max-width: 100vw;
overflow-x: hidden;
}

View File

@@ -0,0 +1,18 @@
import "./globals.css";
export const metadata = {
title: "Next.js Authentication",
description: "Example using NextAuth.js",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

View File

@@ -0,0 +1,41 @@
import { auth, signIn, signOut } from "@/auth";
function SignIn() {
return (
<form
action={async () => {
"use server";
await signIn("github");
}}
>
<p>You are not logged in</p>
<button type="submit">Sign in with GitHub</button>
</form>
);
}
function SignOut({ children }: { children: React.ReactNode }) {
return (
<form
action={async () => {
"use server";
await signOut();
}}
>
<p>{children}</p>
<button type="submit">Sign out</button>
</form>
);
}
export default async function Page() {
let session = await auth();
let user = session?.user?.email;
return (
<section>
<h1>Home</h1>
<div>{user ? <SignOut>{`Welcome ${user}`}</SignOut> : <SignIn />}</div>
</section>
);
}

11
examples/auth/auth.ts Normal file
View File

@@ -0,0 +1,11 @@
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
providers: [GitHub],
});

View File

@@ -0,0 +1,6 @@
export { auth as default } from "./auth";
// Optionally, don't invoke Middleware on some paths
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};

View File

@@ -0,0 +1,20 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"next-auth": "^5.0.0-beta.4",
"react": "latest",
"react-dom": "latest"
},
"devDependencies": {
"@types/node": "latest",
"@types/react": "latest",
"@types/react-dom": "latest",
"typescript": "latest"
}
}

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,5 @@
AUTH0_ISSUER_BASE_URL="https://"
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_BASE_URL="http://localhost:3000"
AUTH0_SECRET=

40
examples/auth0/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# 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

68
examples/auth0/README.md Normal file
View File

@@ -0,0 +1,68 @@
# Next.js and Auth0 Example
This example shows how you can use `@auth0/nextjs-auth` to easily add authentication support to your Next.js application. It tries to cover a few topics:
- Signing in
- Signing out
- Loading the user on the server side and adding it as part of SSR ([`pages/advanced/ssr-profile.tsx`](pages/advanced/ssr-profile.tsx))
- Loading the user on the client side and using fast/cached SSR pages ([`pages/index.tsx`](pages/index.tsx))
- Loading the user on the client side and checking authentication CSR pages ([`pages/profile.tsx`](pages/profile.tsx))
- Loading the user on the client side by accessing API (Serverless function) CSR pages ([`pages/advanced/api-profile.tsx`](pages/advanced/api-profile.tsx))
- Creates route handlers under the hood that perform different parts of the authentication flow ([`pages/auth/[...auth0].tsx`](pages/auth/[...auth0].tsx))
Read more: [https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/](https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example auth0 auth0-app
```
```bash
yarn create next-app --example auth0 auth0-app
```
```bash
pnpm create next-app --example auth0 auth0-app
```
## Configuring Auth0
1. Go to the [Auth0 dashboard](https://manage.auth0.com/) and create a new application of type _Regular Web Applications_ and make sure to configure the following
2. Go to the settings page of the application
3. Configure the following settings:
- _Allowed Callback URLs_: Should be set to `http://localhost:3000/api/auth/callback` when testing locally or typically to `https://myapp.com/api/auth/callback` when deploying your application.
- _Allowed Logout URLs_: Should be set to `http://localhost:3000/` when testing locally or typically to `https://myapp.com/` when deploying your application.
4. Save the settings
### Set up environment variables
To connect the app with Auth0, you'll need to add the settings from your Auth0 application as environment variables
Copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git):
```bash
cp .env.local.example .env.local
```
Then, open `.env.local` and add the missing environment variables:
- `AUTH0_ISSUER_BASE_URL` - Can be found in the Auth0 dashboard under `settings`. (Should be prefixed with `https://`)
- `AUTH0_CLIENT_ID` - Can be found in the Auth0 dashboard under `settings`.
- `AUTH0_CLIENT_SECRET` - Can be found in the Auth0 dashboard under `settings`.
- `AUTH0_BASE_URL` - The base url of the application.
- `AUTH0_SECRET` - Has to be at least 32 characters. You can use [this generator](https://generate-secret.vercel.app/32) to generate a value.
## Deploy on Vercel
You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
### Deploy Your Local Project
To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example).
**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file.

7
examples/auth0/additional.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
export {};
declare global {
interface Window {
__user: any;
}
}

Some files were not shown because too many files have changed in this diff Show More