1. Подготовка
В этой практической работе вы узнаете, как интегрировать Firebase с веб-приложением Next.js под названием Friendly Eats, которое представляет собой сайт с отзывами о ресторанах.

Готовое веб-приложение предлагает полезные функции, которые демонстрируют, как Firebase может помочь вам создавать приложения Next.js. К ним относятся:
- Автоматическая сборка и развертывание. В этой практической работе используется Firebase App Hosting для автоматической сборки и развертывания кода Next.js при каждой отправке в настроенную ветку.
- Вход и выход. В готовом веб-приложении можно войти с аккаунтом Google и выйти из него. Вход пользователей и сохранение данных полностью управляются через Firebase Authentication.
- Изображения. В готовом веб-приложении пользователи, выполнившие вход, могут загружать изображения ресторанов. Объекты изображений хранятся в Cloud Storage for Firebase. Firebase JavaScript SDK предоставляет общедоступный URL для загруженных изображений. Затем этот общедоступный URL сохраняется в соответствующем документе ресторана в Cloud Firestore.
- Отзывы. В готовом веб-приложении пользователи, вошедшие в аккаунт, могут оставлять отзывы о ресторанах, состоящие из оценки и текстового сообщения. Информация об отзывах хранится в Cloud Firestore.
- Фильтры. Готовое веб-приложение позволяет вошедшим в систему пользователям фильтровать список ресторанов по категории, местоположению и цене. Вы также можете настроить метод сортировки. Доступ к данным осуществляется из Cloud Firestore, а запросы Firestore применяются на основе используемых фильтров.
Требования
- аккаунт GitHub;
- Знание Next.js и JavaScript.
Функции, которые вы освоите:
- Как использовать Firebase с App Router в Next.js и обработкой на стороне сервера.
- Как сохранять изображения в Cloud Storage for Firebase.
- Как читать и записывать данные в базе данных Cloud Firestore.
- Как использовать вход с аккаунтом Google с Firebase JavaScript SDK.
Что вам понадобится
- Git
- Последняя стабильная версия Node.js.
- Браузер, например Google Chrome.
- Среда разработки с редактором кода и терминалом.
- Аккаунт Google для создания проекта Firebase и управления им.
- Возможность перейти на тарифный план Blaze в проекте Firebase.
2. Как настроить среду разработки и хранилище GitHub
В этой практической работе используется начальная база кода приложения и интерфейс командной строки Firebase.
Создайте хранилище GitHub
Исходный код практической работы можно найти на странице https://github.com/firebase/friendlyeats-web. В репозитории содержатся примеры проектов для нескольких платформ. Однако в этой практической работе используется только каталог nextjs-start. Обратите внимание на следующие каталоги:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
Скопируйте папку nextjs-start в свое хранилище:
- В терминале создайте на компьютере новую папку и перейдите в нее:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web - Используйте пакет npm giget, чтобы получить только папку
nextjs-start:npx giget@latest "gh:firebase/friendlyeats-web/nextjs-start#master" . --install - Отслеживайте изменения локально с помощью git:
git init git add . git commit -m "Codelab starting point" git branch -M main - Создайте новый репозиторий GitHub: https://github.com/new. Название может быть любым.
- В зависимости от того, как вы выполняете аутентификацию в GitHub (HTTPS или SSH), скопируйте новый URL, созданный GitHub:
https://github.com/<USER_NAME>/<REPOSITORY_NAME>.gitилиgit@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
- Отправьте локальные изменения в новое хранилище GitHub, выполнив следующую команду: Замените плейсхолдер
<REPOSITORY_URL>на URL своего хранилища.git remote add origin <REPOSITORY_URL> git push -u origin main - Теперь вы должны увидеть заготовку кода в своем репозитории GitHub.
Установите или обновите интерфейс командной строки Firebase
Выполните следующую команду, чтобы проверить, установлен ли у вас интерфейс командной строки Firebase и соответствует ли он версии 14.1.0 или более поздней:
firebase --version
Если у вас более ранняя версия или интерфейс командной строки Firebase не установлен, выполните команду установки:
npm install -g firebase-tools@latest
Если вам не удается установить интерфейс командной строки Firebase из-за ошибок, связанных с разрешениями, ознакомьтесь с документацией по npm или воспользуйтесь другим вариантом установки.
Войдите в Firebase.
- Чтобы войти в интерфейс командной строки Firebase, выполните следующую команду:
firebase login
- В зависимости от того, хотите ли вы, чтобы Firebase собирал данные, введите
YилиN. - В браузере выберите аккаунт Google и нажмите Разрешить.
3. Как настроить проект Firebase
В этом разделе вы настроите проект Firebase и свяжете с ним веб-приложение Firebase. Вы также настроите сервисы Firebase, используемые примером веб-приложения.
Создать проект Firebase
- Войдите в консоль Firebase, используя тот же аккаунт Google, что и на предыдущем шаге.
- Нажмите кнопку, чтобы создать проект, и введите его название, например
FriendlyEats Codelab.
- Нажмите Продолжить.
- Если появится запрос, прочитайте и примите Условия использования Firebase, а затем нажмите Продолжить.
- (Необязательно.) Включите помощь от ИИ в консоли Firebase (Gemini в Firebase).
- Для этой практической работы Google Аналитика не нужна, поэтому отключите ее.
- Нажмите Создать проект, дождитесь его инициализации и нажмите Продолжить.
Как перейти на другой тарифный план Firebase
Чтобы использовать Firebase App Hosting и Cloud Storage for Firebase, ваш проект Firebase должен быть на тарифном плане Blaze с оплатой по мере использования, то есть связан с платежным аккаунтом Cloud.
- Для платежного аккаунта Cloud требуется способ оплаты, например кредитная карта.
- Если вы раньше не работали с Firebase и Google Cloud, проверьте, можете ли вы получить бонус в размере 300 долларов США и бесплатный пробный платежный аккаунт Cloud.
- Если вы выполняете эту практическую работу в рамках мероприятия, спросите у организатора, доступны ли бонусы Cloud.
Чтобы перейти на тарифный план Blaze, выполните следующие действия:
- В консоли Firebase выберите смену тарифного плана.
- Выберите тарифный план Blaze. Следуйте инструкциям на экране, чтобы связать платежный аккаунт Cloud со своим проектом.
Если в рамках этого обновления вам нужно было создать платежный аккаунт Cloud, возможно, вам потребуется вернуться к процессу обновления в консоли Firebase, чтобы завершить его.
Как добавить веб-приложение в проект Firebase
- В проекте Firebase перейдите в раздел Обзор проекта, нажмите Добавить приложение и выберите Веб.
- В текстовом поле Псевдоним приложения введите запоминающееся название, например
My Next.js app. - Не устанавливайте флажок Также настроить Firebase Hosting для этого приложения.
- Нажмите Register app (Зарегистрировать приложение) > Continue to console (Перейти в консоль).
Как настроить сервисы Firebase в консоли Firebase
Настроить аутентификацию
- На панели слева в консоли Firebase разверните раздел Build (Сборка) и выберите Authentication (Аутентификация).
- Нажмите Начать.
- В столбце Sign-in providers (Поставщики услуг входа) нажмите Google > Enable (Включить).
- В текстовом поле Общедоступное название проекта введите запоминающееся название, например
My Next.js app. - В раскрывающемся списке Support email for project (Адрес электронной почты службы поддержки для проекта) выберите свой адрес электронной почты.
- Нажмите Сохранить.
Как настроить Cloud Firestore
- На панели слева в консоли Firebase разверните раздел Build (Сборка) и выберите Firestore Database (База данных Firestore).
- Нажмите Создать базу данных.
- Выберите Стандартная версия и нажмите Далее.
- Не меняйте идентификатор базы данных, оставьте значение
(default). - Выберите местоположение базы данных и нажмите Далее.
Для реального приложения лучше выбрать местоположение, которое находится ближе к пользователям. - Нажмите Начать в тестовом режиме. Прочитайте отказ от обязательств, касающийся правил безопасности.
Позже в этой практической работе вы добавите правила безопасности, чтобы защитить свои данные. Не распространяйте и не публикуйте приложение, не добавив правила безопасности для базы данных. - Нажмите Создать.
Как настроить Cloud Storage for Firebase
- На панели слева в консоли Firebase разверните раздел Build (Сборка) и выберите Storage (Хранилище).
- Нажмите Начать.
- Выберите местоположение для сегмента хранилища по умолчанию.
Для сегментов в регионахUS-WEST1,US-CENTRAL1иUS-EAST1можно использовать бесплатный уровень Google Cloud Storage. Для сегментов во всех остальных местоположениях действуют тарифы и условия использования Google Cloud Storage. - Нажмите Начать в тестовом режиме. Прочитайте отказ от обязательств, касающийся правил безопасности.
Позже в этой практической работе вы добавите правила безопасности, чтобы защитить свои данные. Не распространяйте и не публикуйте приложение, не добавив правила безопасности для сегмента хранилища. - Нажмите Создать.
Развертывание правил безопасности
В коде уже есть наборы правил безопасности для Firestore и Cloud Storage for Firebase. После развертывания правил безопасности данные в базе данных и сегменте будут лучше защищены от ненадлежащего использования.
- В терминале настройте интерфейс командной строки для использования проекта Firebase, созданного ранее:
Когда появится запрос на ввод псевдонима, введитеfirebase use --add
friendlyeats-codelab. - Чтобы развернуть эти правила безопасности (а также индексы, которые понадобятся позже), выполните в терминале следующую команду:
firebase deploy --only firestore,storage
- Если появится вопрос
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?", нажмитеEnter, чтобы выбрать Да.
4. Изучите начальную базу кода
В этом разделе вы ознакомитесь с несколькими областями начальной базы кода приложения, в которые вы добавите функциональность в этой практической работе.
Структура папок и файлов
В таблице ниже приведен обзор структуры папок и файлов приложения.
Файлы и папки | Описание |
| Компоненты React для фильтров, заголовков, сведений о ресторанах и отзывов |
| Служебные функции, которые не обязательно привязаны к React или Next.js. |
| Код и конфигурация Firebase |
| Статические объекты в веб-приложении, например значки. |
| Маршрутизация с помощью Next.js App Router |
| Зависимости проекта с npm |
| Конфигурация для Next.js (действия сервера включены) |
| Конфигурация языкового сервиса JavaScript |
Серверные и клиентские компоненты
Это веб-приложение Next.js, в котором используется App Router. Отрисовка на стороне сервера используется во всем приложении. Например, файл src/app/page.js – это компонент сервера, отвечающий за главную страницу. Файл src/components/RestaurantListings.jsx – это клиентский компонент, обозначенный директивой "use client" в начале файла.
Операторы import
Вы можете увидеть инструкции импорта, подобные следующим:
import RatingPicker from "@/src/components/RatingPicker.jsx";
В приложении используется символ @, чтобы избежать громоздких относительных путей импорта. Это возможно благодаря псевдонимам путей.
API, относящиеся к Firebase
Весь код Firebase API находится в каталоге src/lib/firebase. Затем отдельные компоненты React импортируют упакованные функции из каталога src/lib/firebase, а не функции Firebase напрямую.
Фиктивные данные
Файл src/lib/randomData.js содержит макеты данных о ресторанах и отзывах. Данные из этого файла собираются в коде в файле src/lib/fakeRestaurants.js.
5. Как создать бэкенд App Hosting
В этом разделе вы настроите серверную часть App Hosting для отслеживания ветки в репозитории git.
К концу этого раздела у вас будет серверная часть App Hosting, подключенная к вашему репозиторию в GitHub, которая будет автоматически пересобирать и развертывать новую версию вашего приложения всякий раз, когда вы отправляете новый коммит в свою ветку main.
Создание серверной ВМ
- В консоли Firebase перейдите на страницу App Hosting.
- Нажмите Начать, чтобы запустить процесс создания бэкенда.
- Выберите регион. Для реального приложения выберите регион, ближайший к вашим пользователям.
- Следуйте инструкциям на шаге Импорт репозитория GitHub, чтобы настроить аутентификацию GitHub.
- В разделе Repository (Хранилище) выберите Grant access to a new repository in GitHub (Предоставить доступ к новому хранилищу в GitHub) и следуйте инструкциям, чтобы разрешить доступ к хранилищу GitHub, которое вы создали ранее.
- Нажмите Обновить список, выберите хранилище и нажмите Далее.
- Задайте настройки развертывания:
- Установите для активной ветви значение
main. - Оставьте корневой каталог
/. - Включите автоматическое развертывание.
- Установите для активной ветви значение
- Укажите название бэкенда
friendlyeats-codelabи нажмите Далее. - В разделе Связать веб-приложение Firebase выберите Выбрать существующее веб-приложение Firebase и укажите добавленное приложение из списка.
- Нажмите Завершить и развернуть. Вы будете перенаправлены на новую страницу, где можно посмотреть статус нового бэкенда App Hosting.
- Нажмите View (Посмотреть), чтобы узнать больше о развертывании App Hosting, в том числе о статусе внедрения, журналах и сведениях об использовании.
- После завершения развертывания нажмите на URL сайта в разделе Domains (Домены). Из-за распространения DNS изменения могут вступить в силу через несколько минут.
- Ой-ой! При загрузке страницы вы увидите сообщение об ошибке: "Ошибка приложения: возникло исключение на стороне сервера (дополнительную информацию см. в журналах сервера)".
- В консоли Firebase откройте вкладку Logs (Журналы) для серверной части App Hosting. Вы увидите запись в журнале "Error: not implemented" (Ошибка: не реализовано). Мы исправим это на следующем шаге, когда добавим аутентификацию.
Вы развернули начальное веб-приложение. Каждый раз, когда вы отправляете новый коммит в ветку main репозитория GitHub, в консоли Firebase будет начинаться новая сборка и развертывание, а ваш сайт будет автоматически обновляться после завершения развертывания.
6. Добавление аутентификации в веб-приложение
В этом разделе вы добавите в веб-приложение аутентификацию, чтобы в него можно было войти.
Добавьте авторизованный домен.
Firebase Authentication будет принимать запросы на вход только из разрешенных доменов. Здесь мы добавим домен бэкенда App Hosting в список одобренных доменов в вашем проекте.
- Откройте страницу App Hosting и нажмите View (Посмотреть) под развернутым сайтом, чтобы перейти на страницу Overview (Обзор). Скопируйте доменное имя бэкенда App Hosting.
- Перейдите на вкладку Auth Settings (Настройки аутентификации) и выберите проект, в который нужно добавить авторизованный домен. Затем найдите раздел Authorized Domains (Авторизованные домены) и нажмите на него.
- Нажмите кнопку Добавить домен.
- Введите домен бэкенда App Hosting.
- Нажмите Добавить.
Реализуйте функции входа и выхода
В файле src/lib/firebase/auth.js замените функции onAuthStateChanged, onIdTokenChanged, signInWithGoogle и signOut следующим кодом:
export function onAuthStateChanged(cb) {
return _onAuthStateChanged(auth, cb);
}
export function onIdTokenChanged(cb) {
return _onIdTokenChanged(auth, cb);
}
export async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
try {
await signInWithPopup(auth, provider);
} catch (error) {
console.error("Error signing in with Google", error);
}
}
export async function signOut() {
try {
return auth.signOut();
} catch (error) {
console.error("Error signing out with Google", error);
}
}
В этом коде используются следующие API Firebase:
Firebase API | Описание |
Добавляет наблюдателя за изменениями статуса входа пользователя. | |
Добавляет наблюдателя за изменениями токена идентификатора пользователя. | |
Создает экземпляр поставщика аутентификации Google. | |
Запускает процесс аутентификации на основе диалогового окна. | |
Выход из аккаунта. |
В файле src/components/Header.jsx код уже вызывает функции signInWithGoogle и signOut.
Отправка статуса аутентификации на сервер
Чтобы передать статус аутентификации на сервер, мы будем использовать файлы cookie. При каждом изменении статуса аутентификации в клиенте мы будем обновлять файл cookie __session.
В файле src/components/Header.jsx замените функцию useUserSession следующим кодом:
function useUserSession(initialUser) {
useEffect(() => {
return onIdTokenChanged(async (user) => {
if (user) {
const idToken = await user.getIdToken();
await setCookie("__session", idToken);
} else {
await deleteCookie("__session");
}
if (initialUser?.uid === user?.uid) {
return;
}
window.location.reload();
});
}, [initialUser]);
return initialUser;
}
Чтение состояния аутентификации на сервере
Мы будем использовать FirebaseServerApp, чтобы отразить статус аутентификации клиента на сервере.
Откройте файл src/lib/firebase/serverApp.js и замените функцию getAuthenticatedAppForUser:
export async function getAuthenticatedAppForUser() {
const authIdToken = (await cookies()).get("__session")?.value;
// Firebase Server App is a new feature in the JS SDK that allows you to
// instantiate the SDK with credentials retrieved from the client & has
// other affordances for use in server environments.
const firebaseServerApp = initializeServerApp(
// https://github.com/firebase/firebase-js-sdk/issues/8863#issuecomment-2751401913
initializeApp(),
{
authIdToken,
}
);
const auth = getAuth(firebaseServerApp);
await auth.authStateReady();
return { firebaseServerApp, currentUser: auth.currentUser };
}
Подтвердить изменения
Корневой макет в файле src/app/layout.js отображает заголовок и передает пользователя, если он доступен, в качестве свойства.
<Header initialUser={currentUser?.toJSON()} />
Это означает, что компонент <Header> отображает пользовательские данные, если они доступны, во время работы сервера. Если в течение жизненного цикла страницы после ее первоначальной загрузки происходят какие-либо обновления аутентификации, их обрабатывает обработчик onAuthStateChanged.
Теперь нужно выпустить новую сборку и проверить, что у вас получилось.
- Создайте коммит с сообщением "Add authentication" и отправьте его в репозиторий GitHub.
git add . git commit -m "Add authentication" git push - Откройте страницу App Hosting и, когда развертывание будет завершено, нажмите на URL сайта, чтобы открыть его.
- Проверьте аутентификацию:
- Войдите в аккаунт Google и убедитесь, что ваше отображаемое имя появилось в заголовке.
- Выйдите и снова войдите в аккаунт. Вы можете повторить этот шаг для разных пользователей.
- При необходимости нажмите правой кнопкой мыши на веб-приложение, выберите Просмотр кода страницы и найдите отображаемое название. Он присутствует в исходном HTML-коде, полученном от сервера.
7. Посмотреть информацию о ресторане
Веб-приложение включает фиктивные данные для ресторанов и отзывов.
Добавьте один или несколько ресторанов
Чтобы вставить макет данных ресторана в локальную базу данных Cloud Firestore, выполните следующие действия:
- Войдите в веб-приложение, если вы ещё этого не сделали. Затем нажмите
> Добавить примеры ресторанов. Обратите внимание, что в веб-приложении Friendly Eats не отображаются рестораны, поскольку мы ещё не настроили код получения данных. Мы исправим это на следующем шаге. - В консоли Firebase на странице База данных Firestore выберите restaurants. Вы увидите документы верхнего уровня в коллекции ресторанов, каждый из которых представляет ресторан.
- Нажмите на несколько документов, чтобы изучить свойства документа ресторана.
Показать список ресторанов
Теперь в базе данных Cloud Firestore есть рестораны, которые может показывать веб-приложение Next.js.
Чтобы определить код для получения данных, выполните следующие действия:
- В файле
src/app/page.jsнайдите серверный компонент<Home />и проверьте вызов функцииgetRestaurants, которая получает список ресторанов во время работы сервера. ФункцияgetRestaurantsреализуется следующим образом: - В файле
src/lib/firebase/firestore.jsзамените функцииapplyQueryFiltersиgetRestaurantsследующим кодом:
function applyQueryFilters(q, { category, city, price, sort }) {
if (category) {
q = query(q, where("category", "==", category));
}
if (city) {
q = query(q, where("city", "==", city));
}
if (price) {
q = query(q, where("price", "==", price.length));
}
if (sort === "Rating" || !sort) {
q = query(q, orderBy("avgRating", "desc"));
} else if (sort === "Review") {
q = query(q, orderBy("numRatings", "desc"));
}
return q;
}
export async function getRestaurants(db = db, filters = {}) {
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const results = await getDocs(q);
return results.docs.map((doc) => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
}
- Создайте коммит с сообщением "Read the list of restaurants from Firestore" (Прочитать список ресторанов из Firestore) и отправьте его в хранилище GitHub.
git add . git commit -m "Read the list of restaurants from Firestore" git push - Откройте страницу App Hosting в консоли Firebase и дождитесь завершения развертывания.
- Обновите страницу в веб-приложении. Изображения ресторана показаны в виде плиток на странице.
Убедитесь, что данные о ресторанах загружаются во время работы сервера.
При использовании фреймворка Next.js может быть не очевидно, когда данные загружаются во время выполнения на сервере или на клиентской стороне.
Чтобы убедиться, что данные о ресторанах загружаются во время работы сервера, выполните следующие действия:
- В веб-приложении откройте Инструменты разработчика и отключите JavaScript.

- Обновите веб-приложение. Список ресторанов по-прежнему загружается. Информация о ресторане возвращается в ответе сервера. Если JavaScript включен, информация о ресторане гидратируется с помощью клиентского кода JavaScript.
- В инструментах разработчика снова включите JavaScript.
Прослушивание обновлений ресторанов с помощью прослушивателей снимков Cloud Firestore
В предыдущем разделе вы увидели, как из файла src/app/page.js загружается исходный набор ресторанов. Файл src/app/page.js – это серверный компонент, который обрабатывается на сервере, включая код Firebase для получения данных.
Файл src/components/RestaurantListings.jsx – это клиентский компонент, который можно настроить для гидратации разметки, созданной сервером.
Чтобы настроить файл src/components/RestaurantListings.jsx для гидратации разметки, созданной на сервере, выполните следующие действия:
- В файле
src/components/RestaurantListings.jsxнайдите следующий код:
useEffect(() => {
return getRestaurantsSnapshot((data) => {
setRestaurants(data);
}, filters);
}, [filters]);
Этот код вызывает функцию getRestaurantsSnapshot(), которая похожа на функцию getRestaurants(), реализованную на предыдущем шаге. Однако эта функция snapshot предоставляет механизм обратного вызова, поэтому обратный вызов вызывается каждый раз, когда в коллекцию ресторана вносятся изменения.
- В файле
src/lib/firebase/firestore.jsзамените функциюgetRestaurantsSnapshot()следующим кодом:
export function getRestaurantsSnapshot(cb, filters = {}) {
if (typeof cb !== "function") {
console.log("Error: The callback parameter is not a function");
return;
}
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
return onSnapshot(q, (querySnapshot) => {
const results = querySnapshot.docs.map((doc) => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
cb(results);
});
}
- В файле
src/lib/firebase/firestore.jsзамените функциюgetRestaurantSnapshotById()следующим кодом:
export function getRestaurantSnapshotById(restaurantId, cb) {
if (!restaurantId) {
console.log("Error: Invalid ID received: ", restaurantId);
return;
}
if (typeof cb !== "function") {
console.log("Error: The callback parameter is not a function");
return;
}
const docRef = doc(db, "restaurants", restaurantId);
return onSnapshot(docRef, (docSnap) => {
cb({
...docSnap.data(),
timestamp: docSnap.data().timestamp.toDate(),
});
});
}
Изменения, внесенные на странице База данных Firestore, теперь отражаются в веб-приложении в реальном времени.
- Создайте коммит с сообщением "Listen for realtime restaurant updates" и отправьте его в репозиторий GitHub.
git add . git commit -m "Listen for realtime restaurant updates" git push - Откройте страницу App Hosting в консоли Firebase и дождитесь завершения развертывания.
- В веб-приложении нажмите
> Добавить примеры ресторанов. Если функция snapshot реализована правильно, рестораны появляются в режиме реального времени без обновления страницы.
8. Сохранять отзывы, отправленные пользователями из веб-приложения
- В файле
src/lib/firebase/firestore.jsзамените функциюupdateWithRating()следующим кодом:
const updateWithRating = async (
transaction,
docRef,
newRatingDocument,
review
) => {
const restaurant = await transaction.get(docRef);
const data = restaurant.data();
const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
const newSumRating = (data?.sumRating || 0) + Number(review.rating);
const newAverage = newSumRating / newNumRatings;
transaction.update(docRef, {
numRatings: newNumRatings,
sumRating: newSumRating,
avgRating: newAverage,
});
transaction.set(newRatingDocument, {
...review,
timestamp: Timestamp.fromDate(new Date()),
});
};
Этот код вставляет новый документ Firestore, представляющий новый отзыв. Код также обновляет существующий документ Firestore, который представляет ресторан, с обновленными цифрами количества оценок и средней рассчитанной оценки.
- Замените функцию
addReviewToRestaurant()следующим кодом:
export async function addReviewToRestaurant(db, restaurantId, review) {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!review) {
throw new Error("A valid review has not been provided.");
}
try {
const docRef = doc(collection(db, "restaurants"), restaurantId);
const newRatingDocument = doc(
collection(db, `restaurants/${restaurantId}/ratings`),
);
// corrected line
await runTransaction(db, (transaction) =>
updateWithRating(transaction, docRef, newRatingDocument, review),
);
} catch (error) {
console.error(
"There was an error adding the rating to the restaurant",
error,
);
throw error;
}
}
Реализация действия сервера Next.js
Next.js Server Action предоставляет удобный API для доступа к данным формы, например data.get("text") для получения текстового значения из полезной нагрузки отправки формы.
Чтобы использовать действие сервера Next.js для обработки отправки формы отзыва, выполните следующие действия:
- В файле
src/components/ReviewDialog.jsxнайдите атрибутactionв элементе<form>.
<form
action={handleReviewFormSubmission}
onSubmit={() => {
handleClose();
}}
>
Значение атрибута action относится к функции, которую вы реализуете на следующем шаге.
- В файле
src/app/actions.jsзамените функциюhandleReviewFormSubmission()следующим кодом:
export async function handleReviewFormSubmission(data) {
const { firebaseServerApp } = await getAuthenticatedAppForUser();
const db = getFirestore(firebaseServerApp);
await addReviewToRestaurant(db, data.get("restaurantId"), {
text: data.get("text"),
rating: data.get("rating"),
// This came from a hidden form field.
userId: data.get("userId"),
});
}
Добавьте отзывы о ресторане
Вы реализовали поддержку отправки отзывов, поэтому теперь вы можете убедиться, что ваши отзывы правильно вставляются в Cloud Firestore.
Чтобы добавить отзыв и убедиться, что он вставлен в Cloud Firestore, выполните следующие действия:
- Создайте коммит с сообщением "Allow users to submit restaurant reviews" и отправьте его в репозиторий GitHub.
git add . git commit -m "Allow users to submit restaurant reviews" git push - Откройте страницу App Hosting в консоли Firebase и дождитесь завершения развертывания.
- Обновите веб-приложение и выберите ресторан на главной странице.
- На странице ресторана нажмите
. - Выберите оценку.
- Напишите отзыв.
- Нажмите Отправить. Ваш отзыв появится вверху списка.
- В Cloud Firestore на панели Add document (Добавить документ) найдите и выберите документ ресторана, для которого вы оставили отзыв.
- На панели Начать сбор выберите Оценки.
- На панели Добавить документ найдите документ, который вы хотите проверить, и убедитесь, что он был вставлен правильно.
9. Сохраните файлы, загруженные пользователями из веб-приложения
В этом разделе вы добавите функцию, которая позволит заменять изображение, связанное с рестораном, когда вы вошли в систему. Вы загружаете изображение в Firebase Storage и обновляете URL изображения в документе Cloud Firestore, который представляет ресторан.
Чтобы сохранить файлы, загруженные пользователями из веб-приложения, выполните следующие действия:
- В файле
src/components/Restaurant.jsxнайдите код, который выполняется, когда пользователь загружает файл:
async function handleRestaurantImage(target) {
const image = target.files ? target.files[0] : null;
if (!image) {
return;
}
const imageURL = await updateRestaurantImage(id, image);
setRestaurantDetails({ ...restaurantDetails, photo: imageURL });
}
Вносить изменения в эту функцию не нужно, но на следующих шагах вы реализуете поведение функции updateRestaurantImage().
- В файле
src/lib/firebase/storage.jsзамените функцииupdateRestaurantImage()иuploadImage()следующим кодом:
export async function updateRestaurantImage(restaurantId, image) {
try {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!image || !image.name) {
throw new Error("A valid image has not been provided.");
}
const publicImageUrl = await uploadImage(restaurantId, image);
await updateRestaurantImageReference(restaurantId, publicImageUrl);
return publicImageUrl;
} catch (error) {
console.error("Error processing request:", error);
}
}
async function uploadImage(restaurantId, image) {
const filePath = `images/${restaurantId}/${image.name}`;
const newImageRef = ref(storage, filePath);
await uploadBytesResumable(newImageRef, image);
return await getDownloadURL(newImageRef);
}
Функция updateRestaurantImageReference() уже реализована. Эта функция обновляет существующий документ ресторана в Cloud Firestore, добавляя в него обновленный URL изображения.
Проверьте функцию загрузки изображений
Чтобы убедиться, что изображение загружается правильно, выполните следующие действия:
- Создайте коммит с сообщением "Allow users to change each restaurants' photo" и отправьте его в репозиторий GitHub.
git add . git commit -m "Allow users to change each restaurants' photo" git push - Откройте страницу App Hosting в консоли Firebase и дождитесь завершения развертывания.
- В веб-приложении убедитесь, что вы вошли в аккаунт, и выберите ресторан.
- Нажмите
и загрузите изображение из файловой системы. Образ покидает локальную среду и загружается в Cloud Storage. Изображение появится сразу после загрузки. - Перейдите в Cloud Storage для Firebase.
- Перейдите в папку, которая представляет ресторан. Загруженное изображение находится в папке.

