DevGang
Авторизоваться

Преобразование проекта Hygraph Next.js в каталог приложения Next.js

В конце 2022 года команда Next.js выпустила следующую стабильную версию: Next.js 13. Хотя это обновление включает в себя множество улучшенных функций, одна новая функция призвана переопределить способ сборки с помощью Next: бета-версия каталога приложений.

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

Требуемые знания

  1. Базовое понимание Next.js
  2. Базовые знания GraphQL
  3. Базовые знания Hygraph

Почему такая структура приложения?

Новая структура каталогов приложений — это не просто реорганизация вашего проекта (хотя это так, и эта реорганизация кажется мощной). Эта новая методология использует серверные компоненты React для предоставления множества новых функций и ментальных моделей. С помощью серверных компонентов разработчик может реализовать свою бизнес-логику в компоненте React, который не нужно отправлять клиенту.

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

Общая модель получения данных также изменилась. Компания Next расширила собственный метод fetch() из Node и API браузера, а также добавила дополнительные функции кэширования и дедупликации. Это означает, что вы можете создавать запросы данных в различных файлах, но запрос будет отправлен в ваш API только один раз.

Получаете сообщения из блога, чтобы создать список на главной странице и список страниц блога? Теперь это 1 запрос к API, несмотря на то, что код написан в нескольких местах. Это обеспечивает большое удобство для разработчиков и сокращает время сборки и обслуживания.

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

Настройка проекта Next.js 13 для работы с каталогом приложения

Для начала нам нужен проект Next.js. Хотя этот процесс возможен в любом проекте Next, использующем выборку данных, давайте начнем с нашего простого примера Next из репозитория hygraph-examples на GitHub. Выполните следующие команды:

npx degit hygraph/hygraph-examples/with-nextjs with-nextjs
cd with-nextjs

Перед установкой нам нужно обновить некоторые зависимости в файле package.json. Давайте обновим Next до ^13.0.0 и удалим зависимости react и react-doc.

Ваш package.json теперь должен выглядеть так:

{
  "name": "hygraph-with-nextjs",
  "private": true,
  "license": "MIT",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "graphql-request": "^1.8.2",
    "next": "^13.0.0"
  }
}

Теперь мы можем запустить сервер разработки, запустив npm run dev. Сразу после загрузки локальной версии мы видим первое обновление. Поскольку ранее Next 13 не запускался, компонент Link имеет неправильную структуру. В Next 13 нам больше не нужно иметь тег привязки внутри компонента Link. Это отличное обновление, но нам нужно изменить эти ссылки. Единственное место, где используется компонент Link, — это домашняя страница в /src/pages/index.js. Откройте этот файл и удалите теги <a></a>, чтобы сайт заработал.

// Old
    <Link key={slug} href={`/products/${slug}`}>
      <a>{name}</a>
    </Link>

// New
    <Link key={slug} href={`/products/${slug}`}>
       {name}
    </Link>

Теперь, когда сайт запущен, давайте обновим каталог Pages в новый каталог приложения.

Преобразование из /pages в /app

Прежде чем мы сможем преобразовать в каталог приложения, нам нужно сообщить Next, что мы будем использовать эту экспериментальную функцию. Для этого нам понадобится файл конфигурации. В корне нашего проекта создадим файл next.config.js. Внутри этого файла добавьте следующую базовую конфигурацию.

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
  },
};

module.exports = nextConfig;

Оттуда мы можем создать каталог нашего приложения. Внутри каталога src добавьте каталог app. Мы переместим каждый из наших маршрутов в этот каталог. Приятно то, что каждый из наших старых маршрутов продолжит работать после внесения этих изменений, поскольку оба каталога могут работать одновременно.

Создание корневого компонента макета

Одним из первых больших изменений в общей структуре является необходимость «корневого макета». Это будет основа разметки для всех страниц. Это сделать очень просто, но необходимо иметь любую глобальную информацию, необходимую для каждого маршрута. Функция RootLayout принимает дочерний объект. Этот дочерний объект будет содержать серверные компоненты, которые мы будем добавлять на каждой создаваемой странице.

export default function RootLayout({children}) {
    return (
      <html lang="en">
        <body>
            { children }
        </body>
        </html>
    )
}

С помощью этого макета мы теперь можем добавить нашу первую страницу.

Добавление домашней страницы

Вместо соглашения index.js для каталога /pages каждая страница в каталоге приложения будет называться page.js. В корне каталога приложения создайте новый файл page.js. Это будет наша домашняя страница.

Как только вы создадите эту страницу, Next выдаст ошибку в консоли. Теперь существует конфликтующий маршрут: /src/pages/index.js — это тот же маршрут, что и /src/app/page.jsx. А пока переименуйте /src/pages/index.js в oldIndex.js. Мы удалим этот файл позже, но этот файл является основой для нашего нового файла.

Как только мы переименуем файл, мы получим новую ошибку. Файл page.jsx не экспортирует компонент React. По сути, он экспортирует что угодно, поскольку он пустой. Давайте исправим это и экспортируем простой компонент React с h1 Products.

export default async function Page () {
    return (
        <>
            <h1>Products</h1>
        </>
    )
}

Теперь на главной странице должен быть H1 вместо списка продуктов со старой домашней страницы. Вернем список продуктов.

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

Перед нашим серверным компонентом в новом файле page.jsx создайте новую асинхронную функцию с именем getProducts. Это запустит запрос на выборку к конечной точке Hygraph для проекта и вернет массив продуктов. Затем мы можем запустить эту функцию в нашем серверном компоненте, чтобы просмотреть данные и отобразить ссылку на каждую страницу.

import Link from 'next/link';
const getProducts = async () => {
    const response = await fetch('https://api-eu-central-1.hygraph.com/v2/ck8sn5tnf01gc01z89dbc7s0o/master', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
        body: JSON.stringify({
            query: `{
                products {
                  slug
                  name
                  id
                }
              }`
        })

    })

    const {data} = await response.json()

    return data.products
}

export default async function Page () {
    const products = await getProducts()

    return (
        <>
            <h1>Products</h1>
            <ul>
                {products.map(product => (
                    <li key={product.id}>
                        <Link href={`/products/${product.slug}`}>{product.name}</Link>
                    </li>
                ))}
            </ul>
        </>
    )
}

Некоторые вещи изменились между нашей старой версией и новой.

  • Поскольку мы не используем getStaticProps, нам больше не нужно структурировать наш возврат определенным образом. Вместо этого мы просто возвращаем обратно массив продуктов.
  • Использование fetch вместо GraphQLRequest. Используя fetch, мы разрешаем Next кэшировать информацию, и если мы выполним идентичную выборку позже, она не будет делать отдельный вызов, а вместо этого будет использовать эти данные.

Как только вы сохраните это, у нас появится работающая домашняя страница. Эти ссылки даже ведут нас на страницы, связанные с нашими старыми динамическими маршрутами, поскольку /app и /pages могут работать поэтапно. Это может быть хорошей точкой остановки, но давайте также преобразуем наш динамический маршрут.

Преобразование динамического маршрута продуктов

Как и в случае с домашней страницей, мы начнем с настройки нашей структуры. Вместо динамических скобок маршрута, происходящих в файле, они происходят в каталоге. Таким образом, /pages/products[slug].js изменится на /app/products/[slug]/page.jsx. Это обеспечивает большую гибкость и возможность добавлять собственные, совмещенные функции, такие как страницы ошибок, страницы загрузки и пользовательские макеты.

Создайте новый файл и добавьте простой компонент, как мы это сделали для домашней страницы.

export default async function Page() {

    return (
        <>
            <h1>This is a product</h1>
        </>
    )
}

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

Общая структура этого файла существенно отличается. Как и в случае с домашней страницей, нам больше не нужна функция getStaticProps, но и getStaticPaths нам также не нужны. Все эти файлы обрабатываются на сервере, поэтому мы можем переместить всю эту информацию в одну асинхронную функцию, которая может выполняться во время запроса.

Новый серверный компонент предоставляет нам объект params, который мы можем использовать для получения пула для текущего маршрута. Мы можем передать это в новую функцию getProduct() и использовать в качестве переменной в нашем запросе к Hygraph. Это позволит получить данные для этого конкретного продукта. Затем мы можем использовать это в разметке, сгенерированной нашим компонентом, для отображения названия, описания и цены.

async function getProduct(params) {
    const response = await fetch('https://api-eu-central-1.hygraph.com/v2/ck8sn5tnf01gc01z89dbc7s0o/master', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
        body: JSON.stringify({
            query: `{
                product(where: {slug: "${params.slug}"}) {
                    name
                    description
                    price
                }
            }`,
            variables: {
                slug: params.slug
            }
        })
    })
    const {data} = await response.json()
    return data.product
}


export default async function Page({params}) {
    const product = await getProduct(params)

    return (
        <>
            <h1>{product.name}</h1>
            <p>{product.description}</p>
            <p>{product.price}</p>
        </>
    )
}

Теперь все страницы работают вместе. Давайте сделаем еще один шаг вперед и добавим специальную страницу 404 для всех продуктов, которые не найдены.

Настройка пользовательской страницы 404

Благодаря новой структуре приложения мы можем размещать вместе все наши относительные файлы. В этом случае, если нам нужна пользовательская страница 404, мы можем добавить шаблон not-found.jsx в каталог /products/[slug].

Файл будет экспортировать серверный (или клиентский) компонент, и на данный момент у нас будет очень простое сообщение. В данном случае, поскольку мы ищем продукт, давайте уточним и скажем «Товар не найден» вместо простого «Страница не найдена».

export default function NotFound() {

    return (
        <>
            <h1>404</h1>
            <p>Product not found</p>
        </>
    )
}

Теперь перейдите к маршруту, который не соответствует ни одной пуле в Hygraph:
http://localhost:3000/products/sdlfkjl/

Вместо страницы 404 мы получаем необработанную ошибку. Это потому, что нам нужно сообщить Next, когда мы знаем, что он не найден. В этом случае, если наш запрос к Hygraph не возвращает результатов, нам нужно выдать ошибку 404.

После вызова функции getProduct() мы можем проверить, определен ли продукт, и если нет, запустить функцию notFound() из next/navigation. Это кое-что сделает для нас. Он перенаправит браузер на компонент NotFound и автоматически добавит к этим маршрутам метатег noindex. Это хорошая практика SEO, которая предотвратит индексацию страниц 404 вашего сайта поисковыми системами.

export default async function Page({params}) {
    const product = await getProduct(params)

    if (!product) notFound()

    return (
        <>
            <h1>{product.name}</h1>
            <p>{product.description}</p>
            <p>{product.price}</p>
        </>
    )
}

Теперь у нас есть полнофункциональная страница 404!

Отсюда вы можете удалить каталог /pages и перейти к работе над своим приложением. Вы по-прежнему будете использовать каталог страниц для своих маршрутов API, а также для любых статических маршрутов, которые захотите использовать, но большинство вещей можно использовать в этой новой, более мощной версии Next.

Следующие шаги

Мы полностью преобразовали наш простой пример Hygraph Next.js из /pages в /app. На этом этапе я бы предложил взглянуть на все различные типы файлов, которые вы можете создавать в совмещенных каталогах.

  • Добавьте файл head.jsx, чтобы указать метаданные, такие как заголовок, описание и т. д. для каждой страницы продукта.
  • Добавьте файл loading.jsx для загрузки страницы для более длинных запросов.
  • Добавьте файл error.jsx для обработки других типов ошибок.

Источник:

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу