如何使用 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