10. Краткий пересказ отзывов о ресторане с помощью генеративного искусственного интеллекта
В этом разделе вы добавите функцию сводки отзывов, чтобы пользователь мог быстро понять, что все думают о ресторане, не читая каждый отзыв.
Как сохранить ключ Gemini API в Cloud Secret Manager
- Чтобы использовать Gemini API, вам понадобится ключ API. Перейдите в Google AI Studio и нажмите Create API Key (Создать ключ API).
- Укажите любое название ключа. Если вашего проекта нет в списке Выберите импортированный проект, нажмите Импортировать проект, выберите проект в списке и нажмите Импортировать. Затем выберите его в разделе Выберите импортированный проект и нажмите Создать ключ.
- App Hosting интегрируется с Cloud Secret Manager, что позволяет безопасно хранить конфиденциальные данные, например ключи API.
- В терминале выполните команду, чтобы создать секрет:
firebase apphosting:secrets:set GEMINI_API_KEY- Когда появится запрос на ввод секретного значения, скопируйте и вставьте ключ Gemini API из Google AI Studio.
- Когда появится вопрос о том, для чего предназначен новый секретный ключ, выберите "Рабочая версия".
- Когда появится запрос на предоставление доступа к секрету сервисному аккаунту серверной части, выберите "Да".
- Когда появится запрос на добавление нового секрета в
apphosting.yaml, введитеY, чтобы принять.
Теперь ваш ключ Gemini API надежно хранится в Cloud Secret Manager и доступен для серверной части App Hosting.
Как реализовать компонент сводки отзывов
- В файле
src/components/Reviews/ReviewSummary.jsxзамените функциюGeminiSummaryследующим кодом:export async function GeminiSummary({ restaurantId }) { const { firebaseServerApp } = await getAuthenticatedAppForUser(); const reviews = await getReviewsByRestaurantId( getFirestore(firebaseServerApp), restaurantId ); const reviewSeparator = "@"; const prompt = ` Based on the following restaurant reviews, where each review is separated by a '${reviewSeparator}' character, create a one-sentence summary of what people think of the restaurant. Here are the reviews: ${reviews.map((review) => review.text).join(reviewSeparator)} `; try { if (!process.env.GEMINI_API_KEY) { // Make sure GEMINI_API_KEY environment variable is set: // https://genkit.dev/docs/get-started/ throw new Error( 'GEMINI_API_KEY not set. Set it with "firebase apphosting:secrets:set GEMINI_API_KEY"' ); } // Configure a Genkit instance. const ai = genkit({ plugins: [googleAI()], model: gemini20Flash, // set default model }); const { text } = await ai.generate(prompt); return ( <div className="restaurant__review_summary"> <p>{text}</p> <p>✨ Summarized with Gemini</p> </div> ); } catch (e) { console.error(e); return <p>Error summarizing reviews.</p>; } } - Создайте коммит с сообщением "Use AI to summarize reviews" и отправьте его в репозиторий GitHub.
git add . git commit -m "Use AI to summarize reviews" git push - Откройте страницу App Hosting в консоли Firebase и дождитесь завершения развертывания.
- Откройте страницу ресторана. В верхней части страницы вы увидите краткий пересказ всех отзывов.
- Добавьте новый отзыв и обновите страницу. Вы увидите, что сводка изменилась.
11. Как отменить публикацию сайта, опубликованного с помощью App Hosting
Если вы не планируете использовать приложение после завершения этой практической работы, вы можете отменить его публикацию, чтобы никто не мог получить доступ к вашим ресурсам Firestore, Storage и Gemini. Вы можете в любое время опубликовать издание снова.
Чтобы отменить публикацию сайта, размещенного с помощью App Hosting, выполните следующие действия:
- Откройте App Hosting в консоли Firebase.
- Найдите серверную часть приложения и нажмите View (Посмотреть).
- В разделе Информация о серверной части рядом с пунктом Домены нажмите Управление. Откроется страница Domains (Домены).
- Рядом с доменом нажмите на значок Ещё (три вертикальные точки), выберите Отключить домен, а затем нажмите Отключить для подтверждения.
12. Заключение
Поздравляем! Вы узнали, как использовать Firebase для добавления функций и возможностей в приложение Next.js. В частности, вы использовали следующее:
- Firebase App Hosting для автоматической сборки и развертывания кода Next.js при каждой отправке в настроенную ветку.
- Firebase Authentication для входа и выхода.
- Cloud Firestore для данных о ресторанах и отзывах о них.
- Cloud Storage for Firebase для изображений ресторанов.