Создавайте статические сайты Next.js быстрее, используя MDX и Contentlayer

Создавайте статические сайты Next.js быстрее, используя MDX и Contentlayer

13 февраля 2022 г.

TL;DR

TL;DR


  • 💨 Contentlayer reduces a lot of friction in publishing the content on my static website.
  • 💨 Contentlayer уменьшает много трений при публикации контента на моем статическом веб-сайте.

  • 😍 MDX with remark and rehype plugins is awesomely convenient and powerful.
  • 😍 MDX с плагинами замечаний и репостов невероятно удобен и мощен.

  • 🍵 Next.js jells very well with Contentlayer and MDX
  • 🍵 Next.js очень хорошо сочетается с Contentlayer и MDX

I fully embraced Static Site Generation (SSG) for my website to optimize the site speed and scaling in the future.

Я полностью принял Создание статических сайтов (SSG) для моего веб-сайта, чтобы оптимизировать скорость и масштабирование сайта в будущем.


Recently I’ve been researching on reducing the effort to create a new article on my website. There were many touch points in my Next.js project setup in order to:

Недавно я исследовал, как уменьшить усилия по созданию новой статьи на моем веб-сайте. В настройке моего проекта Next.js было много точек соприкосновения, чтобы:


  • Publish a new article
  • Опубликовать новую статью

  • Estimate reading time
  • Расчетное время чтения


  • Create a new RSS feed
  • Создать новый RSS-канал

  • Update the sitemap
  • Обновить карту сайта

What Was The Problem?

В чем была проблема?


I analyzed a little more and found out the friction was in my MDX usage. My file structure looked like this:

Я проанализировал еще немного и обнаружил, что проблема заключалась в использовании MDX. Моя файловая структура выглядела так:


```bash

``` ударить


my-blog

мой блог


├── public

├── общедоступный


├── data

├── данные


│ └── blogs.json

│ └── blogs.json


├── components

├── компоненты


│ └── Blog.tsx

│ └── Blog.tsx


└── pages

└── страницы


├── blogs

├── блоги


│   ├── blog-one.mdx

│ ├── blog-one.mdx


│   ├── blog-two.mdx

│ ├── blog-two.mdx


│   └── blog-three.mdx

│ └── blog-three.mdx


└── index.tsx

└── index.tsx


It is the standard setup recommended by Next.js. I was using @mdx-js/loader and @next/mdx to transform MDX into pages.

Это стандартная установка, рекомендованная Next.js. Я использовал @mdx-js/loader и @next/mdx, чтобы преобразовать MDX в страницы.


Take pages/blogs/blog-one.mdx for example, the content looked like this:

Возьмем, к примеру, страницы/блоги/blog-one.mdx. Содержание выглядело так:


pages/blogs/blog-one.mdx

страницы/блоги/blog-one.mdx


```javascript

```javascript


import Blog from '../../components/Blog'

импортировать блог из '../../components/Blog'


