<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Снёс 90% кода легаси роутера на URLPattern API]]></title><description><![CDATA[<p dir="auto">Когда ты смотришь на десятилетний код роутера в Node.js приложении и видишь там RegExp с флагами, которые никто не помнит зачем, костыли под старые версии браузеров и целую папку юнит-тестов только для парсинга путей - понимаешь, что что-то пошло не так. Проблема не в том, что Express неправильный. Проблема в том, что мы годами решали проблему маршрутизации половинчатыми методами, потому что не было нормального встроенного инструмента.</p>
<p dir="auto">Теперь он есть. <strong>URLPattern API</strong> - это не просто очередной полифилл. Это нативное решение, которое работает одинаково в браузере и на сервере, и главное - оно позволяет выбросить тонну кода, который можно было выбросить ещё пять лет назад.</p>
<h2>Почему роутер стал таким раздутым</h2>
<p dir="auto">Представь себе типичный Express приложение из 2018 года. Там используется <code>path-to-regexp</code> - библиотека, которая преобразует строки с шаблонами вроде <code>/users/:id</code> в регулярные выражения. Звучит просто, но в реальности вокруг этого нарастали слои кода: обработчики ошибок, кастомные валидаторы, миддлвары для каждого параметра, кеширование скомпилированных RegExp и ещё куча мелочей, которая казалась необходимой в 2016 году.</p>
<p dir="auto">Проблема в том, что каждый новый роутер - это новая RegExp, которую нужно создавать, тестировать, кешировать. На сервере при обработке запроса система идёт по списку всех маршрутов и проверяет URL против каждого регулярного выражения, пока не найдёт совпадение. Если у тебя 500 роутов и нужный находится ближе к концу - вот тебе и N операций на каждый запрос. Плюс сама работа с RegExp требует понимания синтаксиса паттернов, и часто эти паттерны становятся нечитаемым месивом специальных символов.</p>
<p dir="auto"><strong>Результат</strong>: бойлерплейт, который дублируется в каждом проекте, лишние npm-зависимости и код, который сложнее тестировать и поддерживать.</p>
<h2>URLPattern API: когда встроенное решение лучше, чем фреймворк</h2>
<p dir="auto">URLPattern - это <strong>встроенная в JavaScript часть</strong>, которая имеет в своей основе тот же синтаксис, что и <code>path-to-regexp</code>, но реализована нативно. Важный момент: это не просто очередной полифилл, это полноценный API, доступный в Node.js 24+ и во всех современных браузерах.</p>
<p dir="auto">Вместо того, чтобы вручную компилировать паттерны и работать с RegExp, ты пишешь:</p>
<pre><code class="language-javascript">const pattern = new URLPattern({
  pathname: '/users/:id/posts/:postId'
});

const result = pattern.exec({ pathname: '/users/123/posts/456' });
console.log(result.pathname.groups); // { id: '123', postId: '456' }
</code></pre>
<p dir="auto">И это работает одинаково в браузере и на сервере. Один API, два окружения - никаких окружающих вокруг либ.</p>
<p dir="auto">У URLPattern есть два основных метода. <strong>exec()</strong> разбирает URL, возвращает объект с группами параметров или null если совпадения нет. Это мощный метод, он даёт полную информацию о каждом элементе маршрута. <strong>test()</strong> - более быстрый вариант, просто проверяет, совпадает ли URL с паттерном, да или нет. Если тебе нужна только валидация - используй test(), если нужны значения параметров - exec().</p>
<p dir="auto">Что касается производительности: нативная реализация работает быстрее, чем покупка js-библиотеки, потому что не нужно создавать лишние объекты в памяти и вообще меньше слоёв абстракции. Регулярные выражения всё равно окажут быстрее на микробенчах, но на реальных нагрузках разница исчезает, а код становится проще.</p>
<h2>Как это убирает 90% легаси кода</h2>
<p dir="auto">Возьми типичный Express роутер, который поддерживает эту самую <code>path-to-regexp</code>. Там обычно есть:</p>
<ul>
<li>Самостоятельная компиляция паттернов в RegExp</li>
<li>Кеширование скомпилированных RegExp для ускорения</li>
<li>Кастомные валидаторы параметров</li>
<li>Обработчики ошибок для невалидных паттернов</li>
<li>Юнит-тесты на всё это безумие</li>
<li>Документация, которая дублирует документацию path-to-regexp</li>
<li>Обёртки для работы с браузером отдельно, для сервера отдельно</li>
</ul>
<p dir="auto"><strong>Вот что исчезает:</strong></p>
<ul>
<li>Весь код компиляции - больше не нужен, встроенный API это делает.</li>
<li>Кеширование - браузер и runtime берут на себя оптимизацию.</li>
<li>Часть юнит-тестов - API протестирован, тебе нужны только интеграционные.</li>
<li>npm-зависимость от <code>path-to-regexp</code> - она больше не критична, хотя может остаться для специфичных случаев.</li>
<li>Дублирование логики клиент-сервер - один API везде.</li>
</ul>
<p dir="auto">В реальности проекты, которые перешли на URLPattern, сообщают об удалении примерно 40-60% кода роутера. Это не преувеличение - если у тебя была нормально поддерживаемая система, ты избавился от слоёв абстракции.</p>
<h2>Практические различия: когда это важно</h2>
<p dir="auto">В начале надо понять, что URLPattern это не замена Express. Это замена нижнему слою роутера - той части, которая парсит пути. Express остаётся полезным для middleware, обработки запросов и ответов. Но ты можешь потом оставить только самое необходимое из Express или даже перейти на более лёгкий фреймворк.</p>
<p dir="auto">Где URLPattern <strong>явно выигрывает</strong>:</p>
<ul>
<li><strong>Унификация клиент-сервер</strong>: один синтаксис паттернов везде.</li>
<li><strong>Меньше кода</strong>: встроенное решение требует меньше обёрток.</li>
<li><strong>Проще дебаг</strong>: нет лишних слоёв абстракции между вызовом и результатом.</li>
<li><strong>Быстрее стартует</strong>: нет нужды грузить и компилировать path-to-regexp.</li>
<li><strong>Меньше утечек памяти</strong>: всё реализовано оптимально под капотом.</li>
</ul>
<p dir="auto">Где RegExp <strong>может быть полезнее</strong>:</p>
<ul>
<li>Если тебе нужна абсолютная максимальная пропускная способность на микросекундах - чистый RegExp быстрее.</li>
<li>Если у тебя сложные условные маршруты - RegExp дает больше гибкости.</li>
<li>Если тебе нужны regex-группы в паттернах - URLPattern ограничивает их в некоторых окружениях из соображений производительности.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Параметр</th>
<th>URLPattern</th>
<th>path-to-regexp</th>
<th>RegExp</th>
</tr>
</thead>
<tbody>
<tr>
<td>Встроенность</td>
<td>Да, нативно</td>
<td>npm-пакет</td>
<td>Встроено</td>
</tr>
<tr>
<td>Синтаксис</td>
<td><code>/users/:id</code></td>
<td><code>/users/:id</code></td>
<td>Сложный</td>
</tr>
<tr>
<td>Клиент+сервер</td>
<td>Одинаково</td>
<td>Нужна обёртка</td>
<td>Сложновато</td>
</tr>
<tr>
<td>Производительность</td>
<td>Хорошая</td>
<td>Хорошая</td>
<td>Очень быстро</td>
</tr>
<tr>
<td>Сложность кода</td>
<td>Минимальная</td>
<td>Средняя</td>
<td>Высокая</td>
</tr>
<tr>
<td>Поддержка regex-групп</td>
<td>Ограничена</td>
<td>Полная</td>
<td>Полная</td>
</tr>
</tbody>
</table>
<h2>Как правильно переходить на URLPattern</h2>
<p dir="auto">Если ты решил очистить свой код, вот схема, которая работает без боли. Не надо менять все роутеры сразу - это гарантирует хаос. Начни с нового функционала. Пиши новые роутеры на URLPattern, оставляя старые как есть. Через месяц-два ты спокойно можешь рефакторить.</p>
<p dir="auto">Второе: используй URLPattern только для парсинга путей. Не пытайся переместить туда всю логику валидации - это не его задача. Валидация параметров должна оставаться в специализированной функции или middleware.</p>
<p dir="auto">Третье: помни про <code>hasRegExpGroups</code>. Спецификация позволяет окружениям ограничивать использование regex-групп в паттернах. Если ты пишешь код, который должен работать везде - старайся избегать regex-синтаксиса в шаблонах. Придерживайся простых паттернов с именованными параметрами.</p>
<pre><code class="language-javascript">// Хорошо - работает везде
const good = new URLPattern({ pathname: '/api/v1/users/:userId/posts/:postId' });

// Может не работать везде - содержит regex
const risky = new URLPattern({ pathname: '/api/v1/users/:userId(\\d+)/posts/:postId' });

// Проверить перед использованием
if (risky.hasRegExpGroups) {
  console.warn('Используются regex-группы, может быть несовместимо');
}
</code></pre>
<p dir="auto">Вот примеры, которые показывают реальную экономию:</p>
<ul>
<li><strong>Старый способ с path-to-regexp</strong>: 150 строк код (импорт, компиляция, кеширование, тесты)</li>
<li><strong>URLPattern решение</strong>: 20 строк кода (новый URLPattern, exec, готово)</li>
<li><strong>Результат</strong>: 87% кода можно выбросить без потери функциональности</li>
</ul>
<h2>Что остаётся за кадром</h2>
<p dir="auto">URLPattern решает одну задачу и решает её хорошо - парсинг и валидация путей. Но это не замена Express целиком и не замена фреймворку. Ты всё равно нужен способ обрабатывать middleware, headers, cookies, ошибки. URLPattern это просто один из кусочков пазла.</p>
<p dir="auto">Есть ещё вещи, которые стоит подумать. Например, как интегрировать URLPattern с существующим middleware-стеком. Или как использовать его вместе с TypeScript, чтобы типы параметров выводились автоматически. Эти задачи уже за пределами самого API - это про экосистему вокруг него.</p>
]]></description><link>https://forum.exlends.com/topic/2175/snyos-90-koda-legasi-routera-na-urlpattern-api</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 14:07:04 GMT</lastBuildDate><atom:link href="https://forum.exlends.com/topic/2175.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 23 Apr 2026 12:14:28 GMT</pubDate><ttl>60</ttl></channel></rss>