社区编辑申请
注册/登录
使用 Next.js 12 和 Cosmic 构建一个可以上线的餐厅网站 译文
开发 前端
在本教程中,我将向你展示如何使用 Next.js 和 Cosmic Headless CMS 构建一个完全移动响应的餐厅网站。Figma 模板可以在 ui8.net 上找到。此外,额外功能包括部署到 Vercel 和使用 Cosmic Webhooks 设置自动静态内容重新验证。

译者 | 吴河东

审校 | 孙淑娟 梁策

使用工具

​Next.js​ - 用于生产的 React 框架,可以轻松地启动全栈应用程序。

​Cosmic​​ - 无头部 CMS工具,它实现了数据(内容)层的独立性,并使我们能够快速管理网站内容。

​Sass ​- 一种稳定、强大的专业级 CSS 扩展语言。

相关资源

相关工具介绍

Next.js是一个完整的套件,用于构建超快的 React 应用程序。它对开发人员友好,使用轻松。随着​​Next.js 12.1​​的发布,性能优化、中间件、React 18 支持、按需 ISR、对 SWC 的扩展支持等新功能只会变得更好。

Cosmic是一款出色的无头 CMS,它使我们能够全面管理和存储网站内容和媒体,并进行快速更新。

探索 Next.js 的 4 个新杀手级功能并将其用于模板

先安装一个新的包含工具和配置的​​ Next.js应用程序​​​。本教程中使用​​Node.js ​​12.22.0 或更高版本。

打开终端,输入:

npx create-next-app@latest nextjs-restaurant-website-cms
# or
yarn create next-app nextjs-restaurant-website-cms

安装依赖

cd nextjs-restaurant-website-cms
npm i
# or
cd nextjs-restaurant-website-cms
yarn

开始运行

npm run dev
# or
yarn dev

在浏览器中打开 ​​*http://localhost:3000/*以查看主页​​。

1. Rust 编译器

Next.js 12 的关键特性之一是性能优化。为了提高性能,Next.js 用可扩展的 Rust 编译器替换了 Babel 编译器,并默认使用 Next.js 12 启用它,该​​编译器构建​​​在​​SWC​​(Speedy Web Compiler)之上,它支持SWC。它可以将TypeScript和JavaScript转化为可以在旧浏览器上运行的 JavaScript 代码。

SWC 在单线程上比 Babel 快 20 倍,在四核上快 70 倍。

2. 中间件

这是最令人兴奋的功能之一。中间件使我们能够使用代码而不是配置。这意味着你可以在请求完成之前运行代码,并根据请求,你可以通过重写、重定向、添加标头、设置 Cookie 等来修改响应。通过中间件,你可以实现​​身份验证、机器人保护、重定向、重写、服务器端分析、日志记录和处理不受支持的浏览器​​等。

中间件被创建在 /pages/_middleware.ts ,它将在/pages目录中的所有路由上运行。_middleware.js文件长什么样?让我们以我们的模板为例。

// pages/_middleware.js

import { NextResponse } from 'next/server';

export async function middleware( request ) {
// create an instance of the class to access the public methods.
//This uses next(),

let response = NextResponse.next();

const country = request.geo.country || 'US';
const city = request.geo.city || 'San Francisco';
const region = request.geo.region || 'CA';

// get the cookies from the request
let cookieFromRequest = request.cookies['location-cookie'];

if(!cookieFromRequest) {
// set the `cookie`
response.cookie('location-cookie', `${country|city|region}`);
}

return response;
}

3.按需增量静态再生​​ISR​

Next.js 公开了一个函数unstable_revalidate(),允许你使用getStaticProps重新授权各个页面。在getStaticProps中,你不需要指定 revalidate 来按需重新验证,只需要在unstable_revalidate()调用时按需重新验证页面。

// pages/api/revalidate.js

export default async function handler(req, res) {
try {
await res.unstable_revalidate('/menu/' + req.body.data.slug)
return res.json({ revalidated: true })
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).send('Error revalidating')
}
}

4. 使用 AVIF 实现更快的图像优化和更小的图像

内置的图像优化API已更新以支持与ISR页面相同的模式,即在后台提供过时的图像并重新验证。此外,它还支持 AVIF 图像,使图像比 WebP 小 20%。

此功能是可选的,在编辑图片配置的时候可以选择启用。在文件next.config.js中配置下面参数即可:

// next.config.js

const nextConfig = {
reactStrictMode: true,
images: {
formats: ['image/avif', 'image/webp'],
domains: ['imgix.cosmicjs.com'],
},
}

module.exports = nextConfig

Cosmic 特征概述

  • 可定制的 API:用户自己定义 API 的 schema,models和 controllers。为方便起见, Cosmic 同时提供了REST 和 GraphQL API的方式。
  • 快速且安全的内容管理系统和 API 工具包。
  • Webhooks在你需要的任何地方回调,以获得你想要的功能,使用 Cosmic API 开箱即用。
  • ​包含Imgix​​集成,可让你为针对跨平台体验优化的动态应用程序进行强大的图像处理。

Cosmic 操作

第一步创建​​免费的 Cosmic 帐户​​。让我们选择“从头开始”(Start from scratch)选项。

现在让我们将内容放进groups,用Object Type来共享组里的内容。例如,部分名称、标题、简介和图片等具有类似属性的部分,这些模块希望得到复用以为不同部分创建内容。

创建Object Type并添加部分属性用来在“Content Model”中定义“Metafields”。

现在,你可以为部分创建一个Object Type模型,并且可以像这样填充内容。

以类似的方式,你可以按照当前的数据模型、架构设计定义模块并创建Object Type:

  • Singleton 为一个单独的模型
  • Multiple 为可重复使用的模型

是时候获取 Next.js 应用程序的值了

将 Cosmic 模块安装到 Next.js 应用程序中。

npm i cosmicjs
# or
yarn add cosmicjs

然后,转到 Cosmic 面板 Your Bucket > Settings > API Access并找到你的 Bucket slug 和 API 读取密钥。

将此 Bucket slug 和 API 读取密钥添加到你的 Next.js 应用程序.env中。

//.env
COSMIC_BUCKET_SLUG=your_cosmic_slug
COSMIC_READ_KEY=your_cosmic_read_key

要使用模板 UI,你需要在​​GitHub​​中将它克隆。打开终端,粘贴或键入此代码以安装所有依赖项,然后运行它。

git clone https://github.com/cosmicjs/nextjs-restaurant-website-cms.git
cd nextjs-restaurant-website-cms

npm install
#or
yarn install

npm run dev
#or
yarn dev

向我们之前在 Cosmic 面板中创建的函数getDataFromBucket请求,并按类型从 Cosmic 中获取我们创建的内容params。

// src/lib/api.js

import Cosmic from 'cosmicjs';

const BUCKET_SLUG = process.env.COSMIC_BUCKET_SLUG
const READ_KEY = process.env.COSMIC_READ_KEY

const bucket = Cosmic().bucket({
slug: BUCKET_SLUG,
read_key: READ_KEY,
});

export async function getDataFromBucket(preview) {
const params = {
type: 'header',
props: 'title,slug,metadata,created_at',
sort: '-created_at',
...(preview && { status: 'all' }),
}
const data = await bucket.getObjects(params)
return data.objects
}

显示我们的内容,将其与我们的 UI 集成,并将一些元素呈现到主页。为此,你需要将此添加到index.js。

// pages/index.js

import Head from 'next/head';
import Home from 'components/Home';
import Layout from 'components/Layout';
import Footer from 'components/Footer';
import AboutUs from 'components/AboutUs';
import SpacialMenu from 'components/Menu';
import Introduction from 'components/Introduction';
import VideoIntro from 'components/VideoIntro';
import Gallery from 'components/Gallery';
import Contacts from 'components/Contact';

import { getDataFromBucket } from 'lib/api';
import chooseByType from 'utils/chooseValueByType';

function Template({ data }) {
return (
<>
<Head>
<title>Next.js Restaurant CMS</title>
<meta name="description" content="Create template using cosmic.js CMS" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Layout navbar={chooseByType(data, 'navigation')}>
<Home info={chooseByType(data, 'header')}/>
<AboutUs info={chooseByType(data, 'about')}/>
<SpacialMenu info={[chooseByType(data, 'drink'), chooseByType(data, 'food')]}/>
<Introduction info={chooseByType(data, 'history')}/>
<Gallery info={[chooseByType(data, 'gallery'), chooseByType(data, 'food')]}/>
</Layout>
<Footer>
<VideoIntro url={chooseByType(data, 'video')}/>
<Contacts info={chooseByType(data, 'contact')}/>
</Footer>
</>
)
}

export async function getStaticProps({ preview }) {
const data = (await getDataFromBucket(preview)) || [];
return {
props: { data },
}
}

export default Template;

下面函数chooseByType将过滤我们在 Cosmic 面板中创建的 Object Type。(Slug)

(Slug)
// src/utils/chooseValueByType.js

const chooseByType = (data, slugName) => {
if( data && slugName ) {
const chooseBySlug = data?.filter(content => Object.values(content).includes(slugName));
return chooseBySlug ? chooseBySlug[0] : [];
}
}

export default chooseByType;



制作菜单项页面

在 Next.js 中,你可以创建动态路由,可以考虑用下面pages/menu/[slug].js页面来创建单个菜单项页面和动态路由:

// pages/menu/[slug].js

import Head from 'next/head';
import { useRouter } from 'next/router';

import Layout from 'components/Layout';
import Footer from 'components/Footer';
import Contacts from 'components/Contact';
import MenuIntro from 'components/MenuIntro';
import VideoIntro from 'components/VideoIntro';
import Gallery from 'components/Gallery';

import { getAllDataWithSlug,getDataFromBucket } from 'lib/api';
import chooseByType from 'utils/chooseValueByType';

function Menu({ data }) {
const {
query: {slug},
} = useRouter();

return (
<>
<Head>
<title>Next.js Restaurant CMS</title>
<meta name="description" content="Create template using cosmic.js CMS" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Layout navbar={chooseByType(data, 'navigation')}>
<MenuIntro info={[chooseByType(data, 'food'), chooseByType(data, 'drink')]} slug={slug} />
<Gallery info={[chooseByType(data, 'gallery'), chooseByType(data, 'food')]}/>
</Layout>
<Footer>
<VideoIntro url={chooseByType(data, 'sushi')}/>
<Contacts info={chooseByType(data, 'contact')}/>
</Footer>
</>
)
}

export async function getStaticProps({ params, preview = null }) {
const data = (await getDataFromBucket(preview)) || [];
return {
props: { data },
}
}

export async function getStaticPaths() {
const dataWithSlug = (await getAllDataWithSlug()) || [];

return {
paths: dataWithSlug.map((menu) => `/menu/${menu.slug}`),
fallback: true,
}
}

export default Menu;

该函数getServerSideProps用于每次调用此路由时从 Cosmic 获取数据。在pages/api/revalidate.js中,我们在unstable_revalidate()被调用时使用unstable_revalidate函数来按需重新验证页面。如果出现错误,Next.js 将继续显示最后成功生成的页面。

在​​Vercel​​上部署代码库后,你可以通过转到 Cosmic 面板并导航到Bucket Settings > Webhooks来启用内容更新的重新验证。编辑内容时要触发的事件是object.edited.published。Webhook URL 端点将如下所示:${YOUR_VERCEL_DEPLOYMENT_URL}/api/revalidate。

这也使得在创建或更新来自无头部的CMS 的内容时,你的网站更容易更新。

现在来测试一下,在 Cosmic 面板中编辑内容,并查看静态内容立即更新。

结论

现在,你已拥有一个动态的、可定制的、完全集成的模板,其中包含新的 Next.js 和 Cosmic 功能。你可以为其他类型的企业定制,并按照自己的喜好来使用。

译者介绍

吴河东,51CTO社区编辑,具有5年工作经验,从事电商相关IT工作。擅长后台开发,大数据,算法等。

原文标题:Build a Production Ready Restaurant Website with Next.js 12 and Cosmic,作者:Naira Gezhoyan


责任编辑:华轩 来源: 51CTO
相关推荐

2022-06-15 11:02:40

网络安全运营

2022-05-27 10:00:06

C++游戏引擎

2022-05-31 10:30:16

元宇宙数字人高清渲染

2022-06-16 15:42:16

攻击面管理ASM

2022-06-07 11:16:51

云原生人工智能运维

2022-06-28 10:03:56

CentOSLinux

2022-06-27 15:25:08

架构模型治理

2022-05-25 07:11:13

2022-06-28 12:35:21

DockerPython

2022-05-11 15:08:52

驱动开发系统移植

2022-06-27 23:44:37

云原生云存储云计算

2022-06-27 17:46:53

PythonFlask

2022-04-23 17:49:05

区块链元宇宙MetaCon

2022-06-23 06:34:56

Node.js子线程

2022-06-13 12:43:13

Java模块

2022-06-02 15:28:42

网络安全信息通信数据保护

2022-06-15 16:16:21

分布式数据库鸿蒙

2022-05-25 10:04:43

Go编程

2022-05-23 10:26:50

Node.jsJavaScrip

2022-06-10 07:45:09

CentOS国产操作系统

同话题下的热门内容

哪个版本的JVM最快?无代码软件发展简史及未来趋势携程基于 GraphQL 的前端 BFF 服务开发实践为什么会存在 1px 问题?怎么解决?EcmaScript 2022 正式发布,有哪些新特性?一文详解|增长那些事儿远程医疗:优势、前景和现有IT解决方案手把手教你实现一个 Python 计时器

编辑推荐

太厉害了,终于有人能把TCP/IP协议讲的明明白白了!牛人5次面试腾讯不成功的经验HBase原理–所有Region切分的细节都在这里了Javascript如何监听页面刷新和关闭事件如何搭建一个HTTPS服务端
我收藏的内容
点赞
收藏

51CTO技术栈公众号