Детально про Gatsby.js – інструмент для створення складних веб-сайтів

Як відомо, на одних бойлерплейтах далеко не заїдеш, тому доводиться лізти вглиб будь-якої технології, щоб навчитися писати щось вартісне. У цій статті розглянемо деталі Gatsby.js, знання яких дозволить вам створювати і підтримувати складні веб-сайти і блоги.

Теми, розглянуті нижче:

Підготовка

Встановлення Gatsby на ПК
yarn global add gatsby-cli
Клонування мінімального проекту
npx gatsby new gatsby-tutorial https://github.com/gatsbyjs/gatsby-starter-hello-world
cd gatsby-tutorial
Ініціалізація репозиторію
git init
git add .
git commit -m "init commit"
Перевірка справності
yarn start

Якщо в консолі немає помилок, а в браузері на http://localhost:8000 видніється «Hello world!» ― значить все працює справно. Можна спробувати змінити вміст файлу /src/pages/index.js, щоб перевірити hot-reload.

Структура сторінок і роутинг

Щоб створити сторінку в Gatsby, досить просто помістити новий файл в папку /src/pages, та його буде скомпільовано в окрему HTML-сторінку. Важливо зауважити, що URL до цієї сторінки буде відповідати фактичному шляху з назвою. Наприклад, додамо ще кілька сторінок:

src
└── pages
    ├── about.js
    ├── index.js
    └── tutorial
        ├── part-four.js
        ├── part-one.js
        ├── part-three.js
        ├── part-two.js
        └── part-zero.js

Контент поки не важливий, тому можна використовувати будь-який текст задля того, щоб розрізняти сторінки:

import React from "react";

export default () => <div>Welcome to tutorial/part-one</div>;

Перевіряємо в браузері:

Ось таким чином можна, структуруючи файли, водночас вирішувати питання роутингу.

Також існує спеціальний createPage API, за допомогою якого можна більш гнучко керувати шляхами і назвами сторінок, але для роботи з ним нам знадобиться розуміння роботи даних в Gatsby, тому розглянемо його трохи далі в статті.

Зв’яжемо створені сторінки за допомогою посилань ― для цього скористаємося компонентом <Link /> з пакета Gatsby, який створений спеціально для внутрішньої навігації. Для всіх зовнішніх посилань слід використовувати звичайний <a> тег.

/src/pages/index.js

import React from "react";
import { Link } from "gatsby";

export default () => (
  <div>
    <ul>
      <li>
        <Link to="/about">about</Link>
      </li>
      <li>
        <Link to="/tutorial/part-zero">Part #0</Link>
      </li>
      <li>
        <Link to="/tutorial/part-one">Part #1</Link>
      </li>
      <li>
        <Link to="/tutorial/part-two">Part #2</Link>
      </li>
      <li>
        <Link to="/tutorial/part-three">Part #3</Link>
      </li>
      <li>
        <Link to="/tutorial/part-four">Part #4</Link>
      </li>
    </ul>
  </div>
);

<Link> під капотом має дуже хитрий механізм щодо оптимізації завантаження сторінок і тому використовується замість <a> для навігації по сайту. Детальніше можна почитати тут.

Сторінки створені, посилання додані. Схоже, що з навігацією закінчили.

Компоненти, шаблони та їх взаємодія

Як відомо, в будь-якому проекті завжди є елементи, що повторюються. Для веб-сайтів це хедер, футер, навігаційна панель. Також сторінки, незалежно від контенту, будуються за заданою структурою. Так як Gatsby — це компілятор для React , тут використовується той самий компонентний підхід для вирішення цих проблем.

Створимо компоненти для хедера та навігаційної панелі:

/src/components/header.js

import React from "react";
import { Link } from "gatsby";

/**
 * Зверніть увагу на те, що зображення для логотипу
 * імпортується так само, як і в звичайному React-проекті.
 * Це тимчасове і не оптимальне рішення, тому що картинка
 * поставляється "як є". Трохи далі ми розглянемо
 * як це робити "правильно" використовуючи GraphQL і gatsby-плагіни
 */
import logoSrc from "../images/logo.png";

export default () => (
  <header>
    <Link to="/">
      <img src={logoSrc} alt="logo" width="60px" height="60px" />
    </Link>
    That is header
  </header>
);

/src/components/sidebar.js

import React from "react";
import { Link } from "gatsby";

