发布于

v1 新特性

概述

一篇关于 v1.0 中引入的新特性的文章。新特性:

尽管添加了许多新特性,首次加载的 JS 从 43kB 减少到 39kB!1

如果你正在从模板的 v0 版本迁移,请参阅下方的升级指南

主题颜色

你可以通过修改 tailwind 配置文件中的 primary 属性来轻松调整主题颜色:

tailwind.config.js
theme: {
    colors: {
      primary: colors.teal,
      gray: colors.neutral,
      ...
    }
  ...
}

primary 颜色属性应该是一个对象,包含从 50、100、200 ... 到 900 的键和相应的颜色代码值。

Tailwind 包含了出色的默认调色板,可用于自定义网站主题。查看自定义颜色文档页面了解所有可用选项。

从 v1 迁移?你可以通过将 primary 设置为 colors.sky(Tailwind 2.2.2 及以上版本,否则使用 colors.lightBlue)并将 gray 改为 colors.gray 来恢复之前的主题。

从 v1.1.2+ 开始,你还可以通过修改 css/prism.css 样式表来轻松自定义代码块的样式。Token 类名与 prismjs 兼容,因此你可以从 prismjs 样式表中复制和调整 token 样式,例如 prism 主题

Xdm MDX 编译器

我们将 MDX 打包器从 next-mdx-remote 切换到了 mdx-bundler。 它在底层使用了 xdm,即最新的 micromark 3 和 remark、rehype 库。

警告: 如果你之前使用了自定义的 remark 或 rehype 库,请升级到兼容 micromark 3 的版本。如果你正在升级,请删除 node_modulespackage-lock.json 以避免与过去依赖项相关的问题。

xdm 相比 @mdx-js/mdx(next-mdx-remote 内部使用的编译器)有多个改进,但可能存在一些破坏性的行为变更。 请检查你的 markdown 输出以进行验证。

一些新的可能性包括使用 import 语法直接在 mdx 文件中加载组件,以及包含可以在构建步骤中编译和打包的 js 代码。

例如,以下 jsx 代码片段可以直接在 MDX 文件中用于渲染页面标题组件:

// 如果你使用 js,可以使用 import PageTitle from './components/PageTitle.js'
import PageTitle from './components/PageTitle.tsx'
;<PageTitle> 在 MDX 中使用 JSX 组件 </PageTitle>

默认配置会相对于 components 目录解析所有组件。

注意: 需要外部图像加载器的组件还需要额外的 esbuild 配置。 依赖于全局应用状态或生命周期的组件(如 Nextjs Link 组件)也无法在此设置下工作,因为每个 mdx 文件都是独立构建的。 对于这种情况,最好使用组件替换。

目录组件

Docusaurus 和 Gatsby 的 gatsby-remark-table-of-contents 启发, 包含文档所有顶级标题的 toc 变量会传递给 MDX 文件,并可以相应地进行样式设置。 为了简化生成目录(TOC)的过程,你可以使用现有的 TOCInline 组件。

例如,这篇文章中的目录是通过以下代码生成的:

<TOCInline toc={props.toc} exclude="Overview" toHeading={2} />

你可以通过配置 fromHeadingtoHeading 属性来自定义显示的标题,或者通过向 exclude 属性传递字符串或字符串数组来排除特定标题。默认情况下,所有深度为 3 或更小的标题都会缩进。这可以通过更改 indentDepth 属性来配置。 可以使用 asDisclosure 属性将目录渲染在可展开的元素中。

以下是在可展开元素中渲染的完整目录。

<TOCInline toc={props.toc} asDisclosure />
Table of Contents

布局

你可以通过配置 frontmatter 字段将 mdx 博客内容映射到布局组件。例如,这篇文章就是使用新的 PostSimple 布局编写的!

添加新模板

布局模板存储在 ./layouts 文件夹中。你可以在此文件夹中添加要映射到 markdown 内容的 React 组件。 组件文件名必须与 markdown frontmatter 中 layout 字段指定的名称匹配。

唯一必需的字段是 children,它包含渲染后的 MDX 内容,但你可能希望传入 frontMatter 内容并在模板中渲染它。

你可以配置模板接受其他字段 - 参见 PostLayout 组件作为示例。

以下是一个可以进一步自定义的布局示例:

export default function ExampleLayout({ frontMatter, children }) {
  const { date, title } = frontMatter

  return (
    <SectionContainer>
      <div>{date}</div>
      <h1>{title}</h1>
      <div>{children}</div>
    </SectionContainer>
  )
}

配置博客文章 frontmatter

使用 frontmatter 中的 layout 字段来指定要将 markdown 文章映射到的模板。这篇文章的 frontmatter 如下所示:

---
title: 'New features in v1'
date: '2021-05-26   '
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'Introducing the new layout features - you can map mdx blog content to layout components by configuring the frontmatter field'
layout: PostSimple
---

你可以通过修改 DEFAULT_LAYOUT 变量在相应的页面部分配置默认布局。 博客文章页面的 DEFAULT_LAYOUT 设置为 PostLayout

扩展

layout 被映射为包装器,包装整个 MDX 内容。

export const MDXComponents = {
  Image,
  a: CustomLink,
  pre: Pre,
  wrapper: ({ components, layout, ...rest }) => {
    const Layout = require(`../layouts/${layout}`).default
    return <Layout {...rest} />
  },
}

export const MDXLayoutRenderer = ({ layout, mdxSource, ...rest }) => {
  const MDXLayout = useMemo(() => getMDXComponent(mdxSource), [mdxSource])

  return <MDXLayout layout={layout} components={MDXComponents} {...rest} />
}

在希望接受布局名称以映射到所需布局的页面上使用 MDXLayoutRenderer 组件。 你需要从布局文件夹传递布局名称(必须是完全匹配)。

分析

该模板现在支持 plausiblesimple analytics 和 google analytics。 使用与所需分析提供商对应的设置配置 siteMetadata.js

analytics: {
    // supports plausible, simpleAnalytics or googleAnalytics
    plausibleDataDomain: '', // e.g. tailwind-nextjs-starter-blog.vercel.app
    simpleAnalytics: false, // true or false
    googleAnalyticsId: '', // e.g. UA-000000-2 or G-XXXXXXX
  },

还支持自定义事件。你可以从 @components/analytics/[ANALYTICS-PROVIDER] 文件导入 logEvent 函数,并在触发感兴趣的事件时调用它。 注意:根据分析提供商的不同,可能需要额外的配置,请查看它们的官方文档获取更多信息。

博客评论系统

我们还添加了对 giscusutterances 或 disqus 的支持。 要启用,只需使用所需的提供商和配置文件中指定的设置配置 siteMetadata.js 的 comments 属性。

comment: {
    // Select a provider and use the environment variables associated to it
    // https://vercel.com/docs/environment-variables
    provider: 'giscus', // supported providers: giscus, utterances, disqus
    giscusConfig: {
      // Visit the link below, and follow the steps in the 'configuration' section
      // https://giscus.app/
      repo: process.env.NEXT_PUBLIC_GISCUS_REPO,
      repositoryId: process.env.NEXT_PUBLIC_GISCUS_REPOSITORY_ID,
      category: process.env.NEXT_PUBLIC_GISCUS_CATEGORY,
      categoryId: process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID,
      mapping: 'pathname', // supported options: pathname, url, title
      reactions: '1', // Emoji reactions: 1 = enable / 0 = disable
      // Send discussion metadata periodically to the parent window: 1 = enable / 0 = disable
      metadata: '0',
      // theme example: light, dark, dark_dimmed, dark_high_contrast
      // transparent_dark, preferred_color_scheme, custom
      theme: 'light',
      // theme when dark mode
      darkTheme: 'transparent_dark',
      // If the theme option above is set to 'custom`
      // please provide a link below to your custom theme css file.
      // example: https://giscus.app/themes/custom_example.css
      themeURL: '',
    },
    utterancesConfig: {
      // Visit the link below, and follow the steps in the 'configuration' section
      // https://utteranc.es/
      repo: process.env.NEXT_PUBLIC_UTTERANCES_REPO,
      issueTerm: '', // supported options: pathname, url, title
      label: '', // label (optional): Comment 💬
      // theme example: github-light, github-dark, preferred-color-scheme
      // github-dark-orange, icy-dark, dark-blue, photon-dark, boxy-light
      theme: '',
      // theme when dark mode
      darkTheme: '',
    },
    disqus: {
      // https://help.disqus.com/en/articles/1717111-what-s-a-shortname
      shortname: process.env.NEXT_PUBLIC_DISQUS_SHORTNAME,
    },
  },

