Error handling в development

Во фреймворке Fresh механизм обработки ошибок построен с учётом принципов современного веб-разработки на Deno и JavaScript, обеспечивая прозрачное выявление проблем на этапе разработки и минимизацию неожиданных сбоев в продакшене. В режиме development ключевое внимание уделяется детальной информации об ошибках, стек-трейсам и возможности быстрого исправления.


Конфигурация режима разработки

Fresh автоматически активирует development mode при запуске через команду:

deno task start

или при использовании переменной окружения:

DENO_ENV=development

В этом режиме включается:

  • Подробная трассировка стека;
  • Интерактивные сообщения об ошибках прямо в браузере;
  • Автоматическая перезагрузка страниц при изменении кода (hot reload).

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


Error Boundaries

В Fresh используется концепция Error Boundaries, аналогичная React, для изоляции ошибок на уровне компонентов. Ошибки, возникшие в дочерних компонентах, не ломают весь маршрут, а обрабатываются локально. Для создания Error Boundary используется компонент с методом catch:

/** @jsx h */
import { h } from "preact";

export default function ErrorBoundary({ error }) {
  return (
    <div style={{ color: "red" }}>
      <h1>Произошла ошибка</h1>
      <pre>{error.message}</pre>
      <pre>{error.stack}</pre>
    </div>
  );
}

Key points:

  • error.message выводит краткое описание ошибки;
  • error.stack показывает полный стек вызовов;
  • Компонент можно подключать к любому маршруту, используя export const config = { errorBoundary: true };.

Обработка ошибок в серверных функциях

Fresh позволяет разделять обработку ошибок на стороне сервера и клиента. Серверные функции (handlers) могут использовать стандартный механизм try/catch:

export const handler = {
  async GET(req) {
    try {
      const data = await fetchSomeData();
      return new Response(JSON.stringify(data));
    } catch (error) {
      console.error("Ошибка при загрузке данных:", error);
      return new Response("Internal Server Error", { status: 500 });
    }
  },
};

Особенности:

  • Ошибки логируются в консоль Deno с полным стеком;
  • Возврат статуса 500 информирует клиент о серверной проблеме;
  • В development режиме можно дополнительно выводить объект error с подробной трассировкой прямо в ответ.

Перехват ошибок маршрутов

Для глобальной обработки ошибок в маршрутах используется файл _middleware.ts:

import { MiddlewareHandlerContext } from "$fresh/server.ts";

export async function handler(
  req: Request,
  ctx: MiddlewareHandlerContext,
) {
  try {
    return await ctx.next();
  } catch (error) {
    console.error("Глобальная ошибка маршрута:", error);
    return new Response(
      `<h1>Ошибка</h1><pre>${error.stack}</pre>`,
      { status: 500, headers: { "Content-Type": "text/html" } },
    );
  }
}

Такой подход обеспечивает:

  • Локализацию всех необработанных исключений;
  • Возможность кастомного рендеринга страницы ошибки;
  • Автоматическое логирование для анализа проблем на этапе разработки.

Интерактивные сообщения об ошибках

Fresh интегрируется с deno lsp и механизмом HMR, поэтому ошибки отображаются прямо в браузере с подсветкой строк кода и стеком вызовов. Для максимально информативного вывода используется следующая структура сообщения:

  • Название файла и строка ошибки;
  • Контекст нескольких строк кода вокруг проблемы;
  • Полный стек вызовов с указанием функций и маршрутов.

Это позволяет сразу выявлять причину ошибки без необходимости заходить в консоль Deno.


Рекомендации по эффективной отладке

  • Использовать try/catch только там, где есть вероятность ошибки;
  • Для критических функций применять отдельные Error Boundaries;
  • Логировать ошибки с использованием console.error для сохранения трассировки;
  • Включать development mode только при локальной разработке, чтобы не раскрывать стек вызовов в продакшене;
  • Проверять корректность возвращаемых типов в handlers, так как несоответствие ожидаемому формату часто является источником ошибок.

Особенности работы с асинхронными ошибками

В Fresh асинхронные операции часто являются источником исключений. При работе с fetch, базами данных или файловой системой рекомендуется:

  • Всегда использовать await внутри try/catch;
  • Обрабатывать Promise с .catch() для локальных операций;
  • Возвращать корректный HTTP-статус и информативное тело ответа для диагностики.

Пример асинхронного Error Boundary:

export default async function AsyncComponent() {
  try {
    const data = await fetchData();
    return <div>{data.title}</div>;
  } catch (error) {
    return (
      <div style={{ color: "red" }}>
        <h2>Ошибка при загрузке данных</h2>
        <pre>{error.stack}</pre>
      </div>
    );
  }
}

Такой подход обеспечивает безопасное отображение ошибок без разрушения всего интерфейса.


Обработка ошибок в Fresh в режиме разработки построена на принципах прозрачности и детального контроля. Использование Error Boundaries, глобальных middleware и асинхронного перехвата исключений позволяет выявлять проблемы на раннем этапе и ускоряет процесс разработки, обеспечивая стабильность и предсказуемость поведения приложения.