export default () => (
  <div>
    <ul>
      <li>
        <Link to="/about">about</Link>
      </li>
      <li>
        <Link to="/tutorial/part-zero">Part #0</Link>
      </li>
      <li>
        <Link to="/tutorial/part-one">Part #1</Link>
      </li>
      <li>
        <Link to="/tutorial/part-two">Part #2</Link>
      </li>
      <li>
        <Link to="/tutorial/part-three">Part #3</Link>
      </li>
      <li>
        <Link to="/tutorial/part-four">Part #4</Link>
      </li>
    </ul>
  </div>
);

і додамо їх в /src/pages/index.js

import React from "react";

import Header from "../components/header";
import Sidebar from "../components/sidebar";

export default () => (
  <div>
    <Header />
    <Sidebar />
    <h1>Index page</h1>
  </div>
);

Перевіряємо:

Все працює, але нам потрібно імпортувати Header і Sidebar на кожну сторінку окремо, що не дуже то й зручно. Щоб вирішити це питання, досить створити layout-компонент та огорнути ним кожну сторінку.

Gatsby layout == React container
так-так, саме неточна рівність, тому що це «майже» одне і те саме_

/src/components/layout.js

import React from "react";

import Header from "./header";
import Sidebar from "./sidebar";

export default ({ children }) => (
  <>
    <Header />
    <div
      style={{ margin: `0 auto`, maxWidth: 650, backgroundColor: `#eeeeee` }}
    >
      <Sidebar />
      {children}
    </div>
  </>
);

/src/pages/index.js (і всі інші сторінки)

import React from "react";

import Layout from "../components/layout";

export default () => (
  <Layout>
    <h1>Index page</h1>
  </Layout>
);

Готово, дивимося в браузер:

Чому в проекті всі назви файлів з маленької літери? Для початку визначимося, що naming convention для React виходить з того, що «кожен файл — це клас, а клас завжди називається з великої літери». В Gatsby файли, як і раніше, містять класи, але є одне «але»: «кожен файл є потенційною сторінкою, а його назва ― URL до цієї сторінки». Ком’юніті прийшло до висновку про те, що посилання виду http://domain.com/User/Settings ― це не comme-il-fautі, і затвердило kebab-case для назв файлів.

Структура файлів
src
├── components
│   ├── header.js
│   ├── layout.js
│   └── sidebar.js
├── images
│   └── logo.png
└── pages
    ├── about.js
    ├── index.js
    └── tutorial
        ├── part-eight.js
        ├── part-five.js
        ├── part-four.js
        ├── part-one.js
        ├── part-seven.js
        ├── part-six.js
        ├── part-three.js
        ├── part-two.js
        └── part-zero.js

Робота з даними

Тепер, коли структура сайту готова, можна переходити до наповнення контентом. Класичний «хардкод» підхід не влаштовував творців JAM-стеку, так само, як і «рендерити контент з AJAX-запитів». Тому вони запропонували заповнювати сайти контентом під час компіляції. У випадку з Gatsby за це відповідає GraphQL, який дозволяє зручно працювати з потоками даних з будь-яких джерел.

Розповісти про GraphQL в двох словах неможливо, тому бажано вивчити його самостійно або почекати моєї наступної статті. Детальніше про роботу з GraphQL можна почитати тут.

Для роботи з GraphQL, з другої версії, в пакеті gatsby є компонент StaticQuery, який може використовуватися як на сторінках, так і в простих компонентах, і в цьому його головна відмінність від його попередника ― page query. Поки що наш сайт не з’єднаний з якимись джерелами даних, тому спробуємо вивести метадані сторінок, для прикладу, а потім перейдемо до більш складних речей.

Щоб побудувати query, потрібно відкрити localhost:8000/___graphql і, користуючись бічною панеллю з документацією, знайти доступні дані про сайт. І не забудьте про автодоповнення.

/src/components/sidebar.js

import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";

export default () => (
  <StaticQuery
    query={graphql`
      {
        allSitePage {
          edges {
            node {
              id
              path
            }
          }
        }
      }
    `}
    render={({ allSitePage: { edges } }) => (
      <ul>
        {edges.map(({ node: { id, path } }) => (
          <li key={id}>
            <Link to={path}>{id}</Link>
          </li>
        ))}
      </ul>
    )}
  />
);

Тепер ми, використовуючи query, отримуємо дані про сторінки, які рендеримо в панелі навігації. Більше не потрібно переживати з приводу того, що посилання не буде відповідати назві, тому що всі дані збираються автоматично.

По факту це всі дані, які можуть бути на нашому сайті без використання сторонніх плагінів і без старого доброго «хардкоду», тому ми плавно переходимо в наступну тему нашої статті ― плагіни.

Плагіни

За своєю суттю Gatsby — це компілятор з купою фішок, якими якраз і є плагіни. За допомогою них можна налаштовувати обробку тих чи інших файлів, типів даних і різних форматів.

Створимо на кореневому рівні додатку файл /gatsby-config.js<|em>, який відповідає за конфігурацію компілятора в цілому, і спробуємо налаштувати перший плагін для роботи з файлами.

Встановлення плагіну:

yarn add gatsby-source-filesystem

Конфігурація у файлі /gatsby-config.js:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`,
      }
    }
  ],
}

Детальніше про файл вище
/**
 * gatsby-config.js це файл, який повинен
 * за замовчуванням експортувати об'єкт JS
 * з конфігурацією для компілятора
 */
module.exports = {
  /**
   * поле 'plugins' описує pipeline процесу компіляції
   * та складається з набору плагінів
   */
  plugins: [
    /**
     * кожен плагін може бути вказаний у вигляді рядка
     * або у вигляді об'єкта для налаштування його опцій
     */
    `gatsby-example-plugin`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`,
      }
    }
  ],
}

Пам’ятайте ми говорили про «правильний» імпорт картинок в Gatsby?

/src/components/header.js

import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";

export default () => (
  <StaticQuery
    query={graphql`
      {
        allFile(filter: { name: { eq: "logo" } }) {
          edges {
            node {
              publicURL
            }
          }
        }
      }
    `}
    render={({
      allFile: {
        edges: [
          {
            node: { publicURL }
          }
        ]
      }
    }) => (
      <header>
        <Link to="/">
          <img src={publicURL} alt="logo" width="60px" height="60px" />
        </Link>
        That is header
      </header>
    )}
  />
);

На сайті нічого не змінилося, але тепер картинка підставляється за допомогою GraphQL, замість простого webpack-імпорту. З першого погляду може здатися, що конструкції занадто складні і це лише додає проблем, але давайте не поспішати з висновками, бо справа в тих же самих плагінах. Наприклад, якби ми вирішили розміщувати на сайті тисячі фотографій, то нам в будь-якому випадку довелося б думати про оптимізацію завантаження всього контенту. Щоб не будувати свій lazy-load процесс з нуля, ми б просто додали gatsby-image плагін, який би оптимізував завантаження всіх картинок, що імпортуються за допомогою query.

Встановлення плагінів для стилізації:

yarn add gatsby-plugin-typography react-typography typography typography-theme-noriega node-sass gatsby-plugin-sass gatsby-plugin-styled-components styled-components babel-plugin-styled-components

gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`
      }
    },
    // add style plugins below
    `gatsby-plugin-typography`,
    `gatsby-plugin-sass`,
    `gatsby-plugin-styled-components`
  ]
};

На офіційному сайті можна знайти плагін на будь-який смак.

Стилізація сайту

Почнемо стилізацію додатку, використовуючи різні підходи. У попередньому кроці ми вже встановили плагіни для роботи з SASS, styled-components та бібліотекою typography.js. При цьому важливо відзначити, що css.modules підтримуються «з коробки».

Почнемо роботу з глобальних стилів, які, як і інші речі, що відносяться до всього сайту, повинні бути налаштовані в файлі /gatsby-browser.js:

import "./src/styles/global.scss";

Детальніше про gatsby-browser.js.

/src/styles/global.scss

body {
  background-color: lavenderblush;
}

З різних причин тенденції останніх років схиляються в бік «CSS in JS» підходу, тому не варто зловживати глобальними стилями і краще обмежитися зазначенням шрифту і глобальних класів. У цьому конкретному проекті планується використання Typography.js для цих цілей, тому глобальні стилі залишаться порожніми.

Ви вже могли помітити зміни зовнішнього вигляду сайту після додавання gatsby-plugin-typography в конфігурацію. Це тому, що був застосований його пресет за замовчуванням, а зараз ми сконфігуруємо його під себе.

/src/utils/typography.js

import Typography from "typography";
import theme from "typography-theme-noriega";

const typography = new Typography(theme);

export default typography;

Можна вибрати будь-який інший пресет зі списку або створити свій власний, використовуючи API пакету (приклад конфігурації офіційного сайту Gatsby).

/gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`
      }
    },
    {
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`
      }
    },
    `gatsby-plugin-sass`,
    `gatsby-plugin-styled-components`
  ]
};

І в залежності від обраного пресету глобальний стиль сайту буде змінений. Яким підходом налаштовувати глобальні стилі, вирішуйте самі, бо відмінностей з технічної точки зору немає і тому це питання смаку. А ми переходимо до стилізації компонентів, використовуючи styled-components.

Додамо файл з глобальними змінними /src/utils/vars.js

export const colors = {
  main: `#663399`,
  second: `#fbfafc`,
  main50: `rgba(102, 51, 153, 0.5)`,
  second50: `rgba(251, 250, 252, 0.5)`,
  textMain: `#000000`,
  textSecond: `#ffffff`,
  textBody: `#222222`
};