多作者

作者信息现在从 siteMetadata.js 中分离出来,存储在单独的 data/authors 文件夹中作为 markdown 文件。至少,你需要有一个包含作者信息的 default.md 文件。你可以根据需要创建其他文件,文件名将用作作者的引用。

作者 markdown 文件可能如下所示:

default.md
---
name: Tails Azimuth
avatar: /static/images/avatar.png
occupation: Professor of Atmospheric Science
company: Stanford University
email: address@yoursite.com
twitter: https://twitter.com/Twitter
linkedin: https://www.linkedin.com
github: https://github.com
---

关于你自己的详细描述...

你可以在模板的多个地方使用这些信息。例如,在页面的关于部分,我们用这行代码获取默认作者信息:

const authorDetails = await getFileBySlug('authors', ['default'])

这在 AuthorLayout 模板中渲染。

博客文章中的多作者

博客文章的 frontmatter 接受一个可选的 authors 数组字段。如果未指定该字段,则假定使用默认作者。只需传入一个作者数组即可渲染与文章关联的多个作者。

例如,以下 frontmatter 将显示由 data/authors/default.mddata/authors/sparrowhawk.md 给出的作者

title: 'My first post'
date: '2021-01-12'
draft: false
summary: 'My first post'
authors: ['default', 'sparrowhawk']

多作者文章的演示显示在介绍 Tailwind Nextjs 入门博客文章中。

代码块复制按钮

将鼠标悬停在代码块上,你会注意到一个受 GitHub 启发的复制按钮!你可以修改 ./components/Pre.js 以进一步自定义它。 该组件被传递给 MDXComponents 并修改所有 <pre> 块。

行高亮和行号

感谢新的 rehype-prism-plus 插件,现在开箱即用地支持行高亮和行号

以下 javascript 代码块:

```js {1, 3-4} showLineNumbers
var num1, num2, sum
num1 = prompt('Enter first number')
num2 = prompt('Enter second number')
sum = parseInt(num1) + parseInt(num2) // "+" means "add"
alert('Sum = ' + sum) // "+" means combine into a string
```

将显示为:

var num1, num2, sum
num1 = prompt('Enter first number')
num2 = prompt('Enter second number')
sum = parseInt(num1) + parseInt(num2) // "+" means "add"
alert('Sum = ' + sum) // "+" means combine into a string

要修改样式,请更改 prism.css 文件中的以下类选择器:

.code-highlight {
  @apply float-left min-w-full;
}

.code-line {
  @apply -mx-4 block border-l-4 border-opacity-0 pl-4 pr-4;
}

.code-line.inserted {
  @apply bg-green-500 bg-opacity-20;
}

.code-line.deleted {
  @apply bg-red-500 bg-opacity-20;
}

.highlight-line {
  @apply -mx-4 border-l-4 border-primary-500 bg-gray-700 bg-opacity-50;
}

.line-number::before {
  @apply -ml-2 mr-4 inline-block w-4 text-right text-gray-400;
  content: attr(line);
}

新闻通讯组件 (v1.1.3)

在 v1.1.3 中引入的新闻通讯组件为你提供了一种轻松建立受众的方式。它与以下提供商集成:

要使用它,请在配置文件中指定你正在使用的提供商,并将必要的环境变量添加到 .env 文件中。 有关所需变量的更多信息,请查看 .env.sample.

导出了两个组件,一个是默认的 NewsletterForm,另一个是 BlogNewsletterForm 组件,它也作为 MDX 组件传入, 可以在博客文章中使用:

<BlogNewsletterForm title="喜欢正在阅读的内容?" />
喜欢正在阅读的内容?

该组件依赖 nextjs 的 API 路由,这需要设置 nextjs 的服务器端实例, 并且与 100% 静态站点导出不兼容。用户应该自行托管或使用支持此功能的兼容平台,如 Vercel 或 Netlify。

静态站点兼容的替代方案是将新闻通讯组件中的路由替换为表单 API 端点提供商。

参考文献和引用 (v1.2.1)

rehype-citation 插件已添加到 v1.2.1 的 xdm 处理管道中。这允许你轻松格式化引用并从现有的 bibtex 或 CSL-json 文件中插入参考文献。

例如,以下 markdown 代码示例:

Standard citation [@Nash1950]
In-text citations e.g. @Nash1951
Multiple citations [see @Nash1950; @Nash1951, page 50]

**References:**

[^ref]

渲染为以下内容:

Standard citation (Nash, 1950)
In-text citations e.g. Nash (1951)
Multiple citations (see Nash, 1950, 1951, p. 50)

References:

Nash, J. (1950). Equilibrium points in n-person games. Proceedings of the National Academy of Sciences, 36(1), 48–49.
Nash, J. (1951). Non-cooperative games. Annals of Mathematics, 286–295.

参考文献将插入在文档末尾,但这可以通过在预期位置指定 [^Ref] 标签来覆盖。 该插件使用 APA 引用格式,但也支持以下 CSL:'apa'、'vancouver'、'harvard1'、'chicago'、'mla',或用户指定的 CSL 文件路径。

有关配置选项的更多信息,请参见 rehype-citation 自述文件

自托管字体 (v1.5.0)

Google 字体已被 Fontsource 的自托管字体替换。这带来了以下优势

自托管带来了显著的性能提升,因为从托管服务(如 Google Fonts)加载字体会导致额外的(渲染阻塞)网络请求。为了提供参考,对于简单的网站,视觉加载时间已看到翻倍。

字体保持版本锁定。Google 经常在没有通知的情况下推送字体更新,这可能会干扰你的在线生产项目。像管理任何其他 NPM 依赖项一样管理你的字体。

致力于隐私。Google 确实会跟踪其字体的使用情况,对于极度关注隐私的人来说,自托管是一种替代方案。

这导致字体包更小,加载时间快 0.1s(webpagetest 对比)。

要更改默认的 Inter 字体:

  1. 安装首选的字体 - npm install -save @fontsource/<font-name>
  2. 更新 pages/_app.js 中的导入 - import '@fontsource/<font-name>.css'
  3. 更新 tailwind css 配置文件中的 fontfamily 属性

升级指南

从 v0 到 v1,代码中有大量部分已更改,包括对布局的支持和新的 mdx 引擎。

如果之前的版本满足你的需求,也没有真正的理由去更改,将你感兴趣的组件更改复制到你现有的博客可能比迁移所有内容更容易。

尽管如此,如果你想这样做且没有更改太多模板,你可以克隆新版本并将博客文章复制到新模板中。

另一种选择是使用以下代码拉取最新的模板版本:

git remote add template git@github.com:timlrx/tailwind-nextjs-starter-blog.git
git pull template v1 --allow-unrelated-histories
rm -rf node_modules

你可以在我的个人博客的这个提交中看到这样的迁移示例。

v1 还使用 feed.xml 而不是 index.xml,以避免与 Vercel 的一些构建问题。如果你正在迁移,你应该像这样向 next.config.js 添加重定向:

async redirects() {
  return [
    {
      source: '/:path/index.xml',
      destination: '/:path/feed.xml',
      permanent: true,
    }
  ]
}

Footnotes

  1. 随着 Nextjs 12 的新变化,首次加载的 JS 增加到 45kB。