4
0
forked from crowetic/commerce

feat: replace next-seo with custom solution (#660)

* replace next-seo with custom solution

* Updated check

Co-authored-by: LFades <luis@vercel.com>
This commit is contained in:
Dom Sip 2022-02-18 09:26:31 +00:00 committed by GitHub
parent 65c9d39ae6
commit db170558d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 176 additions and 25 deletions

View File

@ -1,17 +1,16 @@
import { FC } from 'react' import type { VFC } from 'react'
import NextHead from 'next/head' import { SEO } from '@components/common'
import { DefaultSeo } from 'next-seo'
import config from '@config/seo.json'
const Head: FC = () => { const Head: VFC = () => {
return ( return (
<> <SEO>
<DefaultSeo {...config} /> <meta
<NextHead> key="viewport"
<meta name="viewport" content="width=device-width, initial-scale=1" /> name="viewport"
content="width=device-width, initial-scale=1"
/>
<link rel="manifest" href="/site.webmanifest" key="site-manifest" /> <link rel="manifest" href="/site.webmanifest" key="site-manifest" />
</NextHead> </SEO>
</>
) )
} }

View File

@ -0,0 +1,157 @@
import Head from 'next/head'
import { FC, Fragment, ReactNode } from 'react'
import config from '@config/seo_meta.json'
const storeUrl =
process.env.NEXT_PUBLIC_STORE_URL || process.env.NEXT_PUBLIC_VERCEL_URL
const storeBaseUrl = storeUrl ? `https://${storeUrl}` : null
interface OgImage {
url?: string
width?: string
height?: string
alt?: string
}
interface Props {
title?: string
description?: string
robots?: string
openGraph?: {
title?: string
type?: string
locale?: string
description?: string
site_name?: string
url?: string
images?: OgImage[]
}
children?: ReactNode
}
const ogImage = ({ url, width, height, alt }: OgImage, index: number) => {
// generate full URL for OG image url with store base URL
const imgUrl = storeBaseUrl ? new URL(url!, storeBaseUrl).toString() : url
return (
<Fragment key={`og:image:${index}`}>
<meta
key={`og:image:url:${index}`}
property="og:image"
content={imgUrl}
/>
<meta
key={`og:image:width:${index}`}
property="og:image:width"
content={width}
/>
<meta
key={`og:image:height:${index}`}
property="og:image:height"
content={height}
/>
<meta
key={`og:image:alt:${index}`}
property="og:image:alt"
content={alt}
/>
</Fragment>
)
}
const SEO: FC<Props> = ({
title,
description,
openGraph,
robots,
children,
}) => {
/**
* @see https://nextjs.org/docs/api-reference/next/head
*
* meta or any other elements need to be contained as direct children of the Head element,
* or wrapped into maximum one level of <React.Fragment> or arrays
* otherwise the tags won't be correctly picked up on client-side navigations.
*
* The `key` property makes the tag is only rendered once,
*/
return (
<Head>
<title key="title">
{title ? `${config.titleTemplate.replace(/%s/g, title)}` : config.title}
</title>
<meta
key="description"
name="description"
content={description || config.description}
/>
<meta
key="og:type"
property="og:type"
content={openGraph?.type ?? config.openGraph.type}
/>
<meta
key="og:title"
property="og:title"
content={
openGraph?.title ?? config.openGraph.title ?? title ?? config.title
}
/>
<meta
key="og:description"
property="og:description"
content={
openGraph?.description ??
config.openGraph.description ??
description ??
config.description
}
/>
<meta
key="og:site_name"
property="og:site_name"
content={openGraph?.site_name ?? config.openGraph.site_name}
/>
<meta
key="og:url"
property="og:url"
content={openGraph?.url ?? config.openGraph.url}
></meta>
{openGraph?.locale && (
<meta key="og:locale" property="og:locale" content={openGraph.locale} />
)}
{openGraph?.images?.length
? openGraph.images.map((img, index) => ogImage(img, index))
: ogImage(config.openGraph.images[0], 0)}
{config.twitter.cardType && (
<meta
key="twitter:card"
name="twitter:card"
content={config.twitter.cardType}
/>
)}
{config.twitter.site && (
<meta
key="twitter:site"
name="twitter:site"
content={config.twitter.site}
/>
)}
{config.twitter.handle && (
<meta
key="twitter:creator"
name="twitter:creator"
content={config.twitter.handle}
/>
)}
<meta key="robots" name="robots" content={robots ?? 'index,follow'} />
<meta
key="googlebot"
name="googlebot"
content={robots ?? 'index,follow'}
></meta>
{children}
</Head>
)
}
export default SEO

View File

@ -0,0 +1 @@
export { default } from './SEO'

View File

@ -7,3 +7,4 @@ export { default as Searchbar } from './Searchbar'
export { default as UserNav } from './UserNav' export { default as UserNav } from './UserNav'
export { default as Head } from './Head' export { default as Head } from './Head'
export { default as I18nWidget } from './I18nWidget' export { default as I18nWidget } from './I18nWidget'
export { default as SEO } from './SEO'

View File

@ -1,6 +1,5 @@
import cn from 'clsx' import cn from 'clsx'
import Image from 'next/image' import Image from 'next/image'
import { NextSeo } from 'next-seo'
import s from './ProductView.module.css' import s from './ProductView.module.css'
import { FC } from 'react' import { FC } from 'react'
import type { Product } from '@commerce/types/product' import type { Product } from '@commerce/types/product'
@ -8,6 +7,7 @@ import usePrice from '@framework/product/use-price'
import { WishlistButton } from '@components/wishlist' import { WishlistButton } from '@components/wishlist'
import { ProductSlider, ProductCard } from '@components/product' import { ProductSlider, ProductCard } from '@components/product'
import { Container, Text } from '@components/ui' import { Container, Text } from '@components/ui'
import { SEO } from '@components/common'
import ProductSidebar from '../ProductSidebar' import ProductSidebar from '../ProductSidebar'
import ProductTag from '../ProductTag' import ProductTag from '../ProductTag'
interface ProductViewProps { interface ProductViewProps {
@ -89,7 +89,7 @@ const ProductView: FC<ProductViewProps> = ({ product, relatedProducts }) => {
</div> </div>
</section> </section>
</Container> </Container>
<NextSeo <SEO
title={product.name} title={product.name}
description={product.description} description={product.description}
openGraph={{ openGraph={{
@ -99,8 +99,8 @@ const ProductView: FC<ProductViewProps> = ({ product, relatedProducts }) => {
images: [ images: [
{ {
url: product.images[0]?.url!, url: product.images[0]?.url!,
width: 800, width: '800',
height: 600, height: '600',
alt: product.name, alt: product.name,
}, },
], ],

View File

@ -6,14 +6,13 @@
"title": "ACME Storefront | Powered by Next.js Commerce", "title": "ACME Storefront | Powered by Next.js Commerce",
"description": "Next.js Commerce - https://www.nextjs.org/commerce", "description": "Next.js Commerce - https://www.nextjs.org/commerce",
"type": "website", "type": "website",
"locale": "en_IE",
"url": "https://nextjs.org/commerce", "url": "https://nextjs.org/commerce",
"site_name": "Next.js Commerce", "site_name": "Next.js Commerce",
"images": [ "images": [
{ {
"url": "/card.png", "url": "/card.png",
"width": 800, "width": "800",
"height": 600, "height": "600",
"alt": "Next.js Commerce" "alt": "Next.js Commerce"
} }
] ]

View File

@ -34,7 +34,6 @@
"lodash.random": "^3.2.0", "lodash.random": "^3.2.0",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"next": "^12.0.8", "next": "^12.0.8",
"next-seo": "^4.28.1",
"next-themes": "^0.0.15", "next-themes": "^0.0.15",
"postcss": "^8.3.5", "postcss": "^8.3.5",
"postcss-nesting": "^8.0.1", "postcss-nesting": "^8.0.1",

View File

@ -4763,11 +4763,6 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
next-seo@^4.28.1:
version "4.29.0"
resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.29.0.tgz#d281e95ba47914117cc99e9e468599f0547d9b9b"
integrity sha512-xmwzcz4uHaYJ8glbuhs6FSBQ7z3irmdPYdJJ5saWm72Uy3o+mPKGaPCXQetTCE6/xxVnpoDV4yFtFlEjUcljSg==
next-themes@^0.0.15: next-themes@^0.0.15:
version "0.0.15" version "0.0.15"
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d" resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d"