export const meta = {

экспортировать константу мета = {


title: 'Blog One🚀',

title: 'Первый блог🚀',


publishedAt: 'February 4, 2022'

опубликовано: «4 февраля 2022 г.»


description: "Learn how to build a Next.js blog with MDX and Contentlayer!",

description: "Узнайте, как создать блог Next.js с помощью MDX и Contentlayer!",


cover: '/optimized/articles/blog-one/hero.webp',

обложка: '/optimized/articles/blog-one/hero.webp',


export default ({ children }) => (

экспорт по умолчанию ({ дочерние элементы }) => (


<Blog

<Блог


title={meta.title}

название = {мета.название}


description={meta.description}

описание={мета.описание}


cover={meta.cover}

обложка = {мета.обложка}


publishedAt={meta.publishedAt}

publishAt={meta.publishedAt}


{children}

{дети}



Hey There👋

Привет👋


Welcome to Blog one✨ Let's learn together!

Добро пожаловать в Blog one✨ Давайте учиться вместе!


blog-one.mdx named-exported a meta data. It was picked up by the the default component that took care of the layout and rendered the meta data.

blog-one.mdx экспортировал метаданные с именем. Он был подобран компонентом по умолчанию, который заботился о макете и отображал метаданные.


The <Blog /> component looked like this:

Компонент <Blog /> выглядел следующим образом:


components/Blog.tsx

компоненты/блог.tsx


```typescript

```машинопись


import { BlogProps } from './types'

импортировать { BlogProps } из './types'


export default function Blog(props: BlogProps) {

функция экспорта блога по умолчанию (реквизит: BlogProps) {


return (

возвращение (


<article>

<статья>


  <h1>{props.title}</h1>

{реквизит.название}


  <h2>{props.description}</h2>

{props.description}


  <p>

<р>


    {props.publishedAt}

{реквизит.publishedAt}


  </p>


  <img alt={props.title} src={props.cover} width="100%" loading="lazy" />

{props.title}


  {props.children}

{реквизиты.дети}


</article>

)

I was treating MDX files as pages.

Я рассматривал файлы MDX как страницы.


Because the meta data in each MDX file was trapped in the page, I duplicated all the meta data and aggregated them in data/blogs.json. I used it to maintain the list of articles on my website, the RSS feed, and the sitemap for SEO.

Поскольку метаданные в каждом файле MDX были перехвачены на странице, я продублировал все метаданные и объединил их в data/blogs.json. Я использовал его для ведения списка статей на своем веб-сайте, RSS-канала и карты сайта для SEO.


It would be much better if I could treat the MDX files as data, and generate pages based on the data.

Было бы намного лучше, если бы я мог обрабатывать файлы MDX как данные и генерировать страницы на основе этих данных.


This way, I could use the MDX files as data points and page content at the same time. Publishing a new article ideally could be much more frictionless.

Таким образом я мог одновременно использовать файлы MDX в качестве точек данных и содержимого страницы. Публикация новой статьи в идеале могла бы быть намного проще.


I came across Lee Robinson’s website and found out he was using a alpha library called Contentlayer to solve the problem.

Я наткнулся на веб-сайт Ли Робинсона и узнал, что он использует альфа-библиотеку под названием Contentlayer для решения проблемы.


What is Contentlayer

Что такое Contentlayer


Contentlayer is an library in its early stage that turns content into data. It works roughly like this:

Contentlayer – это библиотека на ранней стадии, которая превращает контент в данные. Это работает примерно так:


  • It takes in headless CMS or local content in YAML, JSON, MDX, or Markdown as source.
  • В качестве источника используется безголовая CMS или локальный контент в форматах YAML, JSON, MDX или Markdown.

  • It transforms the content into TypeScript types and data files in JSON that includes the original content, meta data, and any derived data we specified.
  • Он преобразует содержимое в типы TypeScript и файлы данных в формате JSON, включая исходное содержимое, метаданные и любые указанные нами производные данные.

  • It aggregates all the data in JSON and exports them as ESM.
  • Он собирает все данные в JSON и экспортирует их как ESM.

\

For my use case, I can use the aggregated data generated by Contentlayer to replace my previous manual process:

В моем случае я могу использовать агрегированные данные, сгенерированные Contentlayer, чтобы заменить мой предыдущий ручной процесс:


  • I use the generated data to build the new page for an article.
  • Я использую сгенерированные данные для создания новой страницы статьи.

  • Я использую сгенерированные данные для отображения списка статей.

  • I use the generated data to create a new RSS feed.
  • Я использую сгенерированные данные для создания нового RSS-канала.

  • I use the new file structure to generate a new sitemap.
  • Я использую новую файловую структуру для создания новой карты сайта.

  • All automatic!
  • Все автомат!

Contentlayer offers easy integration with Next.js. I’ll show you how in the next sections.

Contentlayer предлагает простую интеграцию с Next.js. Я покажу вам, как в следующих разделах.


Using MDX as Data

Использование MDX в качестве данных


Let’s first explore how to use MDX as a data point.

Давайте сначала рассмотрим, как использовать MDX в качестве точки данных.


MDX offers YAML frontmatter support with custom parsers. You can express the meta data like this:

MDX предлагает передний план YAML поддержку с пользовательскими анализаторами. Вы можете выразить метаданные следующим образом:


```yaml

``ямл


title: 'Blog One🚀'

title: 'Первый блог🚀'


publishedAt: 'February 4, 2022'

опубликовано: «4 февраля 2022 г.»


description: 'Learn how to build a Next.js blog with MDX and Contentlayer!'

description: «Узнайте, как создать блог Next.js с помощью MDX и Contentlayer!»


cover: '/optimized/articles/blog-one/hero.webp'

обложка: '/optimized/articles/blog-one/hero.webp'


Hey There👋

Привет👋


Welcome to Blog One✨ Let's learn together!

Добро пожаловать в Blog One✨ Давайте учиться вместе!


You can see the meta data in YAML syntax is inside the --- block, and the body of the content follows in MDX syntax. Compared to the old setup where MDX files were treated as pages, the new MDX file contains only meta data and content.

Вы можете видеть, что метаданные в синтаксисе YAML находятся внутри блока ---, а основная часть содержимого следует в синтаксисе MDX. По сравнению с старой установкой, где файлы MDX обрабатывались как страницы, новый файл MDX содержит только метаданные и контент.


The next thing we need to do is to generate the blog page that renders the meta data and the content with the layout from <Blog /> component.

Следующее, что нам нужно сделать, это создать страницу блога, которая отображает метаданные и контент с макетом из компонента <Blog />.


Integrating Contentlayer in Next.js

Интеграция Contentlayer в Next.js


Now that we updated the MDX files to contain only data and content, Let’s move them into the data directory.

Теперь, когда мы обновили файлы MDX, чтобы они содержали только данные и контент, давайте переместим их в каталог data.


The new file structure looks like this:

Новая файловая структура выглядит так:


```bash

``` ударить


my-blog

мой блог


├── public

├── общедоступный


├── components

├── компоненты


│ └── Blog.tsx

│ └── Blog.tsx


├── pages

├── страницы


│ ├── blogs

│ ├── блоги


│ │ └── [slug].tsx

│ │ └── [slug].tsx


│ └── index.tsx

│ └── index.tsx


└── data

└── данные


└──blogs

└──блоги


   ├── blog-one.mdx

├── blog-one.mdx


   ├── blog-two.mdx

├── blog-two.mdx


   └── blog-three.mdx

└── blog-three.mdx


Notice that we replaced the MDX files in pages/blogs directory with a dynamic route [slug].tsx. We'll use this page to statically generate the blog pages later.

Обратите внимание, что мы заменили файлы MDX в каталоге pages/blogs динамическим маршрутом [slug].tsx. Мы будем использовать эту страницу для статического создания страниц блога позже.


Configuring Contentlayer

Настройка слоя содержимого


Contentlayer offers seamless integration with Next.js.

Contentlayer предлагает бесшовную интеграцию с Next.js.


To install the dependencies:

Чтобы установить зависимости:


```bash

``` ударить


yarn add contentlayer next-contentlayer

пряжа добавить слой содержимого следующий слой содержимого


Contentlayer reads the configuration from contentlayer.config.ts. Let's create one.

Contentlayer считывает конфигурацию из contentlayer.config.ts. Давайте создадим его.


```bash

``` ударить


touch contentlayer.config.ts

коснитесь contentlayer.config.ts


Inside the contentlayer.config.ts, we need to add instructions to tell Contentlayer how to parse:

Внутри `contentlayer.config.ts нам нужно добавить инструкции, чтобы сообщить Contentlayer, как выполнять синтаксический анализ:


  • name: namespace
  • имя: пространство имен

  • filePathPattern: input files
  • filePathPattern: входные файлы

  • bodyType: content body type for parsing
  • bodyType: тип тела контента для разбора

  • fields: meta data fields
  • поля: поля метаданных

  • computedFields: derived meta data fields
  • computedFields: производные поля метаданных

contentlayer.config.ts

contentlayer.config.ts


```typescript

```машинопись


import { defineDocumentType, makeSource } from 'contentlayer/source-files'

импортировать {defineDocumentType, makeSource} из 'contentlayer/source-files'


import readingTime from 'reading-time'

импортировать время чтения из «времени чтения»


export const Blog = defineDocumentType(() => ({

экспортировать const Blog = определитьDocumentType(() => ({


name: 'Blog',

имя: 'Блог',


filePathPattern: 'blogs/*.mdx',

filePathPattern: 'блоги/*.mdx',


bodyType: 'mdx',

тип тела: 'mdx',


fields: {

поля: {


title: { type: 'string', required: true },

title: {тип: 'строка', обязательный: true},


publishedAt: { type: 'string', required: true },

publishAt: {тип: 'строка', обязательный: true},


description: { type: 'string', required: true },

описание: { тип: 'строка', обязательно: правда},


cover: { type: 'string', required: true },

обложка: {тип: 'строка', обязательно: истина},


},

computedFields: {

вычисленные поля: {


readingTime: { type: 'json', resolve: (doc) => readingTime(doc.body.raw) },

readTime: {тип: 'json', разрешение: (doc) => readTime(doc.body.raw)},


slug: {

слаг: {


  type: 'string',

тип: 'строка',


  resolve: (doc) => doc._raw.sourceFileName.replace(/\.mdx/, ''),

разрешить: (doc) => doc._raw.sourceFileName.replace(/.mdx/, ''),


},

},

export default makeSource({

экспортировать по умолчанию makeSource({


contentDirPath: 'data',

contentDirPath: 'данные',


documentTypes: [Blog],

Типы документов: [Блог],


mdx: {

мдкс: {


remarkPlugins: [],

примечание Плагины: [],


rehypePlugins: [],

rehypePlugins: [],


},

In the computedFields, we can compute data like readingTime from the content body🤩. I'm using reading-time for calculating the reading time based on word count. The slug field is for generating the dynamic route later in the [slug].tsx page.

В computedFields мы можем вычислять данные, такие как readingTime, из тела контента🤩. Я использую reading-time для расчета времени чтения на основе количества слов. Поле `slug предназначено для создания динамического маршрута позже на странице [slug].tsx .


Under the hood, Contentlayer uses mdx-bundler to parse MDX and YAML frontmatter and extract the content and data. If you're interested in the magic behind it, you can read more about gray-matter and remark-mdx-frontmatter. These are the libraries mdx-bundler uses internally.

Под капотом Contentlayer используется mdx-bundler для разбора MDX и YAML и извлечения содержимого и данных. Если вас интересует магия, стоящая за этим, вы можете прочитать больше о сером веществе и remark-mdx-frontmatter. Это библиотеки, которые mdx-bundler использует для внутреннего использования.


At the end of the configuration, makeSource will then look for files that match blogs/*.mdxpattern under data directory and generate the blog data in .contentlayer directory at your project root.

В конце настройки makeSource будет искать файлы, соответствующие шаблону blogs/*.mdx, в каталоге data и создавать данные блога в каталоге .contentlayer в корне вашего проекта.


Lastly, wrap your Next.js configuration with next-contentlayer to integrate with Next.js's live-reload and build process.

Наконец, оберните свою конфигурацию Next.js с помощью next-contentlayer, чтобы интегрировать ее с процессом динамической перезагрузки и сборки Next.js.


next.config.js

следующий.config.js


```javascript

```javascript


const { withContentlayer } = require('next-contentlayer')

const { withContentlayer } = требуется ('следующий слой содержимого')


module.exports = withContentlayer()({

module.exports = withContentlayer()({


// ... your Next.js config

// ... ваша конфигурация Next.js


Using Contentlayer data for Static Site Generation

Использование данных Contentlayer для создания статического сайта


We are ready to use the generated data from Contentlayer and build the static pages🤩

Мы готовы использовать сгенерированные данные из Contentlayer и строить статические страницы🤩


All we need to do is to use allBlogs from .contentlayer/data to build the dynamic routes with getStaticPaths and use getStaticProps to pass the blog data to the [slug].tsx page.

Все, что нам нужно сделать, это использовать allBlogs из .contentlayer/data для построения динамических маршрутов с помощью getStaticPaths и использовать getStaticProps для передачи данных блога на страницу [slug].tsx.


pages/blogs/[slug].tsx

страницы/блоги/[slug].tsx


```typescript

```машинопись


import { useMDXComponent } from 'next-contentlayer/hooks'

import { useMDXComponent } из 'следующего слоя содержимого/хуков'


import { allBlogs } from '.contentlayer/data'

импортировать { allBlogs } из '.contentlayer/data'


import type { Blog } from '.contentlayer/types'

тип импорта {Блог} из '.contentlayer/types'


import BlogLayout from '../../../components/Blog'

импортировать BlogLayout из '../../../components/Blog'


type BlogProps = {

введите BlogProps = {


blog: Blog

блог: Блог


export default function Blog({ blog }: BlogProps) {

функция экспорта по умолчанию Blog({ blog }: BlogProps) {


const Component = useMDXComponent(post.body.code)

const Component = useMDXComponent(post.body.code)


return (

возвращение (


<BlogLayout {...blog}>


  <Component />

<Компонент/>


</BlogLayout>


)

export async function getStaticPaths() {

экспортировать асинхронную функцию getStaticPaths() {


return {

возвращение {


paths: allBlogs.map((blog) => ({ params: { slug: blog.slug } })),

пути: allBlogs.map((blog) => ({ params: {slug: blog.slug } })),


fallback: false,

запасной вариант: ложь,


}

export async function getStaticProps({ params }) {

экспортировать асинхронную функцию getStaticProps ({ params }) {


const blog = allBlogs.find((blog) => blog.slug === params.slug)

const blog = allBlogs.find((blog) => blog.slug === params.slug)


return { props: { blog } }

вернуть {реквизит: {блог}}


After the project is built, you’ll see the blogs available at /blogs/blog-one/blogs/blog-two, and /blogs/blog-three

После создания проекта вы увидите блоги, доступные в /blogs/blog-one, /blogs/blog-two и /blogs/blog-three


Bonus: remark & rehype Plugins

Бонус: плагины для комментариев и рехайпов


There are a lot more we can do with MDX by leveraging remark and rehype plugins in the contentlayer.config.ts.

С помощью многомерных выражений мы можем сделать гораздо больше, используя плагины для комментариев и рехайпов в файле contentlayer.config.ts.


  • remark is an awesome plugin ecosystem that transforms markdown.
  • remark – потрясающая экосистема плагинов, преобразующая уценку.

  • rehype is another powerful plugin ecosystem that transforms HTML.
  • rehype – еще одна мощная экосистема плагинов, преобразующая HTML.

They are two separate ecosystems but we can convert remark to rehype and generate HTML markup. The transformation looks like this:

Это две отдельные экосистемы, но мы можем преобразовать замечание в рехайп и создать HTML-разметку. Трансформация выглядит так:


```javascript

```javascript


MDX ----> remark AST ------> rehype AST --------> HTML

MDX ----> примечание AST ------> повторное использование AST --------> HTML


parse            convert            stringify

преобразовать преобразовать в строку


Contentlayer takes care of the flow. All we need to do is add the plugins to provide instruction for the transformations. I’m using the following plugins:

Contentlayer заботится о потоке. Все, что нам нужно сделать, это добавить плагины, чтобы предоставить инструкции для преобразований. Я использую следующие плагины:



  • rehype-slug and rehype-autolink-headings to render heading links.
  • rehype-slug и rehype-autolink-headings для отображения ссылок заголовков.

  • rehype-prism-plus to render syntax highlighting in code blocks.
  • rehype-prism-plus для подсветки синтаксиса в блоках кода.

  • rehype-code-titles to render code block titles.
  • rehype-code-titles для отображения заголовков блоков кода.

  • rehype-accessible-emojis to provide accessibility to emojis.
  • rehype-accessible-emojis, чтобы обеспечить доступ к смайликам.

contentlayer.config.ts

contentlayer.config.ts


```typescript

```машинопись


  • import remarkGfm from 'remark-gfm'
  • импортировать commentGfm из 'remark-gfm'

  • import rehypeSlug from 'rehype-slug'
  • импортировать rehypeSlug из 'rehype-slug'

  • import rehypeAutolinkHeadings from 'rehype-autolink-headings'
  • импортировать rehypeAutolinkHeadings из 'rehype-autolink-headings'

  • import rehypeCodeTitles from 'rehype-code-titles'
  • импортировать rehypeCodeTitles из 'rehype-code-titles'

  • import rehypePrism from 'rehype-prism-plus'
  • импортировать rehypePrism из 'rehype-prism-plus'

  • import { rehypeAccessibleEmojis } from 'rehype-accessible-emojis'
  • импортировать { rehypeAccessibleEmojis } из 'rehype-accessible-emojis'

// ...

export default makeSource({

экспортировать по умолчанию makeSource({


mdx: {

мдкс: {


  • remarkPlugins: [],
  • примечание Плагины: [],

  • remarkPlugins: [remarkGfm],
  • примечание Плагины: [remarkGfm],

  • rehypePlugins: [],
  • rehypePlugins: [],

  • rehypePlugins: [
  • rehypePlugins: [

  • rehypeSlug,
  • рехайпСлаг,

  • rehypeCodeTitles,
  • rehypeCodeTitles,

  • rehypePrism,
  • рехайпПризма,

  • rehypeAutolinkHeadings,
  • рехайпАвтоссылкаЗаголовки,

  • rehypeAccessibleEmojis,
  • рехайпAccessibleEmojis,

],

},

Contentlayer Applications

Приложения уровня содержимого


There are more things we can do with the data.

Есть еще вещи, которые мы можем сделать с данными.


Application #1: RSS Feed

Приложение №1: RSS-канал


I can now write a script to generate an RSS feed base on the allBlogs data!

Теперь я могу написать скрипт для создания базы RSS-каналов на основе данных allBlogs!


scripts/rss.mjs

скрипты/rss.mjs


```javascript

```javascript


import { writeFileSync } from 'fs'

импортировать {writeFileSync} из 'fs'


import RSS from 'rss'

импортировать RSS из 'rss'


import { allBlogs } from '.contentlayer/data'

импортировать { allBlogs } из '.contentlayer/data'


const feed = new RSS({

постоянная лента = новый RSS({


title: "My Blogs",

title: "Мои блоги",


feed_url: 'localhost:3000/rss.xml',

feed_url: 'локальный: 3000/rss.xml',


site_url: 'localhost:3000',

site_url: 'локальный: 3000',


allBlogs.map((blog) => ({

allBlogs.map((блог) => ({


title: blog.title,

название: блог.название,


description: blog.description,

описание: описание блога,


url: localhost:3000/blogs/${blog.slug}

URL: localhost:3000/blogs/${blog.slug}


date: blog.publishedAt,

дата: blog.publishedAt,


})).forEach((item) => {

})).forEach((элемент) => {


feed.item(item)

feed.item(элемент)


writeFileSync('./public/rss.xml', feed.xml({ indent: true }))

writeFileSync('./public/rss.xml', feed.xml({отступ: true}))


Application #2: XML Sitemap

Приложение № 2: XML Sitemap


It’s easier to write a script for sitemap generation. All we need is the file structure in the data and page directories.

Проще написать скрипт для генерации карты сайта. Все, что нам нужно, — это файловая структура в каталогах data и page.


scripts/sitemap.mjs

скрипты/карта сайта.mjs


```javascript

```javascript


import { writeFileSync } from 'fs'

импортировать {writeFileSync} из 'fs'


import { globby } from 'globby'

импортировать {globby} из 'globby'


import prettier from 'prettier'

импортировать красивее из 'красивее'


const pages = await globby([

константные страницы = ожидание globby([


'pages/*.tsx',

'страницы/*.tsx',


'data/*/.mdx',

'данные/*/.mdx',


'!pages/_*.tsx',

'!страницы/_*.tsx',


const urlTags = pages

const urlTags = страницы


.map((file) =>

.map((файл) =>


file

файл


  .replace('pages', '')

.заменить('страницы', '')


  .replace('data/content', '')

.replace('данные/контент', '')


  .replace('.tsx', '')

.заменить('.tsx', '')


  .replace('.mdx', '')

.replace('.mdx', '')


)

.map((path) => (path === '/index' ? '/' : path))

.map((путь) => (путь === '/index' ? '/' : путь))


.map(

.карта(


(path) => `

(путь) => `


  <url>

<ссылка>


      <loc>localhost:3000${path}</loc>

localhost:3000${путь}


  </url>


`

)

.join('')

.присоединиться('')


const sitemap = `

константа карта сайта = `




  ${urlTags}

${urlTags}



const prettierConfig = await prettier.resolveConfig('./prettierrc')

const prettierConfig = await prettier.resolveConfig('./prettierrc')


const formatted = prettier.format(sitemap, {

const formatted = prettier.format (карта сайта, {


...prettierConfig,

...красивееКонфигурация,


parser: 'html',

парсер: 'html',


writeFileSync('public/sitemap.xml', formatted)

writeFileSync('public/sitemap.xml', отформатировано)


Run both scripts after building the project and automatically generate a new RSS feed and sitemap.

Запустите оба скрипта после создания проекта и автоматически сгенерируйте новый RSS-канал и карту сайта.


In package.json, add:

В package.json добавьте:


```json

```json


"scripts": {

"скрипты": {


  • "sitemap": "node scripts/sitemap.mjs",
  • "sitemap": "узловые скрипты/sitemap.mjs",

  • "rss": "node scripts/rss.mjs",
  • "rss": "узловые скрипты/rss.mjs",

  • "postbuild": "yarn sitemap && yarn rss",
  • "postbuild": "карта сайта пряжи && пряжа rss",

},

Final Thoughts

Последние мысли


Building Static sites with Next.js becomes so effortless with MDX and Contentlayer.

Создание статических сайтов с помощью Next.js становится таким простым благодаря многомерным выражениям и Contentlayer.


MDX combines with remark and rehype ecosystem enriches the possibility of building consistent pages with Markdown. Contentlayer makes data and content in MDX files available to consume in Next.js projects.

MDX сочетается с экосистемой замечаний, а повторная реклама расширяет возможности создания согласованных страниц с помощью Markdown. Contentlayer делает данные и содержимое в файлах MDX доступными для использования в проектах Next.js.


If you’re exploring ways to build your own static sites, check out the libraries mentioned earlier. It not only reduces the time to market but also is a lot of fun to build!🦄

Если вы изучаете способы создания собственных статических сайтов, ознакомьтесь с упомянутыми ранее библиотеками. Это не только сокращает время выхода на рынок, но и доставляет массу удовольствия!🦄


This article is originally posted on Daw-Chih’s website.

Первоначально эта статья была опубликована на веб-сайте Daw-Chih.



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE