Skip to content

Commit

Permalink
Add advanced redirects example (#716)
Browse files Browse the repository at this point in the history
  • Loading branch information
dominiksipowicz committed Jun 2, 2023
1 parent 201da87 commit 0b3f876
Show file tree
Hide file tree
Showing 20 changed files with 2,953 additions and 0 deletions.
4 changes: 4 additions & 0 deletions app-directory/redirect-with-fallback/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": "next/core-web-vitals"
}
43 changes: 43 additions & 0 deletions app-directory/redirect-with-fallback/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# Dependencies
/node_modules
/.pnp
.pnp.js

# Testing
/coverage

# Next.js
/.next/
/out/

# Production
build
dist

# Misc
.DS_Store
*.pem

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

# Local ENV files
.env.local
.env.development.local
.env.test.local
.env.production.local

# Vercel
.vercel

# Turborepo
.turbo

# typescript
*.tsbuildinfo

next-env.d.ts
4 changes: 4 additions & 0 deletions app-directory/redirect-with-fallback/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"typescript.tsdk": "node_modules/.pnpm/typescript@5.0.2/node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
38 changes: 38 additions & 0 deletions app-directory/redirect-with-fallback/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# redirect-with-fallback example

This example shows how to use a [route handler](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) to handle simple redirects.

The redirects can be found in [`redirects.js`](redirects.js), they are splitted in simple and complex.

- Simple are handled using a static route ([`generateStaticParams()`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params)) in [`app/[...slug]/route.ts`](app/[...slug]/route.ts)
- Complex are handled via [redirects](https://nextjs.org/docs/app/api-reference/next-config-js/redirects) in [`next.config.js`](next.config.js)

## Demo

https://redirect-with-fallback.vercel.app

## How to Use

You can choose from one of the following two methods to use this repository:

### One-Click Deploy

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=vercel-examples):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/app-directory/redirect-with-fallback&project-name=redirect-with-fallback&repository-name=redirect-with-fallback)

