Как создать блог разработчика с помощью Gatsby и MDX

разработчика с помощью Gatsby и MDX Программирование и разработка

Вы можете легко публиковать свои идеи на таких сайтах, как Dev.to, Hashnode или Medium, но в идеале вы должны иметь полный контроль над своим собственным контентом. Список инструментов для создания собственного веб-сайта и управления собственным контентом постоянно растет. В этом обширном руководстве я расскажу, как сделать ваш контент сияющим с помощью Gatsby, с добавленными навороченными функциями, которые вы получаете с такой экосистемой.

Изначально я использовал Jekyll для публикации своего блога, но затем перешел на Gatsby, используя шаблон Lumen. Я использую Gatsby с версии 0, примерно в мае 2017 года.

Я перейду от Hello, World!проекта Gatsby к блогу по кодированию с выделением синтаксиса кода и переключением тем для этого совершенства темного режима.

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

Почему Gatsby?

Gatsby — это генератор статических сайтов, поэтому при запросе страниц не происходит динамического создания страниц. Созданный вывод для сайта Gatsby может быть размещен в CDN, что делает его глобально доступным и супер масштабируемым.

Гэтсби может использовать файлы Markdown для создания страниц в проекте сайта. Гэтсби прочитает файлы Markdown в файловую систему Gatsby и преобразует Markdown в HTML, а затем при создании сайта создаст статические страницы.

Читайте также:  Как получить значения переменных запроса в Flask?

Конечным результатом является сверхбыстрый сайт с небольшой задержкой при запросе страниц.

Markdown и многомерные выражения

Я документирую свой путь разработки с 2016 года в Markdown. Markdown предлагает способ включения простого редактирования в текстовых файлах, которые можно преобразовать в HTML.

MDX (или Markdown JSX) — это инструмент, который позволяет вам писать JSX в ваших документах Markdown, примерно так:

import { RainbowText } from './components/rainbow';
## A Markdown Heading
<RainbowText>Wheeeeeeee</RainbowText>

Gatsby — безусловно, лучший фреймворк, который я использовал для работы с Markdown и MDX, так как выше не требуется специальных обозначений с использованием frontmatter в ваших сообщениях.

Что мне нужно?

Если вы собираетесь следовать по тексту, вам понадобится несколько вещей:

  • базовая настройка веб-разработки: узел, терминал (bash, zsh или fish)
  • текстовый редактор
  • базовое понимание React

Если у вас их нет, есть как StackBlitz, так и GitHub Codespaces, где вы можете создать пустой репозиторий GitHub и начать работу со средой разработки оттуда.

В примерах ниже я буду использовать VS Code в качестве текстового редактора и Yarn в качестве предпочтительного менеджера пакетов. Если вы предпочитаете npm, это круто. 👍

Hello, World!

Пришло время раскрутить проект Гэтсби. Я собираюсь сделать большую часть этого из командной строки для начала:

# create the project directory
mkdir my-gatsby-blog
# change into the directory
cd my-gatsby-blog
# initialise a package.json file
yarn init -y
# initialise the git repo
git init

Прохладный. Теперь, прежде чем что-либо делать с этим, мне нужно добавить.gitignoreфайл перед установкой любых модулей npm:

# create .gitignore file in my directory
touch .gitignore
# add ignore contents with echo
echo "# Project dependencies
.cache
node_modules

# Build directory
public

# Other
.DS_Store
yarn-error.log" > .gitignore

Теперь я могу установить все необходимое для npm без того, чтобы VS Code Git кричал мне о слишком большом количестве активных изменений. Теперь давайте установим некоторые зависимости, чтобы начать работу с Gatsby:

yarn add gatsby react react-dom
# -p is to create parent directories too if needed
mkdir -p src/pages
# create the index (home) page
touch src/pages/index.js

Затем мы добавим в проект первый компонент React (из многих). Я добавлю в index.jsсозданный мной файл следующее:

import React from "react";

export default function IndexPage() {
  return <h1>Hello, World!</h1>;
}

Теперь я готов запустить команду Gatsby developиз командной строки:

# if you're using npm 👇
# $(npm bin)/gatsby develop
yarn gatsby develop

Это запустит сервер разработчиков Gatsby и скажет, что мой проект доступен для просмотра в браузере на порту 8000 (порт Gatsby по умолчанию). URL-адрес — http: // localhost: 8000 /.

Использование двоичных команд Gatsby непосредственно из интерфейса командной строки (CLI) вполне выполнимо, но большинство людей добавят доступные команды в scriptsраздел package.jsonфайла, например:

"scripts": {
  "build": "gatsby build",
  "dev": "gatsby develop",
  "serve": "gatsby serve",
  "clean": "gatsby clean"
},

В качестве дополнительного бонуса здесь есть несколько дополнений, которые можно добавить к скриптам Гэтсби.

Если мы не хотим запускать проект на одном и том же порту каждый раз, его можно изменить с помощью -pфлага и порта, указанного после этого. Например, gatsby develop -p 8945.

Если мы хотим открыть вкладку браузера после того, как проект будет готов, мы можем добавить -oего в скрипт.

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

"scripts": {
  "build": "gatsby build",
  "dev": "gatsby develop -p 8945 -o",
  "serve": "gatsby serve -p 9854 -o",
  "clean": "gatsby clean"
},

И при этом обязательное «Hello, World!» приветствие завершено, и я могу перейти к остальной части этого сообщения! 🤓

Наконец, я зафиксирую сделанные мной изменения:

# add everything for committing
git add .
# commit to repo
git commit -m 'init project'

Контент для блога

Хорошо, сейчас с проектом ничего не происходит, поэтому сначала я добавлю немного контента из командной строки:

# this creates the folders in the root of the project
mkdir -p content/2021/03/{06/hello-world,07/second-post,08/third-post}
# create individual files
touch content/2021/03/06/hello-world/index.mdx
touch content/2021/03/07/second-post/index.mdx
touch content/2021/03/08/third-post/index.mdx

Я буду использовать их во всех примерах, которые я делаю.

Вы заметите расширение файла.mdx. Это файл MDX.

Лицевая сторона

Прежде чем добавить контент для блога, мне нужно поговорить о главном.

Фронтальный материал — это способ хранения информации о файле, который может использоваться Гэтсби при построении страниц из них. А пока я добавлю titleчасть сообщения и файл date. Я также добавлю к ним некоторый контент. Вот наш первый пост:

---
title: Hello World - from mdx!
date: 2021-03-06
---

My first post!!

## h2 Heading

Some meaningful prose

### h3 Heading

Some other meaningful prose

Вот наш второй пост:

---
title: Second Post!
date: 2021-03-07
---

This is my second post!

Третий пост:

---
title: Third Post!
date: 2021-03-08
---

This is my third post!

> with a block quote!

And a code block:

```js
const wheeeeee = true;
```

На этом пока что с публикациями, потому что эти сообщения еще не распознаются Гэтсби как страницы. Мне нужно сообщить Гэтсби, где найти контент для добавления в проект. Для этого я собираюсь добавить файл конфигурации в Gatsby.

Давайте зафиксируем изменения, которые я внес в Git:

# add changed file for committing
git add .
# commit to repo
git commit -m 'add markdown files'

Конфигурация Gatsby

