Что нового в Strapi 5. Спойлер: стало лучше
Всем привет! Меня зовут Александр, я фронтенд-разработчик в KTS.
Не так давно я уже рассказывал про Strapi — одно из ведущих опенсорсных headless CMS-решений, которое на протяжении долгого времени пользуется большой популярностью у разработчиков. Чуть больше месяца назад разработчики системы представили обновленную версию, и в этой статье я расскажу о фишках, которые появились в Strapi 5.
Неважно, переходите вы на Strapi 5 с предыдущей версии или только начинаете знакомиться с технологией — понимание нововведений в любом случае пойдет вам на пользу, поскольку без них вы не сможете полностью раскрыть потенциал актуальной версии. В этой статье перечислены 10 нововведений в Strapi, о которых вам стоит знать.
За основу материала я взял информацию с официального сайта Strapi об обновлениях для разработчиков и для контент-менеджеров, поэтому некоторые скриншоты делал не сам, а скромно переиспользовал. Однако в своем обзоре я разберу основные фишки на более детальных примерах, а также расскажу об особенностях, не упомянутых в рекламных статьях. Приступим.
Оглавление
Новый формат ответа API
Document Service API вместо Entity Service API
Использование в контроллерах коллекций
documentId вместо id
Функциональность Draft&Publish
Отдельные вкладки Draft и Published
Массовые операции
Работа с многоязычным контентом
Обновления TypeScript
Система типов в Strapi 5
Миграция кода в TypeScript
Операции с данными
Создание записи при загрузке файла
Новые функции и параметр запроса
Статус публикации
Функция count ()
Функция publish ()
Plugin SDK
Vite — инструмент сборки по умолчанию
Чат-бот с ИИ
LaunchPad — обновленная витрина
Платные функции
Content History
Расписание публикаций
Заключение
1. Новый формат ответа API
Работа с API стала проще и понятнее — теперь экземпляры коллекций (а также их внутренние связи) больше не оборачиваются в структуру вида { id, attributes }
.
Сравним со Strapi 4. Раньше запрашиваемые данные оборачивались в ключ attributes, и ответ API выглядел следующим образом:
// Ответ API в Strapi v4:
{
"data": {
// поля системы
"id": 14,
"attributes": {
// пользовательские поля
"title": "Article A",
"relation": {
"data": {
"id": "clkgylw7d000108lc4rw1bb6s",
"attributes": {
"name": "Category A"
}
}
}
}
},
"meta": {
"pagination": {
"page": 1,
"pageSize": 10
}
}
}
В Strapi 5 Контент-API возвращает экземпляры коллекции, не оборачивая их в объект attributes
:
// Ответ API в Strapi v5:
{
"data": {
// поля системы
"documentId": "clkgylmcc000008lcdd868feh",
"locale": "en",
// пользовательские поля
"title": "Article A",
"relation": {
// поля системы
"documentId": "clkgylw7d000108lc4rw1bb6s",
// пользовательские поля
"name": "Category A"
}
},
"meta": {
"pagination": {
"page": 1,
"pageSize": 10
}
}
}
Обратите внимание на новый параметр documentId — о нем мы поговорим чуть позже.
Если же вам потребуется ответ старого формата при работе со Strapi 5, вы все равно можете его получить. Для этого в заголовке к запросу нужно задать параметр Strapi-Response-Format: v4.
Пример
Попробуем извлечь запись в Strapi 5:
Получение статьи по documentId
в Strapi 5 без дополнительных заголовков
Как видите, в ответе нет объекта attributes
, поскольку в заголовке не задан параметр Strapi-Response-Format: v4. Давайте зададим его и сравним:
Получение статьи по documentId
в Strapi 5 c заголовком Strapi-Response-Format: v4
С заголовком мы получаем ответ API в старом формате.
2. Document Service API вместо Entity Service API
В Strapi 5 для работы с коллекциями на замену Entity Service API приходит Document Service API. Новый API-сервис позволяет расширить функциональность для коллекций:
Draft and Publish: каждый элемент коллекции теперь одновременно имеет версии черновика и опубликованного варианта (в интерфейсе Strapi — вкладки Draft и Publish). В Strapi 4 черновик у элемента существовал только до его первой публикации;
Content History: можно отслеживать изменение черновика и опубликованного варианта и откатываться к предыдущим версиям;
локализация: благодаря переходу от id к documentId (подробнее расскажем ниже) каждая сущность теперь может существовать в различных локалях. Ранее элементы в локалях существовали независимо друг от друга, и для публикации записи на нескольких языках приходилось ее дублировать.
Устройство контента в Strapi 5: теперь каждый элемент коллекции имеет версии draft/publish и может быть представлен в нескольких локалях
Раньше все вышеописанные действия требовали значительных усилий. Например, между таблицами приходилось настраивать дополнительные связи, из-за которых падала скорость запросов, а при локализации требовалось дублировать записи для разных локалей.
2.1. Использование в контроллерах коллекций
Предлагаю рассмотреть подробнее Entity Service API и Document Service API в контроллерах различных коллекций (более подробно об кастомизации контроллеров вы можете прочитать в нашей предыдущей статье).
Сравним формат запроса в Entity Service API и Document Service API:
Entity API:
strapi.entityService.findMany(uid, { fields: ["id", "name", "description"], populate: ["author", "comments"], publicationState: "live", });
Document API:
strapi.documents(uid).findMany({ fields: ["id", "name", "description"], populate: ["author", "comments"], status: "published", });
В обоих случаях мы получаем только опубликованные записи, просто с помощью разных API. Поддержка Entity Service API в Strapi 5 все еще присутствует, но ее использовать не рекомендуется — в будущих версиях планируется оставить только Document Service API. Подробнее об отличиях в запросах с помощь Entity Service API и Document Service API можно почитать в документации Strapi.
У Document Service API и Entity Service API очень похожий синтаксис, поэтому опытным Strapi-разработчикам не составит труда освоить новый инструмент. Тем не менее, в Strapi 5 появляются новые функции — их мы рассмотрим ниже.
2.2. documentId вместо id
Из-за особенностей Entity Service API в четвертой версии Strapi приходилось использовать id записи при каждом обращении к API. При поиске записи по ее id можно было получить следующий ответ:
Получение записи по ее id
В свою очередь, в Strapi 5 появилась возможность делать запросы к API по id документа (параметр documentId
):
Получение записи по ее documentId
Заметьте, что id записи также присутствует в ответе, и по его значению все еще можно обращаться к API сервиса Document.
2.3. Функциональность Draft&Publish
Разработка и публикация контента всегда подразумевают довольно сложный и запутанный процесс. Функциональность Draft&Publish значительно упрощает его и дает новые возможности по контролю публикаций.
В более ранних версиях Strapi отдельные записи могли быть либо в черновом, либо в опубликованном состоянии. Такой подход был удобен для мелких доработок, но сильно замедлял крупные обновления, над которыми работали команды из нескольких человек.
В Strapi 5 черновая и опубликованная версии контента могут существовать независимо друг от друга. В интерфейсе они разделены на две вкладки — Draft и Published.
Изменения во вкладке Draft можно сохранять, что позволяет нескольким людям вносить последовательные правки в контент перед публикацией. Более того, при работе над черновиком контент-менеджеры больше не рискуют случайно выкатить сырой материал на всеобщее обозрение или потерять прогресс из-за того, что забыли отправить его в Published.
Каждая запись теперь пребывает в одном из трех статусов:
Draft — контент никогда не публиковался и пока в работе;
Modified — контент публиковался ранее, но с момента последней публикации в его черновую версию были внесены изменения;
Published — контент опубликован, и в черновой версии нет новых правок.
Статус виден в режиме Content Manager в верхней части записи (подробнее о режимах мы также рассказывали тут). Таким образом, при командной работе над материалом контент-менеджерам не придется гадать, вносил ли кто-то из их коллег изменения после последней публикации.
Демонстрация статусов контента: published (опубликован) и modified (изменялся после публикации)
2.3.1. Отдельные вкладки Draft и Published
В обновленном интерфейсе черновой и опубликованный контент размещены на отдельных вкладках:
Draft — рабочее пространство, в котором можно вносить и сохранять изменения до тех пор, пока они не будут готовы к публикации;
Published — вкладка, на которой отображается опубликованный контент. На этой вкладке его редактировать нельзя, она нужна для того, чтобы вы понимали, какой материал пользователи видят на вашем сайте.
Между этими вкладками можно свободно переключаться, чтобы сравнивать черновик с опубликованной версией. Довольно полезная фишка, которая поможет не стереть важную информацию по неосторожности.
Элемент Article со статусом Modified во вкладке Draft (после последней публикации был изменен и сохранен, но еще не опубликован заново)
При работе с черновиком во вкладке Draft доступны следующие действия:
Publish — публикация черновика;
Save — сохранение черновика без публикации;
Discard changes — отмена внесенных изменений и откат к последней сохраненной версии черновика.
Также можно отменить публикацию контента. Если нужно будет скрыть с сайта какую-то запись, контент-менеджер сможет удалить опубликованную версию, и контент вернется в статус Draft. После этого доработать материал можно будет доработать перед повторной публикацией или удалить его окончательно.
Подробнее с функциональностью Draft&Publish можно ознакомиться в официальной документации Strapi.
2.3.2. Массовые операции
В Strapi 5 появляется возможность параллельно управлять статусами нескольких записей. Массовые операции в режиме Content Manager позволяют выделить необходимые записи и опубликовать их одновременно. Аналогичным образом можно удалять несколько опубликованных записей сразу.
Если вы локализуете контент под разные регионы, обратите внимание — Internationalization в Strapi 5 реализована как элемент базовой функциональности, а не как отдельный плагин. Благодаря этому вы сможете точечно выполнять массовые операции с контентом в конкретной локализации.
2.4. Работа с многоязычным контентом
В Strapi 5 подход к локалям изменился — благодаря documentId
все переводы и локализованные версии контента теперь совмещены в один «документ».
В предыдущих версиях каждая локализованная версия создавалась как отдельная запись со своим уникальным id, из-за чего записями для каждого региона нужно было управлять индивидуально. Такая структура увеличивала вложенность и делала процесс внесения изменений менее эффективным, особенно при необходимости синхронизировать или обновлять контент.
Давайте посмотрим, как это выглядит в новой версии Strapi. Для примера возьмем статью на английском языке:
Элемент коллекции Article в английской локали
При запросе на список статей мы увидим ее в списке с ”documentId”: "cr2j378mpnjq6o95sogelzns”
(если при запросе не указывать параметр locale
, то его значение задается по умолчанию — в нашем случае это en
):
Получение элемента коллекции в ее локали по умолчанию (en
)
Теперь создадим версию этой статьи для русской локали. Для этого в режиме Content Manager выберем элемент коллекции и справа вверху сменим в нем локаль, а затем заполним ее контентом на русском языке:
Элемент коллекции Article в русской локали
А затем сделаем еще один запрос на список статей, но на этот раз — с параметром "locale”: "ru”
:
Получение элемента коллекции в русской локали
Как мы видим, documentId
не изменился — это все тот же элемент в Strapi, но с другим контентом для другой локали.
3. Обновления TypeScript
Поддержка TypeScript была еще в Strapi 4. Тогда же разработчики добавили экспериментальную типизированную систему для API, а вместе с ней и автоматизированную генерацию типов контента и компонентов. Однако в Strapi 5 появляются еще несколько нововведений.
3.1. Система типов в Strapi 5
В новую версию CMS добавлена возможность импортировать необходимые неймспейсы, используя типы для API. У каждого типа в системе есть описание и пример использования.
Теперь все js-файлы при создании проекта становятся ts-файлами:
Структура проекта — теперь вместо js-файлов используются ts-файлы
А сам Strapi теперь позволяет использовать свои системные типы. Они могут пригодиться, например, при типизации возвращаемых данных в контроллерах:
import type {Data, Schema, UID, Utils} from "@strapi/strapi";
// ...
declare function fetch(uid: T) : Data.Entity;
declare function getComponentSchemas(): Utils.String.Dict;
3.2. Миграция кода в TypeScript
Изначально Strapi был полностью написан на JavaScript, однако к пятой версии код почти целиком переехал на TypeScript. Отчасти это сказывается на удобстве работы с ориентированными на пользователя API.
Использованные языки в Strapi 5 (теперь преобладает TS)
3.3. Операции с данными
В новой версии обеспечена полная совместимость с TypeScript, следовательно, при работе с системой не придется гадать, какие методы, фильтры и типы данных поддерживаются, а какие нет.
Демонстрация автокомплита в ts-файлах Strapi 5
4. Создание записи при загрузке файла
К сожалению, без минусов не обошлось — создавать записи при загрузке файлов стало менее удобно. Раньше система поддерживала автоматическое создание записи при таком сценарии. Теперь в качестве альтернативы можно пользоваться определенной последовательностью действий.
Сначала нужно выгрузить файл и получить его id — этот же id будет использоваться в записи.
Как получить id файлаВыгружаем файл:
const file_upload_response = await fetch(`${StrapiURL}/api/upload`, { method: 'post', body: formData });
Получаем id выгруженного файла:
const id = file_upload_response[0].id
Когда id файла получен, нужно использовать его при создании записи.
Как создать запись с id файлаconst newEntry = { data: { entryName: data.name, entryFile: id // file id } }
Делаем запрос к API на создание новой записи:
const response = await fetch(`${StrapiURL}/api/{collection}`, { method: 'post', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(newEntry), });
5. Новые функции и параметр запроса
С появлением Draft&Publish в Document Service API добавился новый параметр запроса status, а также несколько новых функций:
count()
;publish()
;unpublish()
;discardDraft()
.
Ниже рассмотрим некоторые из них.
5.1. Статус публикации
GET-запросы для извлечения записи обзавелись параметром status
. С его помощью можно выбирать статус записи, которую вернет API — для этого параметру нужно задать значение published
или draft
.
В качестве примера возьмем запись, у которой есть и опубликованная, и черновая версии:
Вкладка Draft у публикации
Вкладка Published у публикации
Если не указывать параметр status
, по умолчанию API возвращает опубликованную версию.
5.2. Функция count ()
Функция count()
позволяет извлечь определенное количество документов, соответствующих заданным параметрам.
5.3. Функция publish ()
С помощью функции publish()
можно опубликовать документ или несколько его локализованных версий. Он работает только в том случае, если включена функциональность Draft&Publish.
Разберемся на примере, как это работает. Предположим, что у нас есть статья на английском языке и черновик ее локализации на французском. Французский вариант нам нужно опубликовать.
Примерно так мог выглядеть наш переписанный контроллер, который публиковал бы статью сразу в несколько локалей:
// src/api/article/controllers/article.js
const { createCoreController } = require('@strapi/strapi').factories;
module.exports = createCoreController('api::article.article', ({ strapi }) => ({
async create(ctx) {
// Создаем основную статью, например, в английской локали
const response = await super.create(ctx);
const article = response.data;
// Проверяем, что статья создана успешно
if (article) {
// Публикуем статью во французской локали (или других локалях)
await strapi.documents('api::article.article').publish({
documentId: article.documentId,
locale: 'fr', // Измените на нужную локаль
});
// Можно добавить публикацию в дополнительных локалях, если требуется
await strapi.documents('api::article.article').publish({
documentId: article.documentId,
locale: 'es', // Пример для испанского варианта
});
}
return response;
},
}));
Готово.
6. Plugin SDK
Для командной строки также появляется новый инструмент — Plugin SDK. С его помощью можно создавать плагины и добавлять их в проекты Strapi уже после того, как эти проекты были заведены.
Чтобы создать Strapi-плагин, нужно выполнить следующие действия:
Создать сам плагин (процесс создания подробно описан в документации).
Подлинковать плагин к проекту — для этого нужно выполнить следующие команды:
cd /path/to/strapi/project
npx yalc add --link my-strapi-plugin && npm install
гдеmy-strapi-plugin
— имя вашего плагина.
Внимание: перед тем, как выполнять вторую команду, проверьте, что вы действительно перешли в ваш Strapi-проект, а также убедитесь, что yalk установлен и работает глобально.Опубликовать плагин — для этого нужно выполнить следующую команду:
npm run build && npm run verify
Данная команда проверяет, готов ли плагин к публикации, и завершает процесс его создания.
На случай, если вам понадобится детальнее разобраться в тонкостях работы с Plugin SDK, оставлю ссылку на документацию.
7. Vite — инструмент сборки по умолчанию
Раньше в Strapi использовался Webpack — опенсорсный модульный инструмент сборки для JavaScript. С новой версией системы разработчики решили перейти на Vite по следующим соображениям:
Vite обеспечивает более высокую скорость работы в Dev-режиме благодаря Go-модулю esbuild — он позволяет собирать код на 15% быстрее, чем JavaScript-модули;
Vite не требует конфигурационных файлов для сборки кода.
Теперь Strapi использует Vite
8. Чат-бот с ИИ
Документация Strapi, на которую я уже неоднократно ссылался, обзавелась собственным чат-ботом с ИИ (диалоговое окно открывается по кнопке Ask AI в правом верхнем углу страницы). Теперь можно задать ему интересующий вопрос и получить быстрый ответ. Несмотря на удобство, слепо верить боту я не рекомендую — его ответы лучше на всякий случай перепроверять.
Взаимодействие с чат-ботом
9. LaunchPad — обновленная витрина
На смену FoodAdvisor — предыдущему приложению на Strapi, предназначенному для демонстрации возможностей системы — приходит LauchPad.
LaunchPad для демонстрации возможностей системы
На этот раз разработчики подготовили официальное демо-приложение для своей CMS. С пользовательской функциональностью можно ознакомиться на сайте Strapi, а на GitHub появился репозиторий с технологическим стеком, в который входят:
10. Платные функции
10.1. Content History
При работе с контентом люди могут допускать ошибки. Порой доработки материалов не приносят ожидаемых результатов, и новые версии оказываются хуже предыдущих. Нововведение Content History из пятой версии Strapi предназначено для того, чтобы исправлять подобные ошибки без лишних усилий.
Теперь система запоминает все версии контента, которые вы сохраняете. К любой версии из истории изменений можно откатиться в несколько кликов. Старые версии хранятся в Content History с указанием даты сохранения и содержат информацию обо всех внесенных правках.
Стоит оговориться, что Content History — не бесплатное удовольствие; хранить старые версии можно либо по подписке в облаке Strapi, либо по расширенной корпоративной лицензии на собственных серверах. С ценниками можно ознакомиться на официальном сайте, но ссылку я не дам — в конце концов, это обзор, а не реклама. Зато дам ссылку на документацию, если вы захотите узнать подробности о Content History из первоисточника.
Content History
Перейти в Content History можно при редактировании документа в режиме Content Manager. Для этого нужно выполнить следующие действия:
нажать на «три точки» в правом верхнем углу экрана;
в выпадающем списке выбрать «Content History».
Открывшийся раздел будет состоять из двух секций:
на панели справа будут отображены записи о старых версиях с указанием даты создания, времени изменения, автора изменений и статуса (Draft, Modified или Published);
в основной секции слева будет отображен контент, соответствующий записи, выбранной на правой панели.
При выборе версии в правой панели вы можете восстановить ее нажатием кнопки Restore. После этого актуальный черновик будет заменен на выбранную версию.
К слову, если вы работаете с функциональностью Internationalization, то откат конкретного поля к одной из предыдущих версий будет автоматически выполняться для всех ваших локализаций, в которых также есть это поле.
Content History помогает отслеживать, какие поля появлялись, исчезали или переименовывались в разных версиях. Неизвестные поля отображаются в разделе Unknown fields.
Поля в Content History
10.2. Расписание публикаций
Также обладателям подписки на Strapi 5 будет доступна функция Release — с ее помощью можно запланировать для записей дату и время публикации. Может пригодиться для анонсов и рекламных постов, чтобы они автоматически публиковались в назначенное время.
Добавление нескольких элементов в расписание публикаций
11. Заключение
На мой взгляд, обновление вышло удачным — новые возможности Strapi действительно упрощают работу там, где раньше порой приходилось плясать с бубном. Функциональность по подписке может показаться тревожным звоночком, но пока она касается только тех возможностей, для реализации которых команде Strapi приходится хранить данные пользователей у себя в облаке.
Если вы по каким-то причинам продолжаете пользоваться старой версией Strapi, сейчас самое время попробовать актуальную и сравнить их самостоятельно. Думаю, многие нововведения придутся вам по вкусу. А если вы не были знакомы с этой системой раньше, то загляните в мой предыдущий материал — там я подробно разбирал основные аспекты работы в ней:
CMS за 0 рублей: как мы начали использовать Strapi
А также читайте материалы моих коллег, которые тоже пишут о фронтенд-разработке: