Как установить переменные конфигурации в Next.js

Представьте себе следующий сценарий: вы - фронтенд-разработчик в NPM, Inc. (отличная работа, поздравляю!). Ваша задача на сегодня - отображать текущую версию пакетов на их целевой странице.

Эта версия находится в файле package.json. Но, конечно, вы знаете, что из соображений безопасности нельзя импортировать package.json во внешний интерфейс. Это может привести к утечке некоторой секретной информации, например, списка ваших пакетов разработки. Вы хотите, чтобы клиентский код имел доступ только к общедоступной информации, такой как версия приложения или лицензия.

Решить эту проблему на удивление… не так просто. Давайте посмотрим, как можно безопасно достичь этой цели в контексте приложения Next.js.

TL; DR: внизу этой статьи есть сводная таблица. Методы 1), 4) и 5) являются наиболее подходящими, остальные можно пропустить.

В качестве примера я использую номер версии package.json. Описанные здесь шаблоны применимы к любому виду глобальной переменной конфигурации: обработка ключей API для Stripe, установка URL-адреса вашего приложения, реализация «флагов функций» и т. Д.

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

Начнем с простейшего шаблона.

1) Импортировать значение из файла

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

Если некоторые значения являются динамическими, просто используйте код JavaScript для их вычисления.

Пример: export const config = { foo: 42 };, а затем import { config } from "config";

Вы даже можете сгенерировать файл JSON, используя собственный скрипт. Сценарий с именем prebuild в вашем package.json всегда будет запускаться до build. Это хорошее место для создания файла конфигурации до начала сборки Next.js.

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

2) Получение данных

Просто для записи: у вас всегда есть возможность сделать свою ценность доступной через API и запросить ее. Так же, как и с любыми другими данными (сообщения в блогах, изображения, список пользователей…).

2.1) Получение значения в интерфейсе пользователя из API

Просто запросите значение, как обычно, в React, используя fetch или что-то еще, и поместите значение в контекст React.

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

2.2) Через Next.js getStaticProps, getInitialProps, getServerRenderProps

Если вы хотите запросить его во время рендеринга на стороне сервера или статической генерации, вы можете использовать встроенные методы Next.js для выборки данных.

Получите значение в getStaticProps (или getInitialProps) и передайте его в качестве свойств страницы или приложения. Затем вы можете поместить его в контекст React, если вам нужно передать его по дереву React.

Документация: https://nextjs.org/docs/basic-features/data-fetching

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

3) Конфигурация среды выполнения Next.js (следует избегать)

Вы можете подумать, что Next.js «конфигурация времени выполнения» - хорошее место для размещения компонентов конфигурации. Вздох, ты будешь разочарован.

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

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

Проблема заключается в части «времени выполнения»: эти конфигурации несовместимы с автоматической статической оптимизацией (рендеринг первой версии вашей страницы во время сборки), что вам определенно нужно.

Вместо конфигурации среды выполнения вы можете использовать простой объект конфигурации, см. Первый шаблон этой статьи.

Документация: https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration

Давайте посмотрим на шаблон, рекомендованный Next: установка переменных в .env файлах.

4) Установка переменной окружения в .env файле

Это рекомендуемый способ управления техническими переменными среды. Next.js может сразу обрабатывать .env файлов, что довольно удобно.

Существует 2 типа переменных: общедоступные переменные с префиксом NEXT_PUBLIC_ и переменные только для сервера.

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

На стороне клиента поведение более сложное. Публичные переменные будут добавлены в клиентский пакет во время сборки. В основном они заменяются в коде своим значением: например instanceprocess.env.NEXT_PUBLIC_42 буквально становится 42.

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

Если ваше значение сильно меняется, вы можете вместо этого получить его динамически, используя некоторый код JavaScript или вызов API, см. Шаблон 1 и 2.

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

Документация: https://nextjs.org/docs/basic-features/environment-variables

Поскольку этот шаблон ограничен заранее известными статическими переменными, он не работает в нашем варианте использования. Мы не можем получить самую последнюю package.json версию автоматически. Следующий шаблон окончательно решит эту проблему элегантно.

5) Установка переменной окружения в next.config.js env object

Проблема с .env файлами в том, что они не являются файлами JavaScript: вы не можете вычислить переменную динамически.

Для обработки динамических переменных вам необходимо установить объект env в next.config.js. Этот файл запускается во время сборки на вашем сервере сборки, поэтому это безопасное место даже для манипулирования личными данными, такими как содержимое package.json.

Этот подход задокументирован как «старый» шаблон, но он полностью оправдан для очень конкретного случая использования, когда вам необходимо динамически вычислять переменную во время сборки.

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

Тада! 🎉

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

Документация: https://nextjs.org/docs/api-reference/next.config.js/environment-variables.

У него есть несколько ограничений, в основном он может обрабатывать только строковые значения. Кроме того, значения вводятся во время сборки только для клиента, точно так же, как для .env файлов в шаблоне 4.

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

6) Вводить переменные во время сборки с помощью Webpack DefinePlugin

Этот подход основан на внедрении кода: он буквально изменяет ваш код, чтобы внедрить в него ваши значения, используя Webpack DefinePlugin. Это похоже на то, как Next.js обрабатывает process.env клиентскую часть изнутри.

Преимущество по сравнению с обычными process.env переменными заключается в том, что вы можете передавать любое сериализуемое значение: строки, числа, объекты JSON (с использованием JSON.stringify) и т. Д.

Кроме того, он позволяет вам устанавливать разные значения на стороне клиента и на стороне сервера для одной и той же переменной. Когда Next.js создает ваше приложение, он дважды читает next.config.js с разными параметрами, один раз для настройки сервера и второй раз для сборки клиента. Следовательно, вы можете сделать что-то вроде этого, чтобы установить переменную «IS_SERVER»:

Документация: https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config

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

Бонусное обновление (09/2021)

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

  • Node-config позволяет настроить конфигурацию на основе файлов. Я не тестировал, но он напоминает мне систему настроек Meteor, и это здорово.
  • React-env позволяет переключать общедоступные (клиентские) переменные среды во время выполнения, а не только во время сборки. Это замечательно, если вы хотите, например, переключить URL-адрес своего сервера, не перестраивая все приложение. Требуется только перезагрузка.

Резюме и пример из жизни

Большой! Теперь вы знаете все шаблоны для доступа к данным конфигурации в Next.js.

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

Вот вам окончательное резюме:

Спасибо, что прочитали эту статью! Если вам понравилось, найдите минутку, чтобы познакомиться с нашей инфраструктурой Next.js и GraphQL, VulcanNext.

Приложение: билеты, которые побудили меня написать эту статью