Nextra快速起步

体验

警告

目前我暂时放弃了Nextra,因为我感觉文档和实际代码有脱节和冲突,让我非常困扰。

我用了两天时间来学习使用Nextra,可能因为我缺乏前端开发经验,对于 npm/pnpm 不熟悉,在尝试 Nextra i18n 时遇到不少挫折,导致我目前暂时放弃:

  • 似乎得从 GitHub: nextra 完整clone出项目,并使用 pnpm 来管理和启动,这样可以少走弯路

  • 我是最初从 nextra introduction 文档开始,文档实际上和 GitHub: nextra 是脱节的,导致我踩了坑折腾了很久

  • 因为我的后端维护经验影响,我会去折腾从最基础的部署开始,例如我尝试手册指导的安装方法,但是由于手册没有提供模版指导,我就摸索从模版复制内容过来运行。但是JavaScript或者说 React 生态其实很复杂(叠床架屋),手册又写得简略(开源文档似乎都习惯以开发者而不是使用者角度撰写),导致我调衡了一天才完成初步运行

  • Nextra i18n 又踩了坑,原来nextjs的i18n是一种动态路径路由,但是我之前找到的文档 Build a documentation site with Next.js using Nextra 使用的模版实际上是几年前尚未实现i18n。不得已推倒重来,在 GitHub: nextraexamples 中找出官方 i18n 模版 awr-site 来部署

  • 又遇到 npm/pnpm 包管理器的迷宫了,参考文档的步骤看来是有一定执行条件的,必须按照 GitHub: nextra 完整clone出项目来搞,我这种缝合胶水的方式困难重重,直接把我劝退了( Node.js 的包管理世界真是非常蛋疼,各种依赖冲突必须按照完美的排列完成,稍有改动可能就轰然倒塌)

不太顺利,我整理 Next.js vs Remix ,准备先退回到 React 学习,等后续再有机会重新开始(nextjs依然是最主流的WEB框架,可能不得不学习使用)

简介

Nextra是基于 Next.js 的框架,用于构建内容密集型的网站,Nextra具备了 Next.js 所有功能,并提供了易于使用的Markdown撰写功能。

Nextra提供了两种不同的用途theme:

备注

我的目标是构建自己的 docs.cloud-atlas.dev 不同的技术手册,所以会以 Docs Theme 为起点构建

安装

  • 在创建 Nextra Docs站点之前,需要首先安装 Next.js , React , Nextra 和 Nextra Docs Theme:

安装Nextra
# 创建项目目录,并在项目目录中安装 Next.js, React, Nextra, and Nextra Docs Theme
# 也可以采用github中已经初始化的仓库,例如 git clone [email protected]:huataihuang/docs.cloud-atlas.io.git

mkdir docs.cloud-atlas.dev
cd docs.cloud-atlas.dev

npm i next react react-dom nextra nextra-theme-docs

安装输出信息:

安装Nextra输出信息
npm warn ERESOLVE overriding peer dependency

added 456 packages in 20m

191 packages are looking for funding
  run `npm fund` for details
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.4.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.4.1
npm notice To update run: npm install -g [email protected]
npm notice

可以根据上述提示升级 npm 版本(可选): npm install -g npm@11.4.1

在上述安装步骤完成后,在项目目录下有如下文件:

安装完成后的文件
574M	node_modules
4.0K	package.json
240K	package-lock.json

完成安装之后,在项目目录下会有 package.json 生成,该文件用于指导安装对应依赖以及启动运行脚本:

package.json
{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "^15.3.3",
    "nextra": "^4.2.17",
    "nextra-theme-docs": "^4.2.17",
    "react": "^19.1.0",
    "react-dom": "^19.1.0"
  }
}

起步

  • 运行:

运行 dev 模式
npm run dev

模版(归档)

备注

这一段所使用的模版不支持 Nextra i18n ,我因为需要撰写多语言文档,所以我改为下一段记录的 模版 步骤

这里有报错,显示还没有 pagesapp 目录:

缺少 pagesapp 目录的报错

> dev
> next

   ▲ Next.js 15.3.3
   - Local:        http://localhost:3000
   - Network:      http://172.17.0.2:3000

 ✓ Starting...
[Error: > Couldn't find any `pages` or `app` directory. Please create one under the project root]

这个问题看起来是缺少基本内容目录导致无法运行,不过,不用急,继续按照 Nextra Docs Theme 指南进行配置和初始化

  • 在项目根目录下创建 next.config.mjs ,这个配置文件可以让Nextra处理 Next.js 项目中Markdown文件

项目根目录下创建 next.config.mjs
import nextra from 'nextra'

// Set up Nextra with its configuration
const withNextra = nextra({
  // ... Add Nextra-specific options here
})

// Export the final Next.js config with Nextra included
export default withNextra({
  // ... Add regular Next.js options here
})
  • 添加 mdx-components 文件:

  • 设置搜索

  • 创建根目录的布局:的

现在需要在 app 目录下创建一个根布局,也就是创建 app/layout.jsx 文件:

创建 app/layout.jsx
import { Footer, Layout, Navbar } from 'nextra-theme-docs'
import { Banner, Head } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import 'nextra-theme-docs/style.css'

export const metadata = {
  // Define your metadata here
  // For more information on metadata API, see: https://nextjs.org/docs/app/building-your-application/optimizing/metadata
}

const banner = <Banner storageKey="some-key">Nextra 4.0 is released 🎉</Banner>
const navbar = (
  <Navbar
    logo={<b>Nextra</b>}
    // ... Your additional navbar options
  />
)
const footer = <Footer>MIT {new Date().getFullYear()} © Nextra.</Footer>

export default async function RootLayout({ children }) {
  return (
    <html
      // Not required, but good for SEO
      lang="en"
      // Required to be set
      dir="ltr"
      // Suggested by `next-themes` package https://github.com/pacocoursey/next-themes#with-app
      suppressHydrationWarning
    >
      <Head
      // ... Your additional head options
      >
        {/* Your additional tags should be passed as `children` of `<Head>` element */}
      </Head>
      <body>
        <Layout
          banner={banner}
          navbar={navbar}
          pageMap={await getPageMap()}
          docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs"
          footer={footer}
          // ... Your additional layout options
        >
          {children}
        </Layout>
      </body>
    </html>
  )
}
  • 渲染 MDX 文件: 也就是使用 基于文件的路由 (file-based routing)来渲染MDX文件,有两种方式:

    • 通过 page 文中件

    • 通过 content 目录

按照 nextra Documentataion: File Conventions > content 介绍,现在的文件转换是采用 content 目录,只需要简单将 pages 目录重命名为 content 就可以

我尝试将 GitHub: shuding/nextra-docs-template 项目中初始页面复制过来修改:

复制 nextra-docs-template
cp -R ../nextra-docs-template/pages ./content

# nextra-docs-template 项目的页面使用了 components 目录下的
cp -R ../nextra-docs-template/components ./

当然,如果更为简单,就只需要 content/index.mdx 一个文件,简单案例内容可以如下:

一个最简单的 index.mdx
# Welcome to Nextra
 
Hello, world!
  • 添加 [[...mdxPath]]/page.jsx 文件:

添加 [[...mdxPath]]/page.jsx
import { generateStaticParamsFor, importPage } from 'nextra/pages'
import { useMDXComponents as getMDXComponents } from '../../mdx-components'

export const generateStaticParams = generateStaticParamsFor('mdxPath')

export async function generateMetadata(props) {
  const params = await props.params
  const { metadata } = await importPage(params.mdxPath)
  return metadata
}

const Wrapper = getMDXComponents().wrapper

export default async function Page(props) {
  const params = await props.params
  const result = await importPage(params.mdxPath)
  const { default: MDXContent, toc, metadata } = result
  return (
    <Wrapper toc={toc} metadata={metadata}>
      <MDXContent {...props} params={params} />
    </Wrapper>
  )
}

这里我修改了第2行,因为我发现项目根目录是 ../../ ,在这个根目录下有一个 mdx-components.js

另外,我还修改了 components/counter.tsx 添加了一行 use client' ,原因是:

TypeError: useState only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component

模版

备注

现在我使用这段记录的步骤,使用nextra官方发布的 examples/swr-site 模版,以支持多国语言文档撰写

同步模版
cd cloud-atlas.dev_arch
# 使用rsync同步
rsync -avz <nextra_dir>/examples/swr-site/ .
  • 安装(使用pnpm)

使用 pnpm 安装
pnpm i

报错:

使用 pnpm 安装报错
ERR_PNPM_WORKSPACE_PKG_NOT_FOUNDIn : "nextra@workspace:*" is in the dependencies but no package named "nextra" is present in the workspace

This error happened while installing a direct dependency of /Users/admin/docs/github/huataihuang/cloud-atlas.dev_arch

Packages found in the workspace:

原来 pnpm > introduction > Installation 在Workstpace中必须有一个 pnpm-workspace.yaml 来配置工作区

我参考 next.js learn: Getting Started 的方法来构建目录

参考模版进行安装
git clone 

cd cloud-atlas.dev_arch

# 先本地安装packages
npm i next react react-dom nextra nextra-theme-docs

# 从模版下载初始项目录,也就是从 swr-site 案例复制到本地的 arch 目录形成初始的开发项目,后续修改arch目录下内容进行定制
npx create-next-app arch --example "https://github.com/shuding/nextra/tree/main/examples/swr-site" --use-pnpm
# 失败,问题没有解决,看来我还需要学习

导航栏

nextra Documentataion: Built-In Components > Navbar 介绍了如何在导航栏设置内容,其中有一些是默认链接,例如 projectLink / chatLink

还可以将一些菜单和定制链接添加到导航栏,需要参考 Page Configuration >> navbar-items

favicon.ico

参考 next.js favicon,icon, and apple-icon

在Next.js中为应用设置icon的图片类型可以是 .ico / .jpg / .png ,文件存储在 /app 目录中。需要注意其中

  • favicon 图片必须位于 app/ 顶层目录,且只支持 .ico 文件类型

  • 应用 icon 则可以是多种类型 .ico, .jpg, .jpeg, .png, .svg

  • apple-icon 则支持 .jpg, .jpeg, .png

  • 除了 favicon 必须位于 app/ 外,另外两种图片类型可以位于 app/**/*

参考