Суть проблемы
Три разных клиента, одна общая беда — «обновили и всё сломалось». Кто-то нажал «Обновить» в админке WordPress, кто-то сделал npm update, кто-то обновил react-router. Результат везде один: прод лежит, пользователь видит белый экран или ошибку сервера.
- !WordPress — белый экран (WSOD)Вместо сайта и админки — пустая страница. PHP Fatal подавляется, ошибок в браузере нет, есть только белый лист по status 200 с нулевой длиной body.
- !Next.js — 500 на всех страницахПосле
npm updateлюбая страница отдаёт HTTP 500 Internal Server Error. В логе сборки TypeError, локальныйnext buildпадает. - !React — белый экран в продеSPA рендерит пустой
#root, в консоли TypeError и «Minified React error #423/#418». В dev-режиме тот же код работает. - !Сайт «не грузит»Симптом общий: либо пустая страница, либо ошибка сервера, либо зависший лоадер. Пользователь не получает контент.
Три лежащих сайта: WP-блог, Next.js-лендинг и React-SPA. У всех последних действий администратора — кнопка «Обновить» либо npm update. Восстановить своими силами не удалось.
Три работающих проекта. В каждом — откат/даунгрейд несовместимой версии, точечный фикс breaking-change и зафиксированный lock-файл/версии, чтобы апдейт больше не ронял прод.
Как диагностировал
Подход единый: включить/найти логи, воспроизвести локально, прочитать ошибку, сопоставить с changelog обновлённой зависимости. Подводных камней нет — почти всегда причина лежит прямо в первой строке лога, нужно только её достать.
WordPress — белый экран = подавлённый Fatal
- Включил отладкуВ
wp-config.phpпоставилWP_DEBUG = trueиWP_DEBUG_LOG = true— ошибки стали писаться вwp-content/debug.logвместо глушения. - Прочитал FatalПервая же строка лога:
Fatal error: Uncaught Error: Call to undefined function create_function() in .../theme/functions.php on line 42.create_function()удалён в PHP 8.0 — хостинг заодно обновил PHP с 7.4 до 8.2. - Проверил конструкторыТам же нашёл класс с конструктором вида
function MyClass()вместоpublic function __construct()— deprecated в PHP 8, в сочетании с WP 6.4 даёт фатал при загрузке темы. - Подтвердил версию PHP
php -vна сервере → 8.2.12.wp theme statusчерез wp-cli показал активную кастомную тему версии, которая последний раз обновлялась под PHP 7.
Next.js — 500 после npm update
- Посмотрел лог рантаймаВ
pm2 logsна сервере:TypeError: Cannot read properties of undefined (reading 'metadata') ... node_modules/next/dist/.... Ошибка в ядре Next.js. - Сверил package.jsonВ
package.jsonNext.js записан как"^14.0.0". Каретка допустила мажорный апгрейд —npm updateподнял зависимость до несовместимой минорной сборки, где изменился контракт генерации метаданных. - Воспроизвёл локально
npm installиз текущегоpackage.json+next build→ упало с тем же TypeError. Значит, проблема в коде приложения под новый контракт metadata, а не в окружении сервера. - Проверил Node-версию
node -v→ 20.11.0. В.nvmrcпроекта зафиксирована 18.17.0 — на сервере иная среда. Не корневая причина, но источник второго класса багов. - Прочитал changelogВ changelog обновлённой минорной версии Next.js — breaking change в экспорте
generateMetadata: теперь требует явного возвратаMetadata-объекта,undefinedпадает.
React — Minified React error в проде
- Раскрыл source mapВ проде ошибка минифицирована:
Minified React error #423. По коду #423 в доке React — это hydration mismatch: разница между серверным и клиентским HTML. - Включил dev-режимЛокально в dev (
npm run dev) React показал полный текст:Hydration failed because the initial UI does not match what was rendered on the server. Указание на компонент<Header />. - Нашёл обращение к
windowВHeaderпри SSR читалосьwindow.localStorage.getItem('theme'). На сервереwindowне существует — тот же компонент дал разный вывод на сервере и клиенте. - Сверил зависимостьВ
package.jsonreact-router-domобновлён с 5 на 6 — как раз накануне падения. В v6 изменился API<Switch>→<Routes>, но это усугубляло, а не было корнем белого экрана.
Что исправил
В каждом под-кейсе — откат/даунгрейд до рабочей версии, точечный фикс несовместимости в коде и закрепление версий в lock-файле. Ниже — сниппеты до и после по всем трём проектам.
WordPress — включение отладки и фикс deprecated-конструктора
Сначала откатил активную тему на штатную, чтобы вернуть сайт онлайн, затем точечно починил кастомную тему.
// отладка выключена — белый экран без подсказок
define( 'WP_DEBUG', false );
// ошибки пишутся в wp-content/debug.log, на экран не выводятся
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Откат темы через wp-cli — чтобы мгновенно вернуть сайт посетителям:
wp theme activate twentytwentyfour
# сайт снова грузится, чиним кастомную тему отдельно
Корневая причина — устаревший конструктор и create_function() в functions.php:
// PHP 8: create_function() удалён → Fatal error
add_filter( 'the_content', create_function(
'$c',
'return str_replace("old", "new", $c);'
) );
class My_Shortcode {
// deprecated-конструктор вместо __construct
function My_Shortcode() {
add_shortcode( 'box', array( $this, 'render' ) );
}
}
// анонимная функция вместо удалённого create_function()
add_filter( 'the_content', function( $content ) {
return str_replace( 'old', 'new', $content );
} );
class My_Shortcode {
public function __construct() {
add_shortcode( 'box', array( $this, 'render' ) );
}
}
Next.js — фиксация версий и правка generateMetadata
Каретка в package.json пропустила мажорный апгрейд. Перешёл на точные версии и npm ci по lock-файлу.
{
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0"
}
}
{
"dependencies": {
"next": "14.1.0",
"react": "18.2.0"
}
}
# установка строго по lock-файлу, без мажорных сюрпризов
npm ci
# сборка зелёная
next build
Точечный фикс breaking-change — generateMetadata должен явно возвращать объект, undefined валит рантайм:
export async function generateMetadata() {
const data = await fetchPage();
// если fetchPage вернёт null — вернётся undefined → TypeError
return data?.seo;
}
export async function generateMetadata(): Promise<Metadata> {
const data = await fetchPage();
// явный объект-пустышка вместо undefined
return data?.seo ?? {
title: 'Дефолтный заголовок',
description: 'Дефолтное описание',
};
}
React — guard на window и вынос логики в useEffect
Чтение window.localStorage при SSR давало hydration mismatch. Перенёс клиентскую логику в useEffect и добавил безопасное чтение темы.
export default function Header() {
// window не существует на сервере → hydration mismatch
const theme = window.localStorage.getItem('theme') ?? 'light';
return (
<header className={`theme-${theme}`}>
<nav>...</nav>
</header>
);
}
import { useState, useEffect } from 'react';
export default function Header() {
// дефолт рендерится и на сервере, и на клиенте одинаково
const [theme, setTheme] = useState('light');
useEffect(() => {
const saved = window.localStorage.getItem('theme') ?? 'light';
setTheme(saved);
}, []);
return (
<header className={`theme-${theme}`} suppressHydrationWarning>
<nav>...</nav>
</header>
);
}
Результат
Три прода подняты за один сеанс каждый. Во всех случаях хватало отката/даунгрейда и точечного фикса несовместимости — переписывать ничего не пришлось.
Во всех трёх случаях рецепт совпал: откатить несовместимую версию → починить конкретный вызов, на котором падает код → закрепить точные версии в lock-файле и package.json. Повторных падений после апдейтов ни у одного из клиентов не было.