如何使用 Next 和 MDX 构建博客

已发表: 2022-03-10
快速总结 ↬在本指南中,我们将介绍 Next.js,这是一个流行的 React 框架,它提供了出色的开发人员体验并附带了生产所需的所有功能。 我们还将使用 Next.js 和 MDX 逐步构建一个博客。 最后,我们将介绍为什么您会选择 Next.js 而不是“vanilla” React 和 Gatsby 等替代品。

Next.js 是一个 React 框架,可让您快速构建静态和动态应用程序。 它已准备好生产并支持服务器端渲染和开箱即用的静态站点生成,使 Next.js 应用程序快速且对 SEO 友好。

在本教程中,我将首先解释 Next.js 到底是什么,以及为什么使用它而不是 Create React App 或 Gatsby。 然后,我将向您展示如何构建一个博客,您可以在该博客上使用 Next.js 和 MDX 编写和呈现帖子。

要开始使用,您需要一些 React 经验。 Next.js 的知识会派上用场,但不是强制性的。 本教程将使那些想要使用 Next.js 创建博客(个人或组织)或仍在寻找使用什么的人受益。

让我们潜入水中。

Next.js 是什么?

Next.js 是由 Vercel 创建和维护的 React 框架。 它是用 React、Node.js、Babel 和 Webpack 构建的。 它是生产就绪的,因为它带有许多通常会在“vanilla” React 应用程序中设置的强大功能。

Next.js 框架可以在服务器上呈现应用程序或静态导出它们。 它不会等待浏览器加载 JavaScript 来显示内容,这使得 Next.js 应用程序对 SEO 友好且速度极快。

为什么使用 Next.js 而不是创建 React 应用程序?

Create React App 是一个方便的工具,它提供了一个现代的构建设置,无需配置,也无需设置 Webpack、Babel 等或维护它们的依赖项。 这是当今创建 React 应用程序的推荐方式。 它有一个 TypeScript 模板,还附带了 React 测试库。

但是,如果你想构建一个多页面应用程序,那么你需要安装一个额外的库,就像你在服务器上渲染一个 React 应用程序一样。 额外的设置可能是一个问题,并且安装的任何包都可能会增加应用程序的最终包大小。

这正是 Next.js 旨在解决的问题。 它提供了最佳的开发人员体验,以及生产所需的所有东西。 它具有几个很酷的功能:

  • 静态导出(预渲染)
    Next.js 允许您在构建时将 Next.js 应用程序导出为无需服务器即可运行的静态 HTML。 这是生成网站的推荐方式,因为它是在构建时完成的,而不是在每次请求时完成的。
  • 服务器端渲染(预渲染)
    它会在每次请求时将页面预渲染为服务器上的 HTML。
  • 自动代码拆分
    与 React 不同,Next.js 会自动拆分代码并仅加载所需的 JavaScript,这使得应用程序运行速度更快。
  • 基于文件系统的路由
    Next.js 使用文件系统在应用程序中启用路由,这意味着pages目录下的每个文件都会被自动视为路由。
  • 代码热重载
    Next.js 依靠 React 快速刷新来热重载您的代码,从而提供出色的开发人员体验。
  • 样式选项
    Next.js 框架内置了对 Styled JSX、CSS 模块、Sass、LESS 等的支持。

Next.js 与盖茨比

Gatsby 是一个建立在 React 和 GraphQL 之上的静态站点生成器。 它很受欢迎,并拥有一个庞大的生态系统,提供主题、插件、食谱等。

Gatsby 和 Next.js 网站非常快,因为它们都在服务器上或静态呈现,这意味着 JavaScript 代码不会等待浏览器加载。 让我们根据开发人员的经验来比较它们。

Gatsby 很容易上手,特别是如果你已经了解 React。 但是,Gatsby 使用 GraphQL 来查询本地数据和页面。 使用 Gatsby 构建这个简单的博客可能有点过头了,因为 GraphQL 有一个学习曲线,而且静态页面的查询和构建时间会更长一些。 如果您两次构建同一个博客,首先使用 Gatsby,然后使用 Next.js,使用 Next.js 构建的博客在构建时会快得多,因为它使用常规 JavaScript 来查询本地数据和页面。

我希望您能利用 Next.js 框架的强大功能,看看为什么它比某些替代方案更方便。 如果您的网站严重依赖 SEO,这也是一个不错的选择,因为您的应用程序可以快速轻松地被 Go​​ogle 机器人抓取。 这就是为什么我们将在本文中使用 Next.js 来使用 MDX 库构建博客的原因。

让我们从设置一个新的 Next.js 应用开始。

跳跃后更多! 继续往下看↓

配置

有两种方法可以创建 Next.js 应用程序。 我们可以手动设置一个新的应用程序或使用创建下一个应用程序。 我们会选择后者,因为这是推荐的方式,它会自动为我们设置一切。

要启动新应用程序,请在命令行界面 (CLI) 中运行以下命令:

 npx create-next-app

项目初始化后,让我们按如下方式构建 Next.js 应用程序:

 src ├── components | ├── BlogPost.js | ├── Header.js | ├── HeadPost.js | ├── Layout.js | └── Post.js ├── pages | ├── blog | | ├── post-1 | | | └── index.mdx | | ├── post-2 | | | └── index.mdx | | └── post-3 | | └── index.mdx | ├── index.js | └── \_app.js ├── getAllPosts.js ├── next.config.js ├── package.json ├── README.md └── yarn.lock

如您所见,我们的项目具有简单的文件结构。 有三点需要注意:

  • _app.js允许我们将一些内容附加到App.js组件中,以使其全局化。
  • getAllPosts.js帮助我们从pages/blog文件夹中检索博客文章。 顺便说一句,您可以随意命名文件。
  • next.config.js是我们的 Next.js 应用程序的配置文件。

我稍后会回到每个文件并解释它的作用。 现在,让我们看看 MDX 包。

安装 MDX 库

MDX 是一种格式,可以让我们无缝地编写 JSX 并将组件导入到我们的 Markdown 文件中。 它使我们能够编写常规的 Markdown 并将 React 组件嵌入到我们的文件中。

要在应用程序中启用 MDX,我们需要安装@mdx-js/loader库。 为此,我们首先导航到项目的根目录,然后在 CLI 中运行以下命令:

 yarn add @mdx-js/loader

或者,如果您使用的是 npm:

 npm install @mdx-js/loader

接下来,安装@next/mdx ,这是一个特定于 Next.js 的库。 在 CLI 中运行此命令:

 yarn add @next/mdx

或者,对于 npm:

 npm install @next/mdx

伟大的! 我们完成了设置。 让我们动手,编写一些有意义的代码。

配置next.config.js文件

const withMDX = require("@next/mdx")({ extension: /\.mdx?$/ }); module.exports = withMDX({ pageExtensions: ["js", "jsx", "md", "mdx"] });

在本教程的前面,我说过在构建时 Next.js 会将pages文件夹下的文件视为页面/路由。 默认情况下,Next.js 只会选择带有.js.jsx扩展名的文件。 这就是为什么我们需要一个配置文件,为 Next.js 的默认行为添加一些自定义。

next.config.js文件告诉框架带有.md.mdx扩展名的文件在构建时也应该被视为页面/路由,因为包含文章的blog文件夹位于pages目录中。

话虽如此,我们可以在下一部分开始获取博客文章。

获取博客文章

使用 Next.js 构建博客非常简单的原因之一是您不需要 GraphQL 等来获取本地帖子。 您可以只使用常规 JavaScript 来获取数据。

getAllPosts.js

 function importAll(r) { return r.keys().map((fileName) => ({ link: fileName.substr(1).replace(/\/index\.mdx$/, ""), module: r(fileName) })); } export const posts = importAll( require.context("./pages/blog/", true, /\.mdx$/) );

这个文件起初可能令人生畏。 这是一个从pages/blog文件夹中导入所有 MDX 文件的函数,并且对于每篇文章,它都会返回一个包含文件路径的对象,不包括扩展名 ( /post-1 ) 和博客文章的数据。

有了这些,我们现在可以构建组件,以便在 Next.js 应用程序中设置样式和显示数据。

构建组件

components/Layout.js

 import Head from "next/head"; import Header from "./Header"; export default function Layout({ children, pageTitle, description }) { return ( <> <Head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta charSet="utf-8" /> <meta name="Description" content={description}></meta> <title>{pageTitle}</title> </Head> <main> <Header /> <div className="content">{children}</div> </main> </> ); }

在这里,我们有Layout组件,我们将使用它作为博客的包装器。 它接收要在页面头部显示的元数据和要显示的组件。

components/Post.js

 import Link from 'next/link' import { HeadPost } from './HeadPost' export const Post = ({ post }) => { const { link, module: { meta }, } = post return ( <article> <HeadPost meta={meta} /> <Link href={'/blog' + link}> <a>Read more →</a> </Link> </article> ) }

该组件负责显示博客文章的预览。 它接收post对象以显示为道具。 接下来,我们使用解构从对象中提取帖子的link和要显示的meta 。 有了这个,我们现在可以将数据传递给组件并使用Link组件处理路由。

components/BlogPost.js

 import { HeadPost } from './HeadPost' export default function BlogPost({ children, meta}) { return ( <> <HeadPost meta={meta} isBlogPost /> <article>{children}</article> </> ) }

BlogPost组件帮助我们渲染一篇文章。 它接收要显示的帖子及其meta对象。

到目前为止,我们已经介绍了很多——但我们没有文章可以展示。 让我们在下一节中解决这个问题。

用 MDX 写帖子

import BlogPost from '../../../components/BlogPost' export const meta = { title: 'Introduction to Next.js', description: 'Getting started with the Next framework', date: 'Aug 04, 2020', readTime: 2 } export default ({ children }) => <BlogPost meta={meta}>{children}</BlogPost>; ## My Headline Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque maximus pellentesque dolor non egestas. In sed tristique elit. Cras vehicula, nisl vel ultricies gravida, augue nibh laoreet arcu, et tincidunt augue dui non elit. Vestibulum semper posuere magna, quis molestie mauris faucibus ut.

如您所见,我们导入了BlogPost组件,该组件接收帖子的meta数据和正文。

参数children是博客文章的正文,或者准确地说,是meta对象之后的所有内容。 它是负责渲染帖子的功能。

通过该更改,我们可以移动到index.js文件并在主页上显示帖子。

显示帖子

import { Post } from "../components/Post"; import { posts } from "../getAllPosts"; export default function IndexPage() { return ( <> {posts.map((post) => ( <Post key={post.link} post={post} /> ))} </> ); }

在这里,我们首先导入Post组件和从blog文件夹中获取的帖子。 接下来,我们遍历文章数组,对于每篇文章,我们使用Post组件来显示它。 完成后,我们现在可以获取帖子并将其显示在页面上。

我们快完成了。 但是,仍然没有使用Layout组件。 我们可以在这里使用它并用它包装我们的组件。 但这不会影响文章页面。 这就是_app.js文件发挥作用的地方。 让我们在下一节中使用它。

使用_app.js文件

在这里,下划线符号 ( _ ) 非常重要。 如果您省略它,Next.js 会将文件视为页面/路由。

 import Layout from "../components/Layout"; export default function App({ Component, pageProps }) { return ( <Layout pageTitle="Blog" description="My Personal Blog"> <Component {...pageProps} /> </Layout> ); }

Next.js 使用App组件来初始化页面。 该文件的目的是覆盖它并为项目添加一些全局样式。 如果您有需要在整个项目中共享的样式或数据,请将它们放在这里。

我们现在可以在 CLI 中浏览项目文件夹并运行以下命令在浏览器中预览博客:

 yarn dev

或者,在 npm 中:

 npm run dev

如果您在浏览器中打开https://localhost:3000 ,您将能够看到:

最终结果预览

伟大的! 我们的博客看起来不错。 我们已经完成了使用 Next.js 和 MDX 构建博客应用程序。

结论

在本教程中,我们通过使用 MDX 库构建博客来了解 Next.js。 Next.js 框架是一个方便的工具,它使 React 应用程序对 SEO 友好且快速。 它可以立即用于构建静态、动态的 JAMstack 网站,因为它已准备好生产并具有一些不错的功能。 Next.js 被大公司广泛使用,性能不断提高。 这绝对是您下一个项目要检查的东西。

您可以在 CodeSandbox 上预览完成的项目。

谢谢阅读!

资源

这些有用的资源将使您超出本教程的范围。

  • Next.js 文档
  • Next.js 和 MDX 文档
  • “创建 Next.js 应用”,Next.js