/src/components/header.js
import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";
import styled from "styled-components";

import { colors } from "../utils/vars";

const Header = styled.header`
  width: 100%;
  height: 3em;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: ${colors.main};
  color: ${colors.textSecond};
  padding: 0.5em;
`;

const Logo = styled.img`
  border-radius: 50%;
  height: 100%;
`;
const logoLink = `height: 100%;`;

export default () => (
  <StaticQuery
    query={graphql`
      {
        allFile(filter: { name: { eq: "logo" } }) {
          edges {
            node {
              publicURL
            }
          }
        }
      }
    `}
    render={({
      allFile: {
        edges: [
          {
            node: { publicURL }
          }
        ]
      }
    }) => (
      <Header>
        That is header
        <Link to="/" css={logoLink}>
          <Logo src={publicURL} alt="logo" />
        </Link>
      </Header>
    )}
  />
);

/src/components/sidebar.js
import React from "react"
import { Link, StaticQuery, graphql } from "gatsby"
import styled from "styled-components"

import { colors } from "../utils/vars"

const Sidebar = styled.section`
  position: fixed;
  left: 0;
  width: 20%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background-color: ${colors.second};
  color: ${colors.textMain};
`

const navItem = `
  display: flex;
  align-items: center;
  margin: 0 1em 0 2em;
  padding: 0.5em 0;
  border-bottom: 0.05em solid ${colors.mainHalf};
  postion: relative;
  color: ${colors.textBody};
  text-decoration: none;

  &:before {
    content: '';
    transition: 0.5s;
    width: 0.5em;
    height: 0.5em;
    position: absolute;
    left: 0.8em;
    border-radius: 50%;
    display: block;
    background-color: ${colors.main};
    transform: scale(0);
  }

  &:last-child {
    border-bottom: none;
  }

  &:hover {
    &:before {
      transform: scale(1);
    }
  }
`

export default () => (
  <StaticQuery
    query={graphql`
      {
        allSitePage {
          edges {
            node {
              id,
              path
            }
          }
        }
      }
    `}
    render={({
      allSitePage: {
        edges
      }
    }) => (
      <Sidebar>
        {
          edges.map(({
            node: {
              id,
              path
            }
          }) => (
            <Link to={path} key={id} css={navItem} >{id}</Link>
          ))
        }
      </Sidebar>
    )}
  />

)

Вже існуючі елементи стилізовані, і настав час зв’язати контент з Contentful, підключити Markdown-плагін і згенерувати сторінки, використовуючи createPages API.

Детальніше про те, як зв’язати Gatsby і Contentful, читайте в попередній статті.

Структура моїх даних з Contentful
[
  {
    "id": "title",
    "type": "Symbol"
  },
  {
    "id": "content",
    "type": "Text",
  },
  {
    "id": "link",
    "type": "Symbol",
  },
  {
    "id": "orderNumber",
    "type": "Integer",
  }
]

Встановлення пакетів:

yarn add dotenv gatsby-source-contentful gatsby-transformer-remark

/gatsby-config.js

if (process.env.NODE_ENV === "development") {
  require("dotenv").config();
}

module.exports = {
  plugins: [
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`,
      }
    },
    {
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`,
      },
    },
    {
      resolve: `gatsby-source-contentful`,
      options: {
        spaceId: process.env.CONTENTFUL_SPACE_ID,
        accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
      },
    },
    `gatsby-plugin-sass`,
    `gatsby-plugin-styled-components`,
  ],
}

Видаляємо папку /src/pages з усіма файлами всередині і створюємо новий файл для керування вузлами в Gatsby:

/gatsby-node.js