### Clone and Deploy

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
pnpm create next-app --example https://github.com/vercel/examples/tree/main/app-directory/redirect-with-fallback
```

Next, run Next.js in development mode:

```bash
pnpm dev
```

Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=edge-middleware-eap) ([Documentation](https://nextjs.org/docs/deployment)).
48 changes: 48 additions & 0 deletions app-directory/redirect-with-fallback/app/[...slug]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { simpleRedirects } from '../../redirects'

export const dynamic = 'error'

interface Params {
slug: string[]
}

export function GET(_: Request, { params }: { params: Params }): Response {
const sourceFromSlug = params.slug.join('/')
const redirectInfo = simpleRedirects.find(
(r) => normalizeSource(r.source) === sourceFromSlug
)
if (!redirectInfo) {
throw new Error(`Unexpected redirect ${String(params.slug)}`)
}
const status = redirectInfo.statusCode ?? (redirectInfo.permanent ? 308 : 307)
// Response.redirect does not support relative URLs but the `Location` header
// can be used to indicate a redirect to the browser

return new Response(null, {
status,
headers: { Location: redirectInfo.destination },
})
}

export function generateStaticParams(): Params[] {
const params = simpleRedirects.map((r) => {
return {
slug: normalizeSource(r.source).split('/'),
}
})
return params
}

function normalizeSource(source: string): string {
return (
source
// removes all backslashes
.replace(/\\/g, '')
// removes all leading slashes
.replace(/^\/+/, '')
// Trailing slash syntax. Supported by default for the generated routes.
.replace(/\{\/\}\?$/, '')
// replaces all occurrences of one or more slashes with a single slash
.replace(/\/+/g, '/')
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Page, Text, Link, Code, Snippet } from '@vercel/examples-ui'
import { complexRedirects } from '../../redirects'

export default function Home() {
return (
<Page className="flex flex-col gap-12">
<section className="flex flex-col gap-6">
<Text variant="h1">complex-redirect</Text>
<Text>Config used for this redirect</Text>
<Snippet>{JSON.stringify(complexRedirects[0], null, 2)}</Snippet>
<Text>
<Link href="/">back</Link>
</Text>
</section>
</Page>
)
}
39 changes: 39 additions & 0 deletions app-directory/redirect-with-fallback/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Nav from '@vercel/examples-ui/nav'
import Vercel from '@vercel/examples-ui/icons/vercel'

import '@vercel/examples-ui/globals.css'

interface Props {
children: React.ReactNode
}

export default async function RootLayout({ children }: Props) {
return (
<html>
<head />
<body>
<div className="mx-auto h-screen flex flex-col">
<Nav path="app-directory/redirect-with-fallback" />
<div className="px-8 bg-accents-0">
<main>{children}</main>
<footer className="py-10 w-full mt-auto border-t flex items-center justify-center bg-accents-1 z-20">
<span className="text-primary">Created by</span>
<a
href="https://vercel.com"
aria-label="Vercel.com Link"
target="_blank"
rel="noreferrer"
className="text-black"
>
<Vercel
className="inline-block h-6 ml-3 text-primary"
alt="Vercel.com Logo"
/>
</a>
</footer>
</div>
</div>
</body>
</html>
)
}
30 changes: 30 additions & 0 deletions app-directory/redirect-with-fallback/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Page, Text, Link, Code } from '@vercel/examples-ui'

export default function Home() {
return (
<Page className="flex flex-col gap-12">
<section className="flex flex-col gap-6">
<Text variant="h1">Redirects</Text>
<ul>
<li>
<Link href="/simple-redirect-source">/simple-redirect-source</Link>{' '}
- handled in a{' '}
<Link href="https://nextjs.org/docs/app/building-your-application/routing/router-handlers">
Route Handler
</Link>
</li>
<li>
<Link href="/complex-redirect-source">
/complex-redirect-source
</Link>{' '}
- handled by{' '}
<Link href="https://nextjs.org/docs/app/api-reference/next-config-js/redirects">
redirects
</Link>{' '}
in <Code>next.config.js</Code>
</li>
</ul>
</section>
</Page>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Page, Text, Link, Code, Snippet } from '@vercel/examples-ui'
import { simpleRedirects } from '../../redirects'

export default function Home() {
return (
<Page className="flex flex-col gap-12">
<section className="flex flex-col gap-6">
<Text variant="h1">simple-redirect</Text>
<Text>Config used for this redirect</Text>
<Snippet>{JSON.stringify(simpleRedirects[0], null, 2)}</Snippet>
<Text>
<Link href="/">back</Link>
</Text>
</section>
</Page>
)
}
8 changes: 8 additions & 0 deletions app-directory/redirect-with-fallback/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const redirects = require('./redirects').complexRedirects

/** @type {import('next').NextConfig} */
module.exports = {
async redirects() {
return redirects
},
}
29 changes: 29 additions & 0 deletions app-directory/redirect-with-fallback/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "redirect-with-fallback",
"repository": "https://github.com/vercel/examples.git",
"license": "MIT",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@vercel/examples-ui": "^1.0.5",
"next": "latest",
"react": "latest",
"react-dom": "latest"
},
"devDependencies": {
"@types/node": "^18.15.5",
"@types/react": "latest",
"autoprefixer": "^10.4.14",
"eslint": "^8.36.0",
"eslint-config-next": "latest",
"postcss": "^8.4.21",
"tailwindcss": "^3.2.7",
"turbo": "^1.8.5",
"typescript": "^5.0.2"
}
}
Loading

4 comments on commit 0b3f876

@vercel
Copy link

@vercel vercel bot commented on 0b3f876 Jun 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must have Developer access to commit code to Vercel on Vercel. If you contact an administrator and receive Developer access, commit again to see your changes.

Learn more: https://vercel.com/docs/concepts/teams/roles-and-permissions#enterprise-team-account-roles

@vercel
Copy link

@vercel vercel bot commented on 0b3f876 Jun 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

next-flask – ./python/nextjs-flask

nextjs-python.vercel.app
next-flask-git-main-vercel-labs.vercel.app
next-flask-vercel-labs.vercel.app
nextjs-flask-starter.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 0b3f876 Jun 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

edge-ab-testing-statsig – ./edge-middleware/ab-testing-statsig

edge-ab-testing-statsig.vercel.app
edge-ab-testing-statsig-git-main-now-examples.vercel.app
edge-ab-testing-statsig-now-examples.vercel.app
edge-ab-testing-statsig.vercel.sh

@vercel
Copy link

@vercel vercel bot commented on 0b3f876 Jun 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

redirect-with-fallback – ./app-directory/redirect-with-fallback

redirect-with-fallback-git-main-vercel-solutions-vtest314.vercel.app
redirect-with-fallback.vercel.app
redirect-with-fallback-vercel-solutions-vtest314.vercel.app

Please sign in to comment.