Конфигурация Gatsby — это то, что используется для определения и настройки многих плагинов Gatsby, которые вы можете использовать. Подробнее об экосистеме плагинов Gatsby чуть позже. А пока я собираюсь создать файл снова в терминале:

touch gatsby-config.js

Это создает gatsby-config.jsв корне проекта, так что я могу начать настройку Gatsby для чтения.mdxфайлов, которые я создал ранее.

Плагины Gatsby

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

yarn add gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react gatsby-source-filesystem

Беглый взгляд на package.jsonтеперь показывает, что у меня установлена ​​следующая версия зависимостей:

"dependencies": {
  "@mdx-js/mdx": "^1.6.22",
  "@mdx-js/react": "^1.6.22",
  "gatsby": "^3.1.1",
  "gatsby-plugin-mdx": "^2.1.0",
  "gatsby-source-filesystem": "^3.1.0",
  "react": "^17.0.1",
  "react-dom": "^17.0.1"
},

Следует отметить, что в Gatsby нет необходимости импортировать React в ваши компоненты с помощью React 17. Но для полноты и во избежание путаницы я буду включать его в эти примеры.

Теперь мне нужно настроить gatsby-plugin-mdxи gatsby-plugin-mdx. В gatsby-config.jsфайл добавлю следующее:

module.exports = {
  plugins: [
    `gatsby-plugin-mdx`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content`,
        name: `content`,
      },
    },
  ],
};

Зафиксируйте изменения до сих пор:

git add .
git commit -m 'add gatsby plugins'

Gatsby GraphQL

Теперь пора посмотреть, где я нахожусь с файлами в Gatsby, используя клиент Gatsby GraphQL, GraphiQL. Если вы следите за инструкциями, вы могли заметить, что интерфейс командной строки указывает два URL-адреса для просмотра проекта:

You can now view my-gatsby-blog in the browser.
⠀
  http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  http://localhost:8000/___graphql

Я собираюсь использовать ___graphqlмаршрут (три символа подчеркивания), чтобы увидеть файлы в файловой системе.

Если это покажется немного пугающим, я попытаюсь охватить все части, которые могут показаться не имеющими особого смысла. Если вы следуете инструкциям, у вас должно получиться скопировать примеры в проводник GraphiQL.

Когда я открываю проводник GraphiQL, у меня появляется несколько панелей проводника. Это все доступные данные для изучения в проекте, которые зависят от того, что я настроил в gatsby-config.jsфайле.

GraphiQL панель запроса и результаты рядом с этим. Здесь я буду писать запросы GraphQL для получения нужных мне данных. Там также ЗАПРОС ПЕРЕМЕННОГО раздел в нижней части панели запроса, и я пойду на что в дальнейшем.

Справа находится обозреватель документации GraphQL. Из-за строгой типизации GraphQL это означает, что он может создавать собственную документацию по своим данным. Но это выходит за рамки этой публикации.

Запрос локальных файлов с помощью GraphQL

Затем я собираюсь запросить файлы, которые я добавил ранее в панель запросов GraphiQL. В этом запросе я запрашиваю заголовок и дату, определенные в шрифте файлов:

{
  allMdx {
    nodes {
      frontmatter {
        title
        date
      }
    }
  }
}

Если мы вставим это в панель запросов и нажмем большую кнопку воспроизведения, мы вернем некоторые данные в панель результатов. Мы также можем использовать проводник на левой панели, чтобы выбирать данные. Вот что я получаю после выполнения запроса:

{
  "data": {
    "allMdx": {
      "nodes": [
        {
          "frontmatter": {
            "title": "Hello World - from mdx!",
            "date": "2021-03-06T00:00:00.000Z"
          }
        },
        {
          "frontmatter": {
            "title": "Second Post!",
            "date": "2021-03-07T00:00:00.000Z"
          }
        },
        {
          "frontmatter": {
            "title": "Third Post!",
            "date": "2021-03-08T00:00:00.000Z"
          }
        }
      ]
    }
  },
  "extensions": {}
}

Это большой объект JSON с соответствующей информацией, которую мы запросили в запросе. Мы скоро посмотрим, как это использовать. На данный момент это означает, что мы можем использовать эти данные в проекте Gatsby для создания страниц.

Метаданные сайта

В gatsby-config.jsфайле также есть возможность указать метаданные сайта. Метаданные сайта нужны, когда я хочу повторно использовать общие данные, такие как название и описание сайта.

Это будет полезно в будущем, когда я захочу добавить на сайт метатеги для поисковой оптимизации (SEO). (Опять же, подробнее об этом позже.) А пока я собираюсь определить некоторую основную информацию о сайте в файле gatsby-config.jsс siteMetadataобъектом.

Я мог бы определить метаду сайта прямо module.exportsтак:

module.exports = {
  siteMetadata: {
    title: `My Gatsby Blog`,
    description: `This is my coding blog.`,
  },
  plugins: [
    // configured plugins here
    {
      // empty for brevity
    },
  ],
};

Объект метаданных сайта может стать немного большим, и я обнаружил, что сохранение его в отдельном объекте может немного упростить его рассуждение, поэтому вместо этого я собираюсь определить его отдельно:

const siteMetadata = {
  title: `My Gatsby Blog`,
  description: `This is my coding blog.`,
};

Затем добавьте siteMetadataобъект в файл конфигурации Gatsby:

const siteMetadata = {
  title: `My Gatsby Blog`,
  description: `This is my coding blog.`,
};

module.exports = {
  siteMetadata,
  plugins: [
    // configured plugins here
    {
      // empty for brevity
    },
  ],
};

Теперь я могу снова перейти в проводник GraphiQL и запросить метаданные этого сайта с помощью следующего запроса:

{
  site {
    siteMetadata {
      title
      description
    }
  }
}

Всегда рекомендуется останавливать и перезапускать сервер разработки, если вы вносите изменения в gatsby-config.jsфайл, поэтому я сделаю это ( Ctrl+ c, затем yarn develop), затем в проводнике GraphiQL обновлю страницу и снова запущу запрос, чтобы получить данные обратно:

{
  "data": {
    "site": {
      "siteMetadata": {
        "title": "My Gatsby Blog",
        "description": "This is my coding blog."
      }
    }
  },
  "extensions": {}
}

Сделайте крючок для метаданных сайта

Теперь, когда у меня есть метаданные сайта в файловой системе Gatsby, я могу запрашивать их везде, где я хочу их использовать, с помощью ловушки статических запросов Gatsby useStaticQuery. Я собираюсь убить сервер разработчика и перезапустить его после того, как добавлю в src/pages/index.jsфайл следующее:

import { graphql, useStaticQuery } from "gatsby";
import React from "react";

export default function IndexPage() {
  const {
    site: { siteMetadata },
  } = useStaticQuery(graphql`
    {
      site {
        siteMetadata {
          title
          description
        }
      }
    }
  `);
  console.log("=====================");
  console.log(siteMetadata);
  console.log("=====================");
  return <h1>Hello World!</h1>;
}

Небольшое примечание о некоторых обозначениях: const { site: { siteMetadata }, }это быстрый способ получить данные в siteзапросе, где я извлекаю siteMetadataиз siteобъекта. Это называется деструктуризацией.

Теперь, после того как я снова запустил сервер разработки, я могу перейти в консоль браузера ( Control+ Shift+ Jв Windows / Linux, Command+ Option+ Jв macOS) и увидеть siteMetadataобъект в выводе консоли.

Я получаю следующий вывод консоли:

=====================
{title: "My Gatsby Blog", description: "This is my coding blog."}
  description: "This is my coding blog."
  title: "My Gatsby Blog"
  __proto__: Object
=====================

Не беспокойтесь о предупреждении консоли об отсутствующей странице 404 not found ( net::ERR_ABORTED 404 (Not Found)). Я сделаю это позже.

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

# make a folder for all the hooks to live
mkdir src/hooks
# creathe the file
touch src/hooks/use-site-metadata.js

Теперь я добавлю ловушку к только что созданному src/hooks/use-site-metadata.jsфайлу, чтобы получать метаданные сайта по запросу:

import { graphql, useStaticQuery } from "gatsby";
export const useSiteMetadata = () => {
  const { site } = useStaticQuery(
    graphql`
      query SITE_METADATA_QUERY {
        site {
          siteMetadata {
            title
            description
          }
        }
      }
    `
  );
  return site.siteMetadata;
};

Возможно, вы заметили, что этот запрос отличается от запроса из проводника GraphiQL:

+ query SITE_METADATA_QUERY {
  site {
    siteMetadata {
      title
      description
    }
  }
}

Это имя для запроса. Поскольку в проекте я буду использовать много запросов, имеет смысл дать им осмысленные имена.

Теперь я добавлю новый хук в src/pages/index.jsфайл:

import React from "react";
import { useSiteMetadata } from "../hooks/use-site-metadata";

export default function IndexPage() {
  const { title, description } = useSiteMetadata();
  return (
    <>
      <h1>{title}</h1>
      <p>{description}</p>
    </>
  );
}

Это намного менее многословно, и я могу выбирать, какие элементы я хочу из списка SITE_METADATA_QUERY.

Пришло время сообщить о сделанных до сих пор изменениях:

git add .
git commit -m 'add site metadata and metadata hook'

Стилизация с помощью пользовательского интерфейса темы

Чтобы стилизовать этот проект, я собираюсь использовать пользовательский интерфейс темы из-за его скорости с реализацией макетов и функций, таких как темный режим. Я подробно опишу, что имеет отношение к тому, что я делаю, и причины этого, хотя это не будет руководством по использованию пользовательского интерфейса темы.

Есть несколько дополнительных зависимостей, которые нужно добавить для пользовательского интерфейса темы, а именно:

yarn add theme-ui gatsby-plugin-theme-ui @theme-ui/presets

После их установки мне нужно добавить gatsby-plugin-theme-uiв gatsby-config.jsмассив плагинов:

module.exports = {
  siteMetadata,
  plugins: [
    `gatsby-plugin-theme-ui`,
    `gatsby-plugin-mdx`,
    {
      resolve: `gatsby-source-filesystem`,
      // rest of the module unchanged

Теперь, если я остановлюсь и перезапущу сервер разработки, у меня будет немного другой вид сайта! Все стало немного посиневшим — точнее, барвинком! Это gatsby-plugin-theme-uiделает свое дело, и этот цвет установлен по умолчанию.

Плагин Gatsby для пользовательского интерфейса темы предлагает множество параметров конфигурации, о некоторых из которых я расскажу более подробно при необходимости. А пока я собираюсь создать папку и определить объект темы для пользовательского интерфейса темы:

# create the folder for the Theme UI theme
mkdir src/gatsby-plugin-theme-ui
# create the theme file
touch src/gatsby-plugin-theme-ui/index.js

В src/gatsby-plugin-theme-ui/index.jsфайле, я собираюсь добавить в пару пресетов Тема пользовательского интерфейса, определить тему, объект и распространение в swissпресет к theme, к theme colors, и к styles.

Для темного режима я использую deepпредустановку пользовательского интерфейса темы и распределяю ее по modesобъекту для dark. (Подробнее об этом скоро.) На данный момент знайте, что это позаботится о многих темах для меня:

import { deep, swiss } from "@theme-ui/presets";

const theme = {
  ...swiss,
  colors: {
    ...swiss.colors,
    modes: {
      dark: {
        ...deep.colors,
      },
    },
  },

  styles: {
    ...swiss.styles,
    p: {
      fontFamily: "body",
      fontWeight: "body",
      lineHeight: "body",
      fontSize: 3,
    },
  },
};

export default theme;

Теперь, если я перезапущу сервер разработки (опять же, да, вы научитесь с этим справляться), он будет выглядеть немного более приемлемым с примененной швейцарской темой. На момент написания UI темы иногда не обновлял localhostстраницу, поэтому необходимо обновить страницу браузера.

Зафиксируйте изменения в Git:

git add .
git commit -m 'add Theme UI and configure presets'

Пора добавить компоненты React!

Компонент компоновки

У Гэтсби нет конкретного макета, поэтому ответственность за него возлагается на разработчика. В данном случае я делаю макет всего сайта. Можно включить множество макетов для использования в проекте Gatsby, но в этом примере я буду использовать только один.

Теперь я собираюсь реорганизовать то, что у меня есть сейчас, чтобы все было обернуто Layoutкомпонентом. То, что я в настоящее время src/pages/index.jsмогут быть использованы для Headerкомпонента, так что я собираюсь сделать несколько файлов теперь Layoutи Header:

# create a components folder
mkdir src/components
# create Layout and Header files
touch src/components/header.js src/components/layout.js

Теперь переместим заголовок и описание src/pages/index.jsво вновь созданный src/components/header.jsкомпонент.

Вместо того, чтобы useSiteMetadataиспользовать в Headerкомпоненте, я передам useSiteMetadataнужные мне реквизиты в заголовок из Layoutкомпонента, где и будет жить заголовок. (Подробнее об этом чуть позже.) Во-первых, вот компонент заголовка, который находится в src/components/header.js:

import { Link as GatsbyLink } from "gatsby";
import React from "react";
import { Box, Heading, Link } from "theme-ui";

export const Header = ({ siteTitle, siteDescription }) => {
  return (
    <Box as="header" sx={{ bg: "highlight", mb: "1.45rem" }}>
      <Box
        as="div"
        sx={{
          m: "0 auto",
          maxWidth: "640px",
          p: "1.45rem 1.0875rem",
        }}
      >
        <Link as={GatsbyLink} to="/">
          <Heading>{siteTitle}</Heading>
        </Link>
        <Box as="p" variant="styles.p">
          {siteDescription}
        </Box>
      </Box>
    </Box>
  );
};

Я добавил несколько основных стилей, используя элементы макета пользовательского интерфейса темы. Это выглядит немного отличается от ранее: Box, Link, Heading… что? Это все компоненты пользовательского интерфейса темы, которые можно использовать для макетов, элементов форм и многого другого.

Вы можете заметить, что as={GatsbyLink}к Linkкомпоненту добавлена ​​ссылка. Это использует asопору в пользовательском интерфейсе темы и позволяет передаваемому компоненту использовать стили пользовательского интерфейса темы.

Есть отличный пост от Пола Скэнлона, в котором более подробно объясняется, как это делается в пользовательском интерфейсе темы. Для действительно исчерпывающего объяснения пользовательского интерфейса темы есть также » Общие сведения о пользовательском интерфейсе темы » того же автора.

Также есть sxи variantреквизиты из пользовательского интерфейса темы. sxпозволяет передавать компоненту дополнительные стили. Думайте об этом как об эквиваленте style={{}}опоры JSX. variantОпора позволяет группа предопределенных стилей, которые должна применяться от темы к используемому компоненту.

Теперь о Layoutкомпоненте, который находится в src/components/layout.js:

import React from "react";
import { Box } from "theme-ui";
import { useSiteMetadata } from "../hooks/use-site-metadata";
import { Header } from "./header";

export const Layout = ({ children }) => {
  const { title, description } = useSiteMetadata();
  return (
    <>
      <Header siteTitle={title} siteDescription={description} />
      <Box
        as="div"
        sx={{
          margin: "0 auto",
          maxWidth: "640px",
          padding: "0 1.0875rem 1.45rem",
        }}
      >
        <Box as="main">{children}</Box>
      </Box>
    </>
  );
};

Здесь я сохраняю useSiteMetadataкрючок и передаю реквизиты, необходимые Headerкомпоненту, снова с помощью sxреквизита, чтобы добавить некоторые базовые стили для выравнивания к основному, содержащему div. Затем я создаю mainоболочку для children.

childrenРеквизит ничего возвращать в Layoutкомпонент инкапсулирует, который будет включать в себя все, что я хочу, чтобы применить макет к. Например:

<Layout>
  <h1>This is wrapped</h1>
</Layout>

Это вернет все, что есть в Layoutкомпоненте, и то, что он упаковывает. В приведенном выше примере это в настоящее время будет заголовок и H1, обернутые Layoutкомпонентом.

В качестве примера я вернусь на страницу индекса ( src/pages.index.js) и добавлю следующее:

import React from "react";
import { Layout } from "../components/layout";

export default function IndexPage() {
  return (
    <>
      <Layout>
        <h1>This is wrapped</h1>
      </Layout>
    </>
  );
}

Результатом является заголовок, представленный в Layoutкомпоненте и H1 This is wrapped.

Запрос сообщений на индексной странице

Теперь пришло время получить сообщения, которые я создал в начале, и отобразить их на странице индекса в виде списка интерактивных ссылок.

Чтобы получить информацию о публикации, я воссоздаю запрос, который я сделал в разделе о запросах локальных файлов с помощью GraphQL, с парой дополнительных бит:

{
  allMdx(sort: { fields: [frontmatter___date], order: DESC }) {
    nodes {
      id
      slug
      excerpt(pruneLength: 250)
      frontmatter {
        title
        date(formatString: "YYYY MMMM Do")
      }
    }
  }
}

Я добавил в idузел и расширение slug. Это путь к.mdxфайлу.

Он excerptиспользует функцию Gatsby для получения первых 250 символов из тела сообщения, а также добавляет некоторое форматирование с dateпомощью другой встроенной функции Gatsby.

Тогда как способ заказать сообщения в хронологическом порядке убывания, я добавил вроде: allMdx(sort: { fields: [frontmatter___date], order: DESC }) {. Это сортировка по дате в материалах статьи.

Добавление этого в проводник GraphiQL дает мне такой результат:

{
  "data": {
    "allMdx": {
      "nodes": [
        {
          "id": "2bed526a-e5a9-5a00-b9c0-0e33beafdbcf",
          "slug": "2021/03/08/third-post/",
          "excerpt": "This is my third post! with a block quote! And a code block:",
          "frontmatter": {
            "title": "Third Post!",
            "date": "2021 March 8th"
          }
        },
        {
          "id": "89ea266b-c981-5d6e-87ef-aa529e98946e",
          "slug": "2021/03/07/second-post/",
          "excerpt": "This is my second post!",
          "frontmatter": {
            "title": "Second Post!",
            "date": "2021 March 7th"
          }
        },
        {
          "id": "75391ba1-3d6b-539f-86d2-d0e6b4104806",
          "slug": "2021/03/06/hello-world/",
          "excerpt": "My first post!! h2 Heading Some meaningful prose h3 Heading Some other meaningful prose",
          "frontmatter": {
            "title": "Hello World - from mdx!",
            "date": "2021 March 6th"
          }
        }
      ]
    }
  },
  "extensions": {}
}

Теперь я могу использовать этот запрос в src/pages/index.jsфайле, чтобы получить эти данные для использования на странице индекса. В IndexPageфункции я деструктурирую dataреквизиты, данные компоненту через запрос GraphQL:

import { graphql, Link as GatsbyLink } from "gatsby";
import React from "react";
import { Box, Heading, Link } from "theme-ui";
import { Layout } from "../components/layout";

export default function IndexPage({ data }) {
  return (
    <>
      <Layout>
        {data.allMdx.nodes.map(({ id, excerpt, frontmatter, slug }) => (
          <Box
            key={id}
            as="article"
            sx={{
              mb: 4,
              p: 3,
              boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
              border: "1px solid #d1d1d1",
              borderRadius: "15px",
            }}
          >
            <Link as={GatsbyLink} to={`/${slug}`}>
              <Heading>{frontmatter.title}</Heading>
              <Box as="p" variant="styles.p">
                {frontmatter.date}
              </Box>
              <Box as="p" variant="styles.p">
                {excerpt}
              </Box>
            </Link>
          </Box>
        ))}
      </Layout>
    </>
  );
}

export const query = graphql`
  query SITE_INDEX_QUERY {
    allMdx(sort: { fields: [frontmatter___date], order: DESC }) {
      nodes {
        id
        excerpt(pruneLength: 250)
        frontmatter {
          title
          date(formatString: "YYYY MMMM Do")
        }
        slug
      }
    }
  }
`;

При этом используются ранее описанные компоненты. Обратите внимание, что excerpt, frontmatterи в slugнастоящее время деструктурированный от data.allMdx.nodes:

{data.allMdx.nodes.map(({ excerpt, frontmatter, slug }) => (

При нажатии на ссылки я попадаю на страницу 404 разработки Gatsby.js. Это потому, что я еще не сделал страницы для.mxdфайлов. Это дальше.

Я передаю то, что сделал до сих пор, прежде чем двигаться дальше:

git add .
git commit -m 'add Header and Layout components'

Использование API маршрутизации файловой системы Gatsby с многомерными выражениями

Я собираюсь использовать API маршрутизации файловой системы Gatsby, чтобы получить пути к файлам сообщений, которые я создал ранее. API маршрутизации файловой системы — это способ программно создавать страницы из моих данных GraphQL.

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

# create the route api file
touch src/pages/{mdx.slug}.js

В этом файле я определю запрос GraphQL для данных, которые хочу включить в этот шаблон:

import { graphql } from "gatsby";
import { MDXRenderer } from "gatsby-plugin-mdx";
import React from "react";
import { Box } from "theme-ui";

export default function PostPage({ data }) {
  const {
    body,
    frontmatter: { title },
  } = data.mdx;
  return (
    <>
      <Box as="h1" variant="styles.h1" fontSize="4xl">
        {title}
      </Box>
      <MDXRenderer>{body}</MDXRenderer>
    </>
  );
}

export const query = graphql`
  query POST_BY_SLUG($slug: String) {
    mdx(slug: { eq: $slug }) {
      id
      slug
      body
      frontmatter {
        date
        title
      }
    }
  }
`;

Кода очень много, поэтому я его разобью. В основном это связано с запросом GraphQL:

query POST_BY_SLUG($slug: String) {
  mdx(slug: { eq: $slug }) {
    id
    slug
    body
    frontmatter {
      date
      title
    }
  }
}

Начало запроса принимает slugwith POST_BY_SLUG($slug: String), а основной узел — mdx, поэтому я использую mdx.slugкак имя файла {mdx.slug}.js.

Если я возьму этот запрос и вставлю его в свой проводник GraphiQL и нажму кнопку воспроизведения, я получу следующее:

{
  "data": {
    "mdx": null
  },
  "extensions": {}
}

Это потому, что $slugв проводнике GraphiQL нет переменной, определенной для. Если вы посмотрите в нижнюю часть панели запросов, вы увидите раздел «Переменные запроса». Щелкнув по нему, вы его развернете. Здесь мне нужно добавить переменную для slug. Я определю его в фигурных скобках с путем к одному из файлов:

{
  "slug": "2021/03/08/third-post/"
}

Запустив запрос еще раз, я получу все данные для этого файла. Я закомментировал bodyвывод для удобства чтения:

{
  "data": {
    "mdx": {
      "id": "105a5c78-6a36-56e8-976c-d53d8e6ca623",
      "slug": "2021/01/08/third-post/",
      "body": "function _extends() ...", // compiled MDX here
      "frontmatter": {
        "date": "2021-03-08T00:00:00.000Z",
        "title": "Third Post!"
      }
    }
  },
  "extensions": {}
}

API маршрутизации файловой системы передает отдельные пути к файлам в запрос страницы src/pages/{mdx.slug}.jsи возвращает данные на страницу из этого запроса в ({ data })опоре, передаваемой на страницу.

В этом файле вы можете заметить, что я деструктурировал bodyиз возвращаемых данных, а затем titleиз frontmatter, в двухуровневой деструктуре:

const {
  body,
  frontmatter: { title },
} = data.mdx;

Альтернативный способ сделать это:

const body = data.mdx.body;
const title = data.mdx.frontmatter.title;

Использование деструктурирования делает его менее многословным.

И последнее, что следует отметить, — это MDXRendererупаковка bodyсообщения. Это все, что включено в.mdxфайл после блока вступительного сообщения. Скомпилированный MDX из запроса GraphiQL, который был закомментирован, — это то, что нужно обернуть в MDXRenderer:

<MDXRenderer>{body}</MDXRenderer>

Я зафиксирую изменения сейчас:

git add .
git commit -m 'create file route API file'

Концепция Root Wrapper

Теперь нажатие на одну из ссылок на странице индекса приведет меня к нужной.mdxстранице, но она выглядит немного иначе, чем страница индекса, верно?

Это потому, что его еще нет макета. Здесь я могу использовать API браузера Gatsby и использовать wrapPageElementфункцию для обертывания всех элементов страницы. Также рекомендуется использовать ту же функцию в Gatsby SSR.

Чтобы избежать дублирования одного и того же кода в двух файлах, я создам третий файл с реальным кодом, который собираюсь использовать, и импортирую его в два gatsby-*упомянутых файла.

Сначала я создам необходимые файлы:

# create gatsby-browser.js and gatsby-ssr.js and root-wrapper.js
touch gatsby-browser.js gatsby-ssr.js root-wrapper.js

В корневом файле-оболочке я буду использовать wrapPageElementфункцию:

// root-wrapper.js
import React from "react";
import { Layout } from "./src/components/layout";

export const rootWrapper = ({ element }) => {
  return <Layout>{element}</Layout>;
};

Затем, в обоих gatsby-browser.jsи gatsby-ssr.jsфайлы, я добавлю следующее:

import { rootWrapper } from "./root-wrapper";

export const wrapPageElement = rootWrapper;

Если в wrapPageElementфункцию нужно внести какие-либо изменения, я могу сделать это в одном файле root-wrapper.js.

Пора остановиться и снова перезапустить сервер разработки, чтобы изменения вступили в силу!

Поскольку компонент макета используется здесь для обертывания всех элементов страницы на сайте, нет необходимости больше держать его на странице индекса, поэтому я собираюсь удалить его из src/pages/index.js:

import { graphql, Link as GatsbyLink } from "gatsby";
import React from "react";
import { Box, Heading, Link } from "theme-ui";
- import { Layout } from "../components/layout";

export default function IndexPage({ data }) {
  return (
    <>
-      <Layout>
        {data.allMdx.nodes.map(({ id, excerpt, frontmatter, slug }) => (
          <Box
            key={id}
            as="article"
            sx={{
              mb: 4,
              p: 3,
              boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
              border: "1px solid #d1d1d1",
              borderRadius: "15px",
            }}
          >
            <Link as={GatsbyLink} to={`/${slug}`}>
              <Heading>{frontmatter.title}</Heading>
              <Box as="p" variant="styles.p">
                {frontmatter.date}
              </Box>
              <Box as="p" variant="styles.p">
                {excerpt}
              </Box>
            </Link>
          </Box>
        ))}
-      </Layout>
    </>
  );
};
// rest unchanged

Я зафиксирую изменения, прежде чем двигаться дальше:

git add .
git commit -m 'add root wrapper to Gatsby Browser and SSR'

404 Page

Пора сделать эту страницу 404!

# create the 404.js page
touch src/pages/404.js

В src/pages/404.jsфайле я добавлю сообщение:

import React from "react";
import { Box, Heading } from "theme-ui";

export default function NotFound() {
  return (
    <>
      <Heading variant="styles.h1">
        Page not found!
        <span role="img" aria-label="crying face">
          😢
        </span>
      </Heading>
      <Box as="h2" variant="styles.h2">
        It looks like that page doesn't exist
      </Box>
    </>
  );
}

Теперь я могу сразу перейти к 404 страницы, чтобы проверить это: http://localhost:8000/404.

Обратите внимание, что при разработке с использованием gatsby developGatsby продолжит использовать страницу 404 по умолчанию, которая переопределяет вашу пользовательскую страницу 404.

Зафиксируйте это и переходите к следующей части:

git add .
git commit -m 'add 404 page'

Переключатель темной темы

Темный режим — важная особенность программирования блогов. (Я говорю это наполовину в шутку, на случай, если вы не были уверены!) Я собираюсь использовать обработчик цветового режима пользовательского интерфейса темы useColorModeи выполнить простое переключение между двумя режимами, которые я определил в themeобъекте ранее. Вот что добавляется к src/components/header.js:

import { Link as GatsbyLink } from "gatsby";
import React from "react";
+ import { Box, Button, Heading, Link, useColorMode } from "theme-ui";

export const Header = ({ siteTitle, siteDescription }) => {
+  const [colorMode, setColorMode] = useColorMode();
  return (
    <Box as="header" sx={{ bg: "highlight", mb: "1.45rem" }}>
      <Box
        as="div"
        sx={{
          m: "0 auto",
          maxWidth: "640px",
          p: "1.45rem 1.0875rem",
        }}
      >
        <Link as={GatsbyLink} to="/">
          <Heading>{siteTitle}</Heading>
        </Link>
        <Box as="p" variant="styles.p">
          {siteDescription}
        </Box>
+        <Button
+          onClick={(e) => {
+            setColorMode(colorMode === "default" ? "dark" : "default");
+          }}
+        >
+          {colorMode === "default" ? "Dark" : "Light"}
+        </Button>
      </Box>
    </Box>
  );
};

Но это выглядит не очень хорошо, поэтому я оберну контейнер Flexкомпонентом пользовательского интерфейса темы и сдвину кнопку вправо:

import { Link as GatsbyLink } from "gatsby";
import React from "react";
+import { Box, Button, Flex, Heading, Link, useColorMode } from "theme-ui";

export const Header = ({ siteTitle, siteDescription }) => {
  const [colorMode, setColorMode] = useColorMode();
  return (
    <Box as="header" sx={{ bg: "highlight", mb: "1.45rem" }}>
      <Box
        as="div"
        sx={{
          m: "0 auto",
          maxWidth: "640px",
          p: "1.45rem 1.0875rem",
        }}
      >
+        <Flex>
+          <Box sx={{ flex: "1 1 auto", flexDirection: "column" }}>
            <Link as={GatsbyLink} to="/">
              <Heading>{siteTitle}</Heading>
            </Link>
            <Box as="p" variant="styles.p">
              {siteDescription}
            </Box>
+          </Box>
          <Button
            onClick={(e) => {
              setColorMode(colorMode === "default" ? "dark" : "default");
            }}
          >
            {colorMode === "default" ? "Dark" : "Light"}
          </Button>
+        </Flex>
      </Box>
    </Box>
  );
};

Перед тем, как перейти к следующему разделу, выполните коммит Git:

git add .
git commit -m 'add theme toggle to header'

Блоки кода

Блоки кода на данный момент выглядят немного странно, поэтому я собираюсь добавить подсветку синтаксиса с помощью одного из множества удобных пакетов пользовательского интерфейса темы. Я использую для этого Prism.

Мне нужно установить пакет и создать компонент в gatsby-plugin-theme-uiпапке с именем components.js:

# install the package
yarn add @theme-ui/prism
# create Theme UI components file
touch src/gatsby-plugin-theme-ui/components.js

В этом файле мне нужно определить, где я хочу применить стили Prism, то есть все preи codeтеги:

import Prism from "@theme-ui/prism";

export default {
  pre: (props) => props.children,
  code: Prism,
};

После этого мне также нужно указать в themeобъекте, какую тему Prism я хочу использовать:

// scr/gatsby-plugin-theme-ui/index.js

import { deep, swiss } from "@theme-ui/presets";
+ import nightOwl from "@theme-ui/prism/presets/night-owl.json";

const theme = {
  ...swiss,
  colors: {
    ...swiss.colors,
    modes: {
      dark: {
        ...deep.colors,
      },
    },
  },

  styles: {
    ...swiss.styles,
+    code: {
+      ...nightOwl,
+    },
    // remainder of the file unchanged

Чтобы изменения вступили в силу, необходима еще одна остановка и запуск сервера разработки!

Зафиксируйте изменения и перейдите к следующему разделу:

git add .
git commit -m 'add Prism package and update theme object'

Добавить компоненты в многомерные выражения

Следующий бит не обязателен. Markdown JSX позволяет включать компоненты React (JSX) в Markdown. Чтобы продемонстрировать это, я собираюсь добавить RainbowTextкомпонент, который будет анимировать некоторые цвета в цикле анимации. Для анимации мне нужна дополнительная зависимость: keyframesот @emotion/react. Я установлю это сейчас:

# create component file
touch src/components/rainbow-text.js
# install @emotion/react
yarn add @emotion/react

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

В src/components/rainbow-text.jsфайл я добавлю этот компонент:

import { keyframes } from "@emotion/react";
import React from "react";
import { Box } from "theme-ui";

export const RainbowText = ({ children }) => {
  const rainbow = keyframes({
    "0%": {
      backgroundPosition: "0 0",
    },
    "50%": {
      backgroundPosition: "400% 0",
    },
    "100%": {
      backgroundPosition: "0 0",
    },
  });

  return (
    <Box
      as="span"
      variant="styles.p"
      sx={{
        fontWeight: "heading",
        cursor: "pointer",
        textDecoration: "underline",
        ":hover": {
          background:
            "linear-gradient(90deg, #ff0000, #ffa500, #ffff00, #008000, #0000ff, #4b0082, #ee82ee) 0% 0% / 400%",
          animationDuration: "10s",
          animationTimingFunction: "ease-in-out",
          animationIterationCount: "infinite",
          animationName: `${rainbow}`,
          WebkitBackgroundClip: "text",
          WebkitTextFillColor: "transparent",
        },
      }}
    >
      {children}
    </Box>
  );
};

Поскольку это необязательно, я не буду вдаваться в подробности того, что здесь происходит. Просто знайте, что это хороший эффект CSS при наведении курсора.

Создав этот компонент, я могу импортировать его в любой.mdxфайл, в котором хочу его использовать. В этом примере я добавляю его в content/2021/03/third-post/index.mdx. Вот разница в файле после добавления компонента:

---
title: Third Post!
date: 2021-03-08
---

+ import { RainbowText } from "../../../../../src/components/rainbow-text";

This is my third post!

> with a block quote!

+ <RainbowText>Wheeeeeeee</RainbowText>

And a code block:

```js
const wheeeeee = true;
```

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

Вы, вероятно, морщась, что импорт:../../../. Снова и снова! Однако есть способ обойти это, используя концепцию корневой оболочки, которую я подробно описал ранее, и используя MDXProviderwhich will — гм! — предоставить MDX любые компоненты, которые вы ему передаете.

Возвращаясь к корневой оболочке ( root-wrapper.js), я могу обернуть страницу elementс MDXProviderи передать RainbowTextкомпонент в MDXProvider:

---
title: Third Post!
date: 2021-03-08
---

- import { RainbowText } from "../../../../../src/components/rainbow-text";

This is my third post!

> with a block quote!

<RainbowText>Wheeeeeeee</RainbowText>

And a code block:

```js
const wheeeeee = true;
```

После остановки и перезапуска сервера разработки я могу перейти к этому сообщению и по-прежнему видеть, как RainbowTextработает. Дополнительным преимуществом добавления компонентов непосредственно в документ MDXProviderявляется то, что нет необходимости импортировать компонент в.mdxдокумент, когда вы хотите его использовать. Он доступен через поставщика для всех документов многомерных выражений.

Я сделаю это сейчас:

git add .
git commit -m 'add component for mdx'

Markdown изображения

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

---
title: Hello World - from mdx!
date: 2021-03-06
---

My first post!!

## h2 Heading

![mdx logo](./mdx-logo.png)

Some meaningful prose

### h3 Heading

Some other meaningful prose

Это./mdx-logo.pngфайл, который я добавил в content/2021/03/06/hello-worldпапку, и я ссылаюсь на него как на относительный файл. Но дело не в этом. Если я перейду к сообщению hello world, отображаемое изображение будет повреждено. Мне нужно будет добавить gatsby-remark-imagesв качестве плагина, gatsby-plugin-mdxчтобы он знал, что делать с файлами изображений:

yarn add gatsby-remark-images gatsby-plugin-sharp

Затем мне нужно будет настроить плагины в gatsby-config.js:

const siteMetadata = {
  title: `My Gatsby Blog`,
  description: `This is my coding blog.`,
};

module.exports = {
  siteMetadata,
  plugins: [
    `gatsby-plugin-theme-ui`,
+    `gatsby-plugin-sharp`,
+    {
+      resolve: `gatsby-plugin-mdx`,
+      options: {
+        gatsbyRemarkPlugins: [
+          {
+            resolve: `gatsby-remark-images`,
+            options: {
+              maxWidth: 640,
+            },
+          },
+        ],
+      },
+    },
+    {
+      resolve: `gatsby-source-filesystem`,
+      options: {
+        path: `${__dirname}/content/`,
+      },
+    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content`,
        name: `content`,
      },
    },
  ],
};

Дополнительный gatsby-source-filesystemобъект сообщает Гэтсби, где искать изображения для обработки.

Зафиксируйте это сейчас:

git add .
git commit -m 'add and configure images'

SEO

SEO очень важно, если я хочу, чтобы мой контент находили в Интернете поисковые системы, поэтому мне нужно добавить здесь соответствующие метатеги в свой блог. Это может быть довольно сложный процесс определения всех необходимых тегов, поэтому, чтобы сэкономить время, я создал компонент React SEO для использования в Gatsby для создания всех необходимых метатегов.

Я перейду к yarn addкомпоненту вместе с зависимостями, необходимыми для его работы:

yarn add react-seo-component react-helmet gatsby-plugin-react-helmet

Мне нужно добавить gatsby-plugin-react-helmetв gatsby-config.jsмассив плагинов:

module.exports = {
  siteMetadata,
  plugins: [
+   `gatsby-plugin-react-helmet`,
    `gatsby-plugin-theme-ui`,
    `gatsby-plugin-sharp`,
    {
  // rest unchanged

Тогда это случай использования SEOкомпонента по всему сайту, где мне нужны метатеги.

Компонент занимает довольно много свойств, многие из которых определяются один раз на всем сайте, поэтому лучше всего их добавлять в siteMetadataобъект. Тогда я могу вытащить то, что мне нужно, с помощью useSiteMetadataкрючка.

Я собираюсь добавить к siteMetadataобъекту еще несколько свойств :

const siteMetadata = {
  title: `My Gatsby Blog`,
  description: `This is my coding blog.`,
+  lastBuildDate: new Date(Date.now()).toISOString(),
+  siteUrl: `https://dummy-url-for-now.com`,
+  authorName: `Author McAuthorson`,
+  twitterUsername: `@authorOfPosts`,
+  siteLanguage: `en-GB`,
+  siteLocale: `en_gb`,
};

Если вы будете следовать указаниям, вы можете изменить их по мере необходимости. На данный момент это siteUrlможет быть фиктивный URL. Это помогает указывать на любые изображения, необходимые для использования в протоколе Open Graph, и это изображение, которое вы видите, когда делитесь публикацией, которую вы сделали, например, в Twitter, Facebook, LinkedIn и Reddit.

Теперь, когда эти дополнительные свойства находятся в siteMetadataобъекте, мне нужно иметь возможность запрашивать их. В настоящее время в useSiteMetadataхуке есть только titleи description, поэтому я добавлю все остальное:

// src/hooks/use-site-metadata.js

import { graphql, useStaticQuery } from "gatsby";
export const useSiteMetadata = () => {
  const { site } = useStaticQuery(
    graphql`
      query SITE_METADATA_QUERY {
        site {
          siteMetadata {
            title
            description
+            lastBuildDate
+            siteUrl
+            authorName
+            twitterUsername
+            siteLanguage
+            siteLocale
          }
        }
      }
    `
  );
  return site.siteMetadata;
};

Я добавлю компонент SEO на все страницы. Сначала я сделаю страницы сообщений на src/pages/{mdx.slug}.jsстранице. Это один из самых сложных, поэтому я расскажу о различиях и подробно опишу, что происходит:

import { graphql } from "gatsby";
import { MDXRenderer } from "gatsby-plugin-mdx";
import React from "react";
+ import SEO from "react-seo-component";
import { Box } from "theme-ui";
+ import { useSiteMetadata } from "../hooks/use-site-metadata";

export default function PostPage({ data }) {
  const {
    body,
+    slug,
+    excerpt,
+    frontmatter: { title, date },
  } = data.mdx;
+  const {
+    title: siteTitle,
+    siteUrl,
+    siteLanguage,
+    siteLocale,
+    twitterUsername,
+    authorName,
+  } = useSiteMetadata();
  return (
    <>
+      <SEO
+        title={title}
+        titleTemplate={siteTitle}
+        description={excerpt}
+        pathname={`${siteUrl}${slug}`}
+        article={true}
+        siteLanguage={siteLanguage}
+        siteLocale={siteLocale}
+        twitterUsername={twitterUsername}
+        author={authorName}
+        publishedDate={date}
+        modifiedDate={new Date(Date.now()).toISOString()}
+      />
      <Box as="h1" variant="styles.h1" fontSize="4xl">
        {title}
      </Box>
      <MDXRenderer>{body}</MDXRenderer>
    </>
  );
}

export const query = graphql`
  query POST_BY_SLUG($slug: String) {
    mdx(slug: { eq: $slug }) {
      id
      slug
      body
+      excerpt
      frontmatter {
        date
        title
      }
    }
  }
`;

siteUrl, slugИ excerptнеобходимы для канонической связи (очень важно в SEO) и excerptдля описания мета.

Я использую siteMetadataловушку, чтобы получить остальную информацию, необходимую компоненту. titleи titleTemplateиспользуются для создания того, что вы видите на вкладке браузера.

articleBoolean для компонента, поэтому он может создать список в строке навигации JSONLD формата. Остальные реквизиты помогают определить автора и дату публикации. 😅

Это было много. Я надеюсь, что кое-что из этого имело смысл! Что касается объема этого сообщения, я оставлю его там, но есть еще много чего, чтобы вникнуть в эту тему, и я имею в виду очень многое !

К счастью, src/pages/index.jsстраница стала немного проще!

import { graphql, Link as GatsbyLink } from "gatsby";
import React from "react";
+ import SEO from "react-seo-component";
import { Box, Heading, Link } from "theme-ui";
+ import { useSiteMetadata } from "../hooks/use-site-metadata";

export default function IndexPage({ data }) {
+  const {
+    title,
+    description,
+    siteUrl,
+    siteLanguage,
+    siteLocale,
+    twitterUsername,
+  } = useSiteMetadata();
  return (
    <>
+      <SEO
+        title={`Home`}
+        titleTemplate={title}
+        description={description}
+        pathname={siteUrl}
+        siteLanguage={siteLanguage}
+        siteLocale={siteLocale}
+        twitterUsername={twitterUsername}
+      />
      {data.allMdx.nodes.map(({ id, excerpt, frontmatter, slug }) => (
// rest of component unchanged

Я намеренно исключил изображение из обоих примеров. Если вы заинтересованы в создании собственных изображений Open Graph для использования в этом компоненте, ознакомьтесь с публикацией » Изображения Open Graph с помощью Gatsby и Vercel «, чтобы узнать, как это сделать с помощью бессерверной функции. 🔥

Теперь я могу создать сайт (почти готовый к производству), и как только он будет построен, я могу проверить источник страницы на наличие метатегов:

# build the site first
yarn build
# use gatsby serve to run built site locally
yarn serve

После завершения сборки я могу использовать yarn serveсозданный сайт для локального обслуживания localhost:9000. В браузере я могу просмотреть исходный код страницы с помощью сочетания клавиш Ctrl+ u. Отсюда я могу проверить canonicalметатег, который будет фиктивным URL-адресом, используемым в метаданных.

Хорошо! Зафиксируйте это в Git и двигайтесь дальше:

git add .
git commit -m 'add SEO component :sweat_smile:'

Отправьте это на GitHub

Вам может быть интересно, почему я делаю коммиты Git в конце каждого раздела. Это потому, что сейчас я собираюсь отправить проект на GitHub.

Я войду в свою учетную запись GitHub, выберу +значок плюса рядом с изображением моего аватара в правом верхнем углу и выберу » Новый репозиторий».

В имени репозитория я добавлю имя проекта, my-gatsby-blogно оставлю остальные значения по умолчанию и нажму » Создать репозиторий«.

Следующий экран дает мне команды терминала, которые мне нужны, чтобы отправить мой локальный проект в GitHub:

git remote add origin https://github.com/spences10/my-gatsby-blog
git branch -M main
git push -u origin main

После того, как вы поместите все это в терминал и нажмете Enter, обновите страницу GitHub, чтобы увидеть новый проект!

Развертывать

Пора выложить эту малышку в Интернет! Есть много способов сделать это. Поскольку Gatsby имеет плоскую файловую структуру, вы можете разместить сайт Gatsby на любом файловом сервере с доступом в Интернет.

Есть много сервисов, предлагающих хостинг на CDN, многие бесплатно! Такие услуги, как Netlify, Vercel и визуализация позволит вам продвинуть Ваш сайт, построенный на их КДС с помощью CLI, интеграции GitHub, или, в случае Netlify, прямо вверх перетаскивание!

Vercel

Для развертывания с Vercel вам понадобится учетная запись GitHub, GitLab или Bitbucket для аутентификации. Затем вам будет предложено установить Vercel CLI:

yarn global add vercel

Он у меня уже установлен, так что теперь можно запустить команду CLI:

vc

Затем мне будет предложено настроить и развернуть новый проект. Я собираюсь ответить на все вопросы по умолчанию Enter:

Set up and deploy “~/repos/my-gatsby-blog”? [Y/n]
Which scope do you want to deploy to?
Link to existing project? [y/N]
What’s your project’s name? (my-gatsby-blog)
In which directory is your code located? ./
> Upload [====================] 99% 0.0sAuto-detected Project Settings (Gatsby.js):
- Build Command: `npm run build` or `gatsby build`
- Output Directory: public
- Development Command: gatsby develop --port $PORT
? Want to override the settings? [y/N]

Вот и все. Затем мне предоставляется URL-адрес развертывания, по которому я могу наблюдать за сборкой сайта на Vercel.

С панели инструментов Vercel я могу настроить домен, а также купить его у Vercel, если захочу. Я лично использую Namecheap.com, но это вариант.

Netlify

Развертывание с помощью Netlify через интерфейс командной строки почти такое же, как и с помощью Vercel, но я собираюсь выполнить создание с помощью перетаскивания.

Для аутентификации мне понадобится одна из учетных записей GitHub, GitLab, Bitbucket или электронной почты. После аутентификации и входа в систему я могу выбрать » Сайты» в строке меню, затем появится область перетаскивания. Хотите развернуть новый сайт без подключения к Git? Перетащите сюда папку вывода вашего сайта. Я собираюсь перейти в моем файловом проводнике к корню моего проекта и перетащить publicпапку в область перетаскивания.

Netlify создаст файлы и развернет их по сгенерированному URL-адресу для проверки. Как и в случае с Vercel, Netlify позволит вам приобрести там домен и развернуть его.

Оказывать

Render не имеет интерфейса командной строки или опции перетаскивания и вместо этого использует интеграцию с GitHub. Для аутентификации мне понадобится учетная запись GitHub, GitLab или Google. После аутентификации и входа в систему я попадаю в раздел услуг. Отсюда я могу выбрать » Новый статический сайт», а затем ввести свой URL-адрес GitHub для проекта, который я ранее отправил на GitHub.

На следующей странице я дам ему следующие настройки:

  • Имя :my-gatsby-blog
  • Ветвь : значение по умолчанию
  • Команда сборки :yarn build
  • Опубликовать каталог :./public

Затем нажмите » Создать статический сайт «.

Подождите, пока Render сделает свое дело, а затем щелкните ссылку под названием проекта, чтобы увидеть сайт вживую.

Render также имеет возможность установить свой собственный домен для сайта!

Дополнительные плагины Gatsby

Есть еще много плагинов Gatsby для добавления дополнительных функций. Я оставлю это вам, если вы хотите добавить больше. Например:

  • Вы хотите встраивать видео с YouTube, твиты, сообщения Strava, CoodePens и Codesandbox? Посмотрите gatsby-plugin-mdx-embed.
  • Вы используете поисковую консоль Google / Bing? Затем вам нужно будет создать карту сайта с помощью gatsby-plugin-sitemap.
  • Вы хотите, чтобы ваш сайт был доступен в автономном режиме как PWA? Добавьте gatsby-plugin-offline.
  • Вы хотите, чтобы на вкладке браузера был значок вашего сайта? Ознакомьтесь с gatsby-plugin-manifest.

Аналитика

Если вам интересно узнать, насколько популярен ваш сайт, есть варианты аналитики. Некоторое время назад я перестал использовать Google Analytics в своих проектах и ​​теперь предпочитаю альтернативы, ориентированные на конфиденциальность. Я рекомендую Fathom Analytics. (У меня есть партнерская ссылка, если вы хотите получить скидку 10 долларов на подписку на первый месяц.)

Другая альтернатива — Plausible, о которой я тоже много слышал.

Чтобы реализовать Fathom Analytics на сайте Gatsby, мне нужно добавить дополнительный тег скрипта в заголовок моего сайта. Что это обозначает? Ну, сначала мне нужно создать сайт на моей панели инструментов Fathom, затем перейти на https://app.usefathom.com/#/settings/sites, прокрутить до конца списка, добавить мой новый сайт ( my-gatsby-blog), затем щелкните Получить код сайта. Затем я получаю всплывающее окно с кодом сайта. Мне это понадобится для сценария, который я собираюсь добавить в заголовок моего проекта Gatsby. Вот как выглядит сценарий:

<script
  src="https://cdn.usefathom.com/script.js"
  data-spa="auto"
  data-site="ABCDEF"
  defer
></script>

Вот разница root-wrapper.js:

import { MDXProvider } from "@mdx-js/react";
import React from "react";
+import { Helmet } from "react-helmet";
import Layout from "./src/components/layout";
import RainbowText from "./src/components/rainbow-text";

const MDXComponents = {
  RainbowText,
};

export const wrapPageElement = ({ element }) => {
  return (
+    <>
+      <Helmet>
+        <script
+          src="https://cdn.usefathom.com/script.js"
+          spa="auto"
+          data-site="ABCDEF"
+          defer
+        ></script>
+      </Helmet>
      <Layout>
        <MDXProvider components={MDXComponents}>{element}</MDXProvider>
      </Layout>
+    </>
  );
};

Оцените статью
bestprogrammer.ru
Добавить комментарий