简介

Strapi 和 Next.js 是当今市场上最好的无头 CMS 和应用程序开发环境!它们是两种强大的技术,可以协同工作,为您提供最佳的数字体验。

Strapi 是一个灵活的开源无头 CMS,它允许开发人员使用他们最喜欢的工具和框架,同时还赋予编辑者对其内容的控制权。 Next.js 是开发人员梦想成真,具有生产所需的所有功能:混合静态和服务器渲染、TypeScript 支持、智能捆绑、资产优化等等!

本教程将使用 Strapi 作为 CMS 并使用 Next.js 作为框架来构建一个博客应用程序。我们还将使用它的两个很酷的功能,图像优化和预览模式。这是我们将要构建的示例。

[nextjs-strapi-blog](https://res.cloudinary.com/practicaldev/image/fetch/s--1kSDxP5V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev -to-uploads.s3.amazonaws.com/uploads/articles/9scrsl52xc2pjs1eygqa.gif)

先决条件

  • node <=14.0.0

  • npm >=6.0.0

  • yarn

  • 关于git的基础知识

  • Strapi (v3.6.5)的最新版本

  • Next.js (v.11.0.1)的最新版本

目标

这篇文章是关于 Next.js 和 Strapi 的!您将学习如何使用 Image 组件将图像添加到您的应用程序中并使用 Next.js Preview。从 Strapi 查看您的内容的编辑版本。

在开始之前,让我们先谈谈 Next.js 的两个特性,我们将在我们的博客应用程序中使用它们。

用Image优化图片加载

网站的图像会显着影响其加载时间。通常,如果格式或大小不正确,它们是可能损害我们网站性能的资产。

查找和修复大图像是一个乏味的过程。如果您没有自动执行此操作的方法,您会发现自己花费数小时寻找那些降低您的网站速度并优化它们的图像。

使用 next/image 组件,我们可以调整大小、优化和提供现代格式的图像。这有助于我们极大地提高网站速度和图像用户体验。 Next.js 不仅可以优化本地托管的图像,还可以使用外部数据源。在我们的例子中,图片托管在 Strapi 上。

使用 Nextjs 预览模式获取草稿预览

静态站点生成是在用户请求之前提前创建静态页面的好方法。这使您的博客文章加载速度更快,但它使编辑体验不太愉快。每次您在帖子中进行编辑,并且您想查看编辑的外观时,您都必须重建整个网站。

在这种情况下,预览模式可以提供帮助。预览模式绕过静态生成,并在请求时而不是在构建时使用草稿数据而不是生产时呈现页面。简而言之,它所做的就是使静态页面动态化。

脚手架 Strapi 项目

安装

要安装 Strapi,您可以选择其中一种安装方法这里。

如果您想关注这篇文章,请随时使用https://github.com/amirtds/strapi-sqlite。

    git clone https://github.com/amirtds/strapi-sqlite
    strapi-sqlite
    yarn install && yarn develop

进入全屏模式 退出全屏模式

成功运行开发命令后,您应该可以在http://localhost:1337/访问 Strapi 仪表板,并在http://localhost:1337/admin创建一个管理员帐户。

内容类型

我们为博客构建了两种内容类型。

  • 作者

  • 博客

下面是每个集合中应包含的字段的图像。

[作者](https://res.cloudinary.com/practicaldev/image/fetch/s--NeqWrAFd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/90lpegl02k94zwstl70o.png)

[博客](https://res.cloudinary.com/practicaldev/image/fetch/s--5BWjl5Sh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/4gb0kgbg2azza2170lel.png)

通过单击左侧边栏上的_Authors_ 和_Blogs_,随意为每种内容类型添加新记录。

[记录](https://res.cloudinary.com/practicaldev/image/fetch/s--Af2ASXso--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/6pwy28bbsn0xrve2zgnx.png)

API 访问

我们正在使用 GraphQL 来使用 Strapi 数据。确保您的 Strapi 设置正确,并且您拥有适当的权限。转到设置 → 角色 → 公开并将findcount权限授予公开。

[权限](https://res.cloudinary.com/practicaldev/image/fetch/s--kOJU4J2j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/7htyrdd8lsoqbv68cbgk.png)

GraphQL 插件

如果您没有使用我们的 Strapi 存储库,请确保已安装 GraphQL 插件!您可以在左侧边栏中的 Marketplace 部分找到它。

[GraphQL 插件](https://res.cloudinary.com/practicaldev/image/fetch/s--kombjMVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/15jg0wq9cz0xrp8l9ikr.png)

使用 Nextjs 构建前端

创建新项目

让我们使用 GitHub 存储库中的示例创建一个名为next-blog的新项目并运行开发环境。在运行此命令之前,请确保您在 Strapi 中为作者和博客创建了一些记录。

    npx create-next-app next-blog --example "https://github.com/amirtds/blog/tree/develop"
    cd next-blog
    npm run dev

进入全屏模式 退出全屏模式

现在您应该可以通过http://localhost:3000访问该站点。

Nextjs 图片

在我们的博客应用程序中,我们使用 Nextjs Image 组件来优化我们的图像。

有关更多信息,请访问https://nextjs.org/docs/basic-features/image-optimization。

使用Image组件

  • 要使用图像组件,首先要导入它
    import Image from 'next/image'

进入全屏模式 退出全屏模式

  • 设置宽度、高度和src

需要设置Image的宽度和高度属性。在我们的应用程序中,我们还将 src 设置为src={urlBuilder(post.image[0].url)}

让我们更深入地看看我们的代码。在src/components/blogs.jsx我们有:

    {siteBlogs.map((post) => (
     <Link key={post.id} href={`/blogs/${post.slug}`}>
        <a>
            <motion.div variants={fadeIn} key={post.id} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}className="flex flex-col rounded-lg shadow-lg overflow-hidden">
            <div className="flex-shrink-0">
                <Image width={600} height={350} className="h-48 w-full object-cover" src={urlBuilder(post.image[0].url)} alt={post.title} />
            </div>
            <div className="flex-1 bg-white p-6 flex flex-col justify-between">
                <div className="flex-1">
                <a href={post.href} className="block mt-2">
                    <p className="text-xl font-semibold text-gray-900">{post.title}</p>
                    <p className="mt-3 text-base text-gray-500">{post.description}</p>
                </a>
                </div>
                <div className="mt-6 flex items-center">
                <div className="flex-shrink-0">
                    <span className="sr-only">{post.author.name}</span>
                    <Image width={50} height={50} className="h-10 w-10 rounded-full" src={urlBuilder(post.author.photo[0].url)} alt={post.title} />
                </div>
                <div className="ml-3">
                    <p className="text-sm font-medium text-gray-900">
                        {post.author.name}
                    </p>
                    <div className="flex space-x-1 text-sm text-gray-500">
                    <time dateTime={post.published}>{post.published}</time>
                    </div>
                </div>
                </div>
            </div>
            </motion.div>
        </a>
     </Link>
    ))}

进入全屏模式 退出全屏模式

*siteBlogs*是一个包含我们所有博客列表的数组。我们正在循环它并根据此列表中的每个博客项目创建一个博客卡。在Image中,src={urlBuilder(post.image[0].url)}结果将为STRAPI_URL/IMAGE_URL,例如http://localhost:1337/uploads/strapi_cover_1fabc982ce_1c5a5b390a.png

next.config.js中设置domain。在这个文件中,你应该有类似的东西

    module.exports = {
        images: {
          domains: ["localhost"],
        },
      }

进入全屏模式 退出全屏模式

在我们的例子中,我们有

    module.exports = {
        images: {
          domains: [configs.STRAPI_DOMAIN],
        },
      }

进入全屏模式 退出全屏模式

其中configs.STRAPI_DOMAIN是我们在 Strapi 域的configs.json文件中拥有的内容。

我们的Blog里没有很多图片,但是使用图片组件后,我们从灯塔审计中得到了很好的结果。

[阅读报告](https://res.cloudinary.com/practicaldev/image/fetch/s--iMApPwda--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/9qz2s82wdq6l3x7ai5qn.png)

Nextjs 预览

预览使预渲染页面作为服务器端渲染页面可见。这意味着,使用 Preview,您可以实时查看更改,而无需再次完成整个构建过程!

它是如何工作的?

NextJS 检查您的站点 cookie,如果存在两个特殊 cookie,它会将请求视为预览模式,并绕过 SSG。有关预览的更多信息,请访问https://nextjs.org/docs/advanced-features/preview-mode。

创建 API

我们需要为预览功能创建 2 个 API。

首先,我们将拥有/api/preview,它将预览模式 cookie 添加到您的站点。成功实现此 API 后,对其调用将添加__prerender_bypass__next_preview_datacookie。

[cookies](https://res.cloudinary.com/practicaldev/image/fetch/s--BTadn_3p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/fas86759uq4spzd7ix37.png)

打开preview.js文件并添加以下代码:

    // src/pages/api/preview.js

    import { getPost } from 'lib/api'

    export default async function handler(req, res) {
    # Check if the user is requesting with valid token
     if (req.query.secret !== (process.env.STRAPI_PREVIEW_SECRET)) {
       return res.status(401).json({ message: "Invalid token" });
     }

    # Make sure the blog post actiually exits
     const slug = req.query.slug
     const blogData = await getPost(slug)
     if (!blogData) {
       return res.status(401).json({ message: "Invalid slug" });
     }
    # If all good we set preview cookies
    # And we redirect the user to the preview version of the blog post
     res.setPreviewData({});

     res.writeHead(307, { Location: `/blogs/${slug}` });
     res.end();
    };

进入全屏模式 退出全屏模式

其次,我们将创建最后一个 API/api/exit-preview。要返回 SSG 模式,我们需要从浏览器中删除这些 cookie。这个 API 会解决这个问题。

    // src/pages/api/exit-preview.js

    export default async function exit(_, res) {
        // Exit the current user from "Preview Mode". This function accepts no args.
        res.clearPreviewData()
        // Redirect the user back to the index page.
        res.writeHead(307, { Location: "/" })
        res.end()
      }

进入全屏模式 退出全屏模式

从 Strapi 获取livepreview内容

最后一步是基于预览模式从 Strapi 获取数据。在我们开始从 Strapi 获取和显示数据之前,让我们看看如何检测预览模式。

以下context对象具有preview属性,该属性返回truefalse

我们如何在我们的页面上使用它。在您页面的getStaticProps函数中,您可以使用context作为参数,并根据 Preview 的状态,从 Strapi 获取实时或预览内容。

    // src/pages/blogs/[slug].js

    export const getStaticProps = async (context) => {
        const previewMode = context.preview == false || context.preview == null ? "live" : "preview"
        const slug = context.params.slug
        const BLOG_QUERY = gql`
        query($slug: String, $previewMode: String){
          blogs(where: {slug: $slug, _publicationState: $previewMode}){
            id
            title
            subtitle
            description
            published
            slug
            image{
              url
            }
            author {
              name
              photo {
                url
              }
            }
            content
          }
        }
        `
        const { data:blogData } = await apolloClient.query({
          query: BLOG_QUERY,
          variables: {
            slug,
            previewMode
          },
          preview: context.preview,
        })

进入全屏模式 退出全屏模式

如您所见,我们的调用中有_publicationState条件,可以是livePreview

外观如何

我们更改了“使用 Strapi 构建 Next.js 博客并使用预览和图像组件!”博客标题为“使用 Strapi 构建 Next.js 博客 - 草稿”,但我没有再次构建该站点,让我们看看它的样子。

[](https://res.cloudinary.com/practicaldev/image/fetch/s--eGJhto0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.dropbox.com/ s/w74frtne9zvr5uv/preview.gif%3Fraw%3D1)

结论

在本文中,我们学习了如何利用 Next.js 预览和图像优化的强大功能与 Strapi 内容。

我们希望本教程能够帮助您了解将这些工具集成到您的应用程序中是多么容易。在当今世界,为您的客户创造卓越的数字体验比以往任何时候都更加重要。

博客托管在 Vercel:https://nextjs-blog-rose-eta.vercel.app

您可以在找到源代码 https://github.com/amirtds/blog

使用 Strapi 和 Next.js,您可以做到这一点!我们看到了这两种强大的技术如何无缝协作,帮助您快速构建具有预览和优化图像的博客应用程序。

Logo

更多推荐