Тема сайта собирается webpack прямо на сервере. За год это дало три урока: сборка падает на новой версии Node, линтер, запущенный «по всему», висит сутками даже после прерывания, а CI находит ошибку, которую сборка на тесте не видела ни разу.

Это 13-я часть цикла «Сервер для WordPress».

1. Node 22 ломает сборку

[webpack-cli] SyntaxError: Unexpected identifier 'assert'

Один из плагинов webpack импортирует JSON старым синтаксисом:

import schema from './schemas/plugin-options.json' assert { type: 'json' };

В Node 22 этот синтаксис удалён (новый — with { type: 'json' }), и webpack не может даже загрузить конфиг. Node 22 падает так же, как 24, — первая попытка «поставить LTS поновее» не помогла. Собралось только на Node 20.

Править файл внутри node_modules бесполезно — правка слетит при следующей установке пакетов. Варианты: держать Node 20, зафиксировать правку через patch-package или обновить плагин, когда выйдет версия с новым синтаксисом. Мы держим Node 20.

Node — в контейнере, а не на сервере

На сервере живут проекты, которым нужны разные версии Node. Ставить Node в систему — значит выбирать, какой из них сломать. Поэтому node и npm на сервере — обёртки, которые запускают официальный образ node:20 с папкой проекта:

docker run --rm -v "$PWD":/app -w /app node:20-bookworm npm run build

Версия Node становится свойством команды, а не сервера.

2. Линтер, который висит сутками

Запуск eslint src/ по всей теме на тестовом сервере занял ядро на 101% и не заканчивался. Вызов прервали — а процесс остался жить: он работал в контейнере, запущенном с --rm, и прерывание клиента контейнер не останавливает.

# найти и остановить прогон, который остался после прерывания
docker ps --format '{{.ID}} {{.Command}}' | grep -i eslint
docker kill <id>   # именно контейнер: kill процесса на хосте его не остановит

Не убивайте node на сервере всем скопом: там же работают сборки в режиме наблюдения у других проектов.

3. CI видит больше, чем сборка на тесте

Изменения ушли в репозиторий — и выкат остановился на ошибке форматирования в файле, который сборка на тесте собирала много раз без замечаний.

Причина — настройка сборки в режиме наблюдения: линтер проверяет только изменённые модули (lintDirtyModulesOnly). Файл правили до того, как запустили наблюдение, поэтому «изменённым» он для сборки не стал ни разу. А CI ставит пакеты с нуля и проверяет весь src.

Что именно ругалось: при ширине строки 150 символов многострочная стрелочная функция, которая помещается в одну строку, обязана быть в одну строку.

// prettier потребует собрать в одну строку — она влезает
['scroll', 'touchstart'].forEach((type) =>
  window.addEventListener(type, open, { once: true, passive: true })
);

// однозначно при любой ширине строки
for (const type of ['scroll', 'touchstart']) {
  window.addEventListener(type, open, { once: true, passive: true });
}

Правило: перед коммитом прогнать линтер по всему src так же, как CI. Повторные прогоны во время работы — только по изменённым файлам, чтобы не повторять историю с зависшим контейнером.

docker run --rm -v "$PWD":/app -w /app node:20-bookworm npx eslint src

Сборка темы падает на сервере или в CI?

Пришлите ошибку — найду, в версии Node дело, в линтере или в том, что CI видит больше.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.