const path = require(`path`);

/**
 * Експортована функція, яка перезапише існуючу за замовчуванням,
 * та буде викликана для генерації сторінок
 */
exports.createPages = ({ graphql, actions }) => {
  /**
   * Отримуємо метод для створення сторінки з екшенів,
   * щоб уникнути зайвих імпортів і зберігати контекст
   * сторінки і функції
   */
  const { createPage } = actions;
  return graphql(`
    {
      allContentfulArticle {
        edges {
          node {
            title
            link
            content {
              childMarkdownRemark {
                html
              }
            }
          }
        }
      }
    }
  `).then(({ data: { allContentfulArticle: { edges } } }) => {
    /**
     * Для кожного елемента з відповіді
     * викликаємо createPage () функцію і передаємо
     * всередину дані за допомогою контексту
     */
    edges.forEach(({ node }) => {
      createPage({
        path: node.link,
        component: path.resolve(`./src/templates/index.js`),
        context: {
          slug: node.link
        }
      });
    });
  });
};

Детальніше про gatsby-node.js.

Створюємо template-файл, який буде основою для сторінок, які генеруються/src/templates/index.js

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

export default ({
  data: {
    allContentfulArticle: {
      edges: [
        {
          node: {
            content: {
              childMarkdownRemark: { html }
            }
          }
        }
      ]
    }
  }
}) => {
  return (
    <Layout>
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </Layout>
  );
};

export const query = graphql`
  query($slug: String!) {
    allContentfulArticle(filter: { link: { eq: $slug } }) {
      edges {
        node {
          title
          link
          content {
            childMarkdownRemark {
              html
            }
          }
        }
      }
    }
  }
`;

Чому тут не використовується <StaticQuery /> компонент? Вся справа в тому, що він не підтримує змінні для побудови запиту, а нам потрібно використовувати змінну $slug з контексту сторінки.

Оновлюємо логіку в навігаційній панелі
import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";
import styled from "styled-components";

import { colors } from "../utils/vars";

const Sidebar = styled.section`
  position: fixed;
  left: 0;
  width: 20%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background-color: ${colors.second};
  color: ${colors.textMain};
`;

const navItem = `
  display: flex;
  align-items: center;
  margin: 0 1em 0 2em;
  padding: 0.5em 0;
  border-bottom: 0.05em solid ${colors.main50};
  postion: relative;
  color: ${colors.textBody};
  text-decoration: none;

  &:before {
    content: '';
    transition: 0.5s;
    width: 0.5em;
    height: 0.5em;
    position: absolute;
    left: 0.8em;
    border-radius: 50%;
    display: block;
    background-color: ${colors.main};
    transform: scale(0);
  }

  &:last-child {
    border-bottom: none;
  }

  &:hover {
    &:before {
      transform: scale(1);
    }
  }
`;

export default () => (
  <StaticQuery
    query={graphql`
      {
        allContentfulArticle(sort: { order: ASC, fields: orderNumber }) {
          edges {
            node {
              title
              link
              orderNumber
            }
          }
        }
      }
    `}
    render={({ allContentfulArticle: { edges } }) => (
      <Sidebar>
        {edges.map(({ node: { title, link, orderNumber } }) => (
          <Link to={link} key={link} css={navItem}>
            {orderNumber}. {title}
          </Link>
        ))}
      </Sidebar>
    )}
  />
);

SEO-оптимізація з використанням react-helmet

З технічної точки зору сайт можна вважати готовим, тому давайте попрацюємо з його мета-даними. Для цього нам знадобляться такі плагіни:

yarn add gatsby-plugin-react-helmet react-helmet

react-helmet генерує <head> ... </ head> для HTML сторінок і в зв’язці з Gatsby рендерингом є потужним і зручним інструментом для роботи з SEO.

/src/templates/index.js

import React from "react";
import { graphql } from "gatsby";
import { Helmet } from "react-helmet";

import Layout from "../components/layout";

export default ({
  data: {
    allContentfulArticle: {
      edges: [
        {
          node: {
            title,
            content: {
              childMarkdownRemark: { html }
            }
          }
        }
      ]
    }
  }
}) => {
  return (
    <Layout>
      <Helmet>
        <meta charSet="utf-8" />
        <title>{title}</title>
      </Helmet>
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </Layout>
  );
};

export const query = graphql`
  query($slug: String!) {
    allContentfulArticle(filter: { link: { eq: $slug } }) {
      edges {
        node {
          title
          link
          content {
            childMarkdownRemark {
              html
            }
          }
        }
      }
    }
  }
`;

Тепер title сайту буде завжди збігатися з назвою статті, що буде істотно впливати на видачу сайту в результатах пошуку, конкретно з цього питання. Сюди ж можна легко додати <meta name="description" content="Опис статті"> з описом кожної статті окремо, надаючи цим можливість користувачеві, ще на сторінці пошуку, зрозуміти, про що йде мова в статті. І взагалі всі можливості SEO тепер доступні, і ними можна керувати з одного місця.

Налаштування PWA

Gatsby розроблений, щоб забезпечити першокласну продуктивність «з коробки». Він бере на себе питання щодо розділення і мінімізації коду, а також оптимізації у вигляді попереднього завантаження у фоновому режимі, обробки зображень і ін. Отже, створюваний вами сайт має високу продуктивність без будь-яких додаткових налаштувань. Ці функції продуктивності є важливою частиною підтримки прогресивного підходу до веб-додатків.

Але крім усього, перерахованого вище, існують три базові критерії для сайту, які визначають його як PWA:

Перший пункт не може бути вирішений силами Gatsby, оскільки домен, хостинг і протокол — це питання деплойменту, і ніяк не розробки. Але можу порадити Netlify, який легко вирішує проблему з https.

Переходимо до інших пунктів. Для цього встановимо два плагіни:

yarn add gatsby-plugin-manifest gatsby-plugin-offline

і налаштуємо їх /src/gatsby-config.js

if (process.env.NODE_ENV === "development") {
  require("dotenv").config();
}

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `GatsbyJS translated tutorial`,
        short_name: `GatsbyJS tutorial`,
        start_url: `/`,
        background_color: `#f7f0eb`,
        theme_color: `#a2466c`,
        display: `standalone`,
        icon: `public/favicon.ico`,
        include_favicon: true
      }
    },
    `gatsby-plugin-offline`,
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`
      }
    },
    {
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`
      }
    },
    {
      resolve: `gatsby-source-contentful`,
      options: {
        spaceId: process.env.CONTENTFUL_SPACE_ID,
        accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
      }
    },
    `gatsby-plugin-sass`,
    `gatsby-plugin-styled-components`,
    `gatsby-plugin-react-helmet`
  ]
};

Ви можете налаштувати свій маніфест, використовуючи документацію, а також кастомізувати стратегію service-workers, перезаписавши налаштування плагіну.

Ніяких змін в режимі розробки ви не помітите, але сайт вже відповідає останнім вимогам світу web. І коли він буде розміщений на https:// домені, йому не буде рівних.

Висновок

Кілька років тому, коли я вперше зіткнувся з проблемами виведення в інтернет React-додатку, його підтримки і оновлення контенту, я і не міг уявити, що на ринку вже існував JAM-stack підхід, який спрощує всі ці процеси. І зараз я не перестаю дивуватися його простоті. Gatsby вирішує більшість питань, які впливають на продуктивність сайту просто «з коробки». А якщо ще трохи розібравшись в тонкощах, налаштувати його під свої потреби, то можна отримати 100% показники за всіма пунктами в Lighthouse, чим суттєво вплинути на видачу сайту в пошукових системах (принаймні в Google).

Репозиторій з проектом

Наостанок

Як ви могли помітити, розглянутий в статті проект копіює основний сайт з документацією Gatsby.js. Це неспроста, тому що я замахнувся перекласти хоча би вступний туторіал російською та українською мовами, щоб популяризувати цей стек в Україні та СНД. Подивитися на поточну версію можна тут.

Читайте також мою попередню статтю про те, як створити і опублікувати особистий блог, використовуючи JAM-stack.

Похожие статьи:
У новому випуску DOU News — новинного дайджесту, в якому ми розповідаємо про головні новини в світі IT, — говоримо про те, чи може ChatGPT від...
Оператор мобильной связи «Билайн» в преддверии празднования 23 февраля или 8 марта предалагает воспользоваться возможностью...
Команда Міністерства цифрової трансформації України вирушила на серію міжнародних заходів та зустрічей у Європі. Зокрема,...
За час повномасштабної війни росії проти України майже 5 млн українців втратили роботу. Через це багато людей почали...
Время: по субботам, 11:00 — 15:00 29 октября стартует курс выходного дня QA Auto. На данном курсе вы узнаете, что...
Яндекс.Метрика