Skip to content

Commit

Permalink
feat: add new redirects feature (#2583)
Browse files Browse the repository at this point in the history
## What's the purpose of this pull request?

The implementation of the redirects feature in FastStore appears as a
strategic solution to facilitate the migration of old stores to our
platform.

The idea of ​​this feature is to run the redirect in the
**getStaticProps** function when a certain page is not found. In other
words, before rendering a **not found (404)** result to the user, we
check if there is a redirect associated with the pathname requested by
the user.

Since the pathname is not found (404). The redirect flow follows two
steps. First it goes through a customization function called
**matcher**. If the matcher cannot resolve the redirects, we validate
whether a redirect exists in the **rewriter** database.

![Captura de Tela 2024-12-10 às 10 18
24](https://github.com/user-attachments/assets/9f1a6fb0-da7d-46e3-80c0-69380f57eb40)

### Components

- **Matcher**: Optional function that can be implemented via
customization. Some pathnames can be resolved via simple logic, without
necessarily going to a database to check if there is a redirect
registered. [See an
example](https://github.com/vtex-sites/starter.store/blob/fad4fde01c0151cf78e1f9de5a378e24afe3f28a/src/redirects/index.ts).

- **Rewriter**: If the redirect is not resolved via customization, a
call will be made to the rewriter api to check if there is a redirect
associated with the requested pathname.

[Redirects
RFC](https://docs.google.com/document/d/15QxSNexAcDtrryDTR_LXcMmFLg2jnq2linMdp5-Q-r8/edit?usp=sharing)


## How to test it?
https://storeframework.myvtex.com/admin/cms/redirects

![Captura de Tela 2024-12-12 às 10 08
49](https://github.com/user-attachments/assets/c3cb9e59-cc00-4d78-af87-dac91a690cb5)

We can run locally and try to access one of these redirects. 

Example of matcher in starter:
vtex-sites/starter.store#626

Example: `/produto/1`

---------

Co-authored-by: eduardoformiga <eduardo.formiga@gmail.com>
  • Loading branch information
pedromtec and eduardoformiga authored Dec 16, 2024
1 parent f3ffdf2 commit 4624a5d
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/core/discovery.config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,6 @@ module.exports = {
enableCypressExtension: false,
noRobots: false,
preact: false,
enableRedirects: false,
},
}
12 changes: 12 additions & 0 deletions packages/core/src/customizations/src/redirects/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
interface MatcherArgs {
pathname: string
}

interface MatcherReturn {
destination: string
permanent?: boolean
}

export function matcher(_: MatcherArgs): MatcherReturn | null {
return null
}
11 changes: 11 additions & 0 deletions packages/core/src/pages/[...slug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import ProductListingPage, {
ProductListingPageProps,
} from 'src/components/templates/ProductListingPage'
import { getRedirect } from 'src/sdk/redirects'
import { PageContentType } from 'src/server/cms'
import { getPLP, PLPContentType } from 'src/server/cms/plp'
import { getDynamicContent } from 'src/utils/dynamicContent'
Expand Down Expand Up @@ -140,6 +141,16 @@ export const getStaticProps: GetStaticProps<
const notFound = errors.find(isNotFoundError)

if (notFound) {
if (storeConfig.experimental.enableRedirects) {
const redirect = await getRedirect({ pathname: `/${slug}` })
if (redirect) {
return {
redirect,
revalidate: 60 * 5, // 5 minutes
}
}
}

return {
notFound: true,
}
Expand Down
49 changes: 49 additions & 0 deletions packages/core/src/sdk/redirects/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import storeConfig from 'discovery.config'
import { matcher } from 'src/customizations/src/redirects'

type GetRedirectArgs = {
pathname: string
}

type GetRedirectReturn = {
destination: string
permanent: boolean
}

type RewriterResponse = {
location: string
status: number
}

const PERMANENT_STATUS = 308

export async function getRedirect({
pathname,
}: GetRedirectArgs): Promise<GetRedirectReturn> {
try {
const redirectMatch = matcher({ pathname })
if (redirectMatch) {
return {
destination: redirectMatch.destination,
permanent: redirectMatch.permanent ?? true,
}
}

const response = await fetch(
`https://${storeConfig.api.storeId}.myvtex.com/_v/public/redirect-evaluate${pathname}`
)
const rewriterData = (await response.json()) as RewriterResponse

if (rewriterData.location) {
return {
destination: rewriterData.location,
permanent: rewriterData.status === PERMANENT_STATUS,
}
}
return null
} catch (err) {
// TODO: handle error logs
console.error(err)
return null
}
}

0 comments on commit 4624a5d

Please sign in to comment.