<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Aleksandr Kitov</title><generator>teletype.in</generator><description><![CDATA[Aleksandr Kitov]]></description><image><url>https://img2.teletype.in/files/95/91/9591a694-e989-4a6d-9d97-59992f665565.png</url><title>Aleksandr Kitov</title><link>https://blog.akitov.info/</link></image><link>https://blog.akitov.info/?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/heymdall?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/heymdall?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Sat, 11 Apr 2026 07:44:56 GMT</pubDate><lastBuildDate>Sat, 11 Apr 2026 07:44:56 GMT</lastBuildDate><item><guid isPermaLink="true">https://blog.akitov.info/vulnerability-is-broken</guid><link>https://blog.akitov.info/vulnerability-is-broken?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall</link><comments>https://blog.akitov.info/vulnerability-is-broken?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall#comments</comments><dc:creator>heymdall</dc:creator><title>&quot;Польза&quot; от уязвимостей</title><pubDate>Wed, 26 Nov 2025 12:49:06 GMT</pubDate><description><![CDATA[Я вообще не очень люблю ныть, когда у меня нет какого-то конкретного предложения, как починить причину нытья, но тут что-то уже клинит.]]></description><content:encoded><![CDATA[
  <p id="seDW">Я вообще не очень люблю ныть, когда у меня нет какого-то конкретного предложения, как починить причину нытья, но тут что-то уже клинит.</p>
  <p id="yRry">Безопасность - это важно. Важно, чтобы все писали свой код так, чтобы его нельзя было просто взломать. Важно, чтобы мы не писали в своем коде <code>NODE_TLS_REJECT_UNAUTHORIZED</code>. Важно, чтобы библиотеки, которые обрабатывают http-запросы, не давали возможности сделать запрос типа <code>GET ../../../etc/passwd</code>.</p>
  <p id="pqTs">Но мне кажется, что за последнее время поиск уязвимостей в библиотеках превратился в какой-то абсурд. И мне кажется, что это может превратиться в историю про мальчика, который кричал &quot;волки&quot;.</p>
  <p id="TH4l">Рандомные примеры критических уязвимостей за последнее время:</p>
  <h3 id="b7Gs">Уязвимость в fast-redact</h3>
  <p id="u7Il"><a href="https://nvd.nist.gov/vuln/detail/CVE-2025-57319" target="_blank">CVE-2025-57319</a> - жуткая (high severity!) уязвимость в библиотеке, которая предназначена для маскирования данных в объектах. Часто используется в системах логирования. В чем же там суть? Какой-то секьюрити-ресёрчер обнаружил prototype pollution уязвимость в одном из методов библиотеки.</p>
  <p id="JBjo">Если передать в него специальным образом сконструированный объект - он может испортить глобальные прототипы всех объектов. В первую секунду ты думаешь &quot;да, действительно неприятно, надо чтобы это исправили&quot;. Но потом начинаешь смотреть на пример того, а как же это работает.</p>
  <p id="Oldf">Вот пример из самой уязвимости:</p>
  <pre id="GKyh" data-lang="javascript">// Create a custom object
const customObject = {};

// Craft the instructions to inject a property into Object.prototype
const instructions = [
  {
    target: customObject,
    path: [&quot;polluted&quot;, &quot;prototype&quot;, &quot;constructor&quot;],
    value: true
  }
];

// Call the vulnerable function with the crafted instructions
require(&quot;fast-redact/lib/modifiers&quot;).nestedRestore(instructions);

// Verify the exploit
console.log({}.polluted !== undefined ? &#x27;[POLLUTION_TRIGGERED]&#x27;:&#x27;&#x27;);
</pre>
  <p id="hpWS">Кажется, что чтобы это сработало в реальности - нужно либо допустить то, что ваши разработчики - злые буратины, которые пытаются заменить поля типа <code>constructor</code> и <code>prototype</code> в объекте, либо, что еще хуже, они дают возможность внешним пользователям определять &quot;а что же надо удалить из логов&quot;. И в том, и в другом случае - вам уже мало что поможет.</p>
  <p id="YYZ3">Но если посмотреть на уязвимость еще внимательнее - выяснится, что это вообще не реальный API библиотеки - это одна из внутренних функций библиотеки. Она не задокументирована и использоваться вообще не должна. А при использовании нормального внешнего API - даже злые или не очень сообразительные разработчики будут в безопасности:</p>
  <pre id="7hTT" data-lang="javascript">const fastRedact = require(&quot;fast-redact&quot;);

const customObject = {};

const redact = fastRedact({
  paths: [&#x27;polluted.prototype.constructor&#x27;],
});

console.log({}.polluted !== undefined ? &#x27;[POLLUTION_TRIGGERED]&#x27;:&#x27;&#x27;); // выведет &#x27;&#x27;
</pre>
  <p id="MOIK">Да, сейчас уязвимость перевели в статус disputed. Но какой ценой? Люди уже успели наделать бесчисленное количество issue, форков, кто-то (даже поняв, что проблемы реально нет!) сделал <a href="https://adventures.nodeland.dev/archive/from-fast-redact-to-slow-redact/" target="_blank">полностью свою реализацию библиотеки</a>.</p>
  <p id="dzJS">Принесло ли это пользу человечеству? Что-то я сомневаюсь.</p>
  <h3 id="hi4l">Уязвимость в докер-образах</h3>
  <p id="WJLR">Наши стандартные докер-образы основаны на node:alpine. В них почти нет лишних пакетов, и они почти совсем пустые - только код приложения и рантайм, чтобы его запустить. Да, иногда даже в совсем базовых пакетах (типа zlib или tzdata) обнаруживаются уязвимости, но это происходит не так уж и часто. Но вот недавно в кучу чатов начали стучаться. &quot;Аларм!&quot;, &quot;Все сломалось!&quot;, &quot;Мы в опасности!&quot;. Сканер нашел в базовых образах критические уязвимости с высоким приоритетом, а именно <a href="https://nvd.nist.gov/vuln/detail/CVE-2025-64756" target="_blank">CVE-2025-64756</a>. Откуда? Из пакета <code>glob</code>. Откуда у нас пакет <code>glob</code>? Из <code>npm</code>. Он является базовой частью node:alpine.</p>
  <p id="TM7G">А в чем там вообще уязвимость?</p>
  <p id="crFh">Оказывается, что уязвимость срабатывает только если использовать cli-интерфейс <code>glob</code>, запускать его с флагом <code>--cmd</code>. В таком случае, если злоумышленник создаст файл с именем вида <code>$(touch pwned)</code> и он попадет под glob - то код из имени файла успешно выполнится.</p>
  <p id="EuWX">Что ж, действительно уязвимость... Но только если вы используете этот самый пакет glob как cli-утилиту. Ну и если кто-то уже понаписал в вашу файловую систему файлов с командами в их именах (а как он их туда напихал? Он уже вас взломал?) </p>
  <p id="dYR9">Но у нас эта библиотека - зависимость зависимости. Никто никогда его не запускал и запускать не будет. Понятное дело, что правильным решением с точки зрения мейнтейнеров glob было бы выделить это все в отдельный пакет (что они и сделали, теперь есть отдельный <a href="https://www.npmjs.com/package/glob-bin" target="_blank">glob-bin</a>, в котором и уязвимость заодно починили). Да и вообще - виной всему любовь js-разработчиков к пакетам, в которых лежат еще пакеты, а в них - еще пакеты...</p>
  <p id="Inaf">Но вот реально, являлась ли эта уязвимость критичной в нашем конкретном случае? На мой взгляд - нет.</p>
  <h2 id="B2R4">Вместо вывода</h2>
  <p id="Jxmp">Проблема не в этих двух конкретных уязвимостях. Это просто то, что я легко вспомнил. Почти все уязвимости, с которыми я сталкивался за последнее время, являются именно такими мутными вещами. Всегда для их эксплуатации надо сделать какие то кривые вещи со стороны самих разработчиков. Всегда для исправления ставятся максимально сжатые сроки - починить их надо уже всера.</p>
  <p id="8ciJ">Как я в самом начале и сказал - у меня нет какого-то решения. Уязвимости надо искать. Их надо исправлять. Но ощущение, что что-то в этом процессе фундаментально неправильно - не покидает меня.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.akitov.info/boolean-is-bad-for-you</guid><link>https://blog.akitov.info/boolean-is-bad-for-you?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall</link><comments>https://blog.akitov.info/boolean-is-bad-for-you?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall#comments</comments><dc:creator>heymdall</dc:creator><title>Boolean - легкий способ сделать плохой API</title><pubDate>Sat, 07 Sep 2024 07:01:47 GMT</pubDate><description><![CDATA[Что? Почему? Это же прекрасный тип данных - всего два значения, которые так легко использовать...]]></description><content:encoded><![CDATA[
  <p id="MHmR">Что? Почему? Это же прекрасный тип данных - всего два значения, которые так легко использовать...</p>
  <p id="H5ij">Проще всего показать проблему на примере. Представьте, что мы делаем обертку над webpack, которая прячет в себя весь ужас вебпака и дает такой простой програмный API для использования:</p>
  <pre id="0xXJ" data-lang="typescript">function buildApp(entryPoint: string): Promise&lt;void&gt;;</pre>
  <p id="0WOu">Вроде бы всё просто и понятно. Чуть позже вы понимаете, что части ваших пользователей хочется немного настраивать вашу сборку - они хотят использовать <code>ts-loader</code> вместо <code>babel-loader</code> для обработки ts файлов.</p>
  <p id="XaQ3">Что-ж, доработаем наш API!</p>
  <pre id="P0qg" data-lang="typescript">function buildApp(
  entryPoint: string,
  useTsLoader: boolean = false,
): Promise&lt;void&gt;;</pre>
  <p id="wgBf">При вызове это выглядит как то так:</p>
  <pre id="O5So" data-lang="typescript">await buildApp(&#x27;./my-entry.tsx&#x27;, true);</pre>
  <p id="ahkl">Конечно же любой опытный разработчик сразу поймет, что лучше бы переписать это API чтобы он принимал объект, а не отдельные аргументы. Если читать вызов в текущем варианте - вообще не понятно что же за <code>true</code> передается тут во втором аргументе</p>
  <pre id="sBHm" data-lang="typescript">type BuildAppParams = {
  entryPoint: string;
  useTsLoader?: boolean;
}
function buildApp({
  entryPoint,
  useTsLoader = false,
}: BuildAppParams): Promise&lt;void&gt;;

// вызов
buildApp({
  entryPoint: &#x27;./my-entry.tsx&#x27;,
  useTsLoader: true,
});</pre>
  <p id="bV0s">Красота? Вроде бы все понятно?</p>
  <p id="cCMk">Нет. А что если мы напишем <code>useTsLoader: false</code>? Что это вообще будет означать? Что будет использоваться вместо него? Конечно можно прочитать документацию и понять какое будет поведение..</p>
  <p id="fmXY">А что если через какое то время мы захотим добавить еще немного гибкости, и давать возможность использовать например <code>swc</code> или <code>esbuild</code>?</p>
  <pre id="eZrL" data-lang="typescript">type BuildAppParams = {
  entryPoint: string;
  useTsLoader?: boolean;
  useSwcLoader?: boolean;
};
function buildApp(options: BuildAppParams): Promise&lt;void&gt;;
</pre>
  <p id="cdz7">Теперь вопрос - что будет происходить когда и <code>useTsLoader</code>, и <code>useSwcLoader</code> выставлены в <code>true</code>? Наверное можно указать в документации что использование параметров одновременно - некорректно, или даже попробовать починить это на уровне типов:</p>
  <pre id="Obwt" data-lang="typescript">type BuildAppPrams = {
  entryPoint: string;
} &amp; ({
  useTsLoader: true;
  useSwcLoader?: false;
} | {
  useTsLoader?: false;
  useSwcLoader: true;
} | {
  useTsLoader?: false;
  useSwcLoader?: false;
})

// валидно:
buildApp({
  entryPoint: &#x27;./my-entry.tsx&#x27;,
});
buildApp({
  entryPoint: &#x27;./my-entry.tsx&#x27;, useTsLoader: true,
});
buildApp({
  entryPoint: &#x27;./my-entry.tsx&#x27;, useSwcLoader: true,
});
// ошибка от ts:
buildApp({
  entryPoint: &#x27;./my-entry.tsx&#x27;,
  useSwcLoader: true,
  useTsLoader: true,
});</pre>
  <p id="rQyN">Но согласитесь, смотреть на такие типы становится больно, и очень редко кто-то действительно строит такие типы.</p>
  <h2 id="Oa65">Что же делать?</h2>
  <p id="U7ps">Очевидно, использовать перечисляемые типы! enum в ts недолюбливают, но есть понятная альтернатива - union + literal types.</p>
  <pre id="f8Sr" data-lang="typescript">type BuildAppParams = {
  entryPoint: string;
  loader?: &#x27;ts&#x27; | &#x27;babel&#x27; | &#x27;swc&#x27;;
};

buildApp({ entryPoint: &#x27;./my-entry.tsx&#x27;, loader: &#x27;ts&#x27; });</pre>
  <p id="lNmB">Этот вариант стоит использовать даже если на текущий момент у вас предполагается всего два варианта - кто знает как захочется расширить API в будущем?</p>
  <p id="sYWG">Другой вариант, <a href="https://martinfowler.com/bliki/FlagArgument.html" target="_blank">предлагаемый Мартином Фаулером</a> - делать полность отдельные методы вместо использования флагов:</p>
  <pre id="YFZe" data-lang="typescript">function buildAppWithBabel(entryPoint: string): Promise&lt;void&gt;;
function buildAppWithTs(entryPoint: string): Promise&lt;void&gt;;
function buildAppWithSwc(entryPoint: string): Promise&lt;void&gt;;</pre>
  <p id="Tgca">Мне персонально такой вариант в мире react кажется менее удобным, но полноценных аргументов кроме вкусовщины на это у меня нет.</p>
  <p id="ZpaI">Конечно, бывают варианты, когда <code>boolean</code> является очевидным и правильным решением. Условный <code>setModalOpen(boolean)</code> будет понятен, и вариантов с наполовину открытой модалкой у вас скорее всего не появится. Но даже в подобных случаях лучше задумываться - например проп для селекта <code>defaultOpen</code> возможно стоит заменить на <code>defaultState: &#x27;open&#x27; | &#x27;closed&#x27;</code> - вдруг вы захотите менять его поведение в зависимости от количества опций?</p>
  <p id="BbW7">Вообщем проектируйте апи правильно, думайте не только о том как удобно написать вам сейчас, но и как оно будет работать потом, и как это будут использовать.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.akitov.info/code-review-levels</guid><link>https://blog.akitov.info/code-review-levels?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall</link><comments>https://blog.akitov.info/code-review-levels?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall#comments</comments><dc:creator>heymdall</dc:creator><title>Про код ревью - как перестать докапываться до мелочей и начать получать удовольствие</title><pubDate>Sat, 07 Sep 2024 06:58:40 GMT</pubDate><description><![CDATA[Сделать так, чтобы все писали код одинаково - невозможно. Как бы нам не хотелось чтобы все делали все абсолютно так же как и мы - это не реально. У нас у всех разный опыт, разный бекграунд и разные подходы к написанию одного и того же.]]></description><content:encoded><![CDATA[
  <p id="s8qm">Сделать так, чтобы все писали код одинаково - невозможно. Как бы нам не хотелось чтобы все делали все абсолютно так же как и мы - это не реально. У нас у всех разный опыт, разный бекграунд и разные подходы к написанию одного и того же.</p>
  <p id="AP23">Тем не менее зачастую разработчики пытаются сделать на ревью именно это. Советы по тому, что в коде стоит отделять дополнительным <code>\\n</code>, рекомендации использовать один метод вместо другого (ведь так будет на 1 строчку короче!), настоятельные просьбы вынести что-то в отдельную функцию…</p>
  <p id="NQ0n">А точно ли все эти комментарии нужны?</p>
  <h2 id="JpjN">Уровни комментариев</h2>
  <p id="TQZy">Содержимое любого ПР-а можно условно разделить на 5 уровней:</p>
  <ol id="74HG">
    <li id="XNU0">Архитектурный. Это то, <strong>что делает фича</strong>, какие системы вызываются, как именно устроено взаимодействие с ними.</li>
    <li id="WxfF">Фичёвый. А <strong>как фича реализована</strong>? Покрыты ли все нужные в бизнес-логике кейсы? Будет ли код работать корректно в специфичных кейсах?</li>
    <li id="ZcR2">Структурный. Это то, <strong>как код структурирован</strong>. На какие модули он разбит, как эти модули внутри взаимодействуют</li>
    <li id="ETdO">Уровень кода. Это то, <strong>как внутри устроены модули</strong>. Как называются переменные, какие фичи языка используются, как реализованы какие то алгоритмы.</li>
    <li id="UNpo">Уровень форматирования. Это то, <strong>как код выглядит</strong>. Пробелы, комментарии в коде, какие кавычки использованы - относится сюда.</li>
  </ol>
  <p id="2Uzx">Комментарии к пул-реквесту чаще всего относятся к одному из этих уровней. И на мой взгляд первому и последнему уровню не место на этапе пул-реквеста. Остальные же можно и нужно пытаться минимизировать.</p>
  <h3 id="m9fb">Архитектурные</h3>
  <p id="qJ5Q">Предположим какой то разработчик уже проделал большую работу, сделал новую фичу, а потом приходит кто-то и говорит что надо было вообще использовать другой микросервис/писать в другую базу/реализовывать всё это в другом модуле. Это <strong>архитектурные</strong> замечания.</p>
  <p id="O1yq">Если у вас возникают архитектурные вопросы на этапе пул-реквеста - кажется у вас что-то не так с процессом разработки/аналитики. Либо реализацию не обсудили с заинтересованными сторонами, либо не потратили достаточно времени на дискавери. В большинстве случаев на этом этапе логичнее всего сложить это замечание в беклог, а текущую реализацию помержить как есть. Как убедиться что задача из беклога будет сделана - отдельная большая тема, но сейчас оставим её за скобками.</p>
  <h3 id="V1Je">Фичевые</h3>
  <p id="qxLL"><strong>Фичевые</strong> комментарии - самые полезные при погружении в проект. Это те вещи, которые могут знать аналитики или те, кто давно работает над проектом. “А если придет пользователь с 500 записями?”, “А не забыли ли мы про мобильную версию”. Сюда же можно отнести и комментарии по нефункциональным требованиям - “Этот сервис должен маскировать данные, которые он отправляет в логи”, “Надо написать тесты” и так далее.</p>
  <p id="rHdF">Это полезные комментарии, и если у вы хотите такой написать - не стоит колебаться. Конечно, можно сказать что такие вещи должны отлавливаться на этапе сбора требований, но в реальности при какой-либо agile разработке учесть всё - очень тяжело.</p>
  <h3 id="13R8">Структурные</h3>
  <p id="xxyF"><strong>Структурные</strong> комментарии объясняют как стоит склеивать код из мелких кусочков. Что нужно выносить в отдельные функции? Может быть есть слой, в котором должно происходить любое взаимодействие с базами данных? Или вообще такой код у вас обычно размещается в библиотеке?</p>
  <p id="6JpG">Такие коменты могут возникать независимо от уровня разработчика, написавшего код. Если вы хотите снижать их количество - фиксируйте договоренности о структуре и пишите их в ридми вашего проекта.</p>
  <h3 id="mSFg">Про код</h3>
  <p id="IJdk">Комментарии, относящиеся к <strong>уровню кода</strong> могут быть полезны начинающим/людям которые только присоединились к проекту. Но тут нужно быть осторожными, и не пытаться заставлять всех писать в точности так, как пишите вы. Запись <code>if (items.length == 0)</code> и запись <code>if (!items.length)</code> эквиваленты для ts. Как писать правильно? По моему субъективному мнению первая запись понятнее, но это именно субъективное мнение. Стоит ли писать про это при ревью? Если у вас нигде не зафиксированы договоренности об этом и у вас нет цели научить разработчика - вполне возможно что правильным решением будет промолчать. В то же время если в новом коде все переменные названы одной рандомной буквой - молчать нельзя.</p>
  <p id="rghb">Многие комментарии с этого уровня могут решаться автоматическими проверками. Линтеры, code-quality инструменты - все они нужны чтобы снять нагрузку на отлавливание мелочей с разработчиков и переложить их на уровень машин. Если вы замечаете что часто пишите комментарии на этом уровне - подумайте об автоматизации.</p>
  <h3 id="FI2N">Форматирование</h3>
  <p id="KCgF">Комментарии про отсутствующий пробел или не ту форму кавычек - это просто трата времени. Это уровень <strong>форматирования</strong>, и он должен решаться инструментами. Для большинства языков есть автоматические форматеры. prettier в js, gofmt в go, autopep8 для python и так далее. Если тот код, который получается на выходе из таких инструментов вас не устраивает (он не такой красивый!) - у вас есть два варианта - смириться или сделать свой инструмент, который будет выдавать такой код, который будет вам казаться эстетичным. Только сделайте так, чтобы этот инструмент работал не только на вашем компьютере, но и у других разработчиков.</p>
  <h2 id="vSgx">Критичность комментариев</h2>
  <p id="62br">Кроме разделения на “уровень” комментариев, их можно (и нужно!) разделять и по их критичности. Некоторые вещи могут быть простым замечанием - если его проигнорировать - об этом забудется очень скоро. Какие то могут быть важными моментами, на которые автору стоит обратить внимание и постараться это исправить. Ну и некоторые комментарии могут быть блокерами. Код с такими комментариями не должен попасть в мастер ни при каких условиях.</p>
  <p id="OXpg">У всех известных инструментов для работы с гит есть возможность поставить блокирующий комментарий - NEED_WORKS в битбакете, request changes в гитхабе/гитлабе. Не стоит разбрасываться таким статусом по каждой мелочи. Блокирующие комментарии по <strong>уровню кода</strong> - странный выбор. Простановка такого статуса - это повод задуматься о том, что нужно поменять чтобы таких ситуаций не возникало.</p>
  <p id="96E8">Для разделения между двумя другими уровнями критичности никаких инструментов нет. В команде лучше всего выработать договоренности о том, как именно их разделять. Одним из популярных вариантов является префикс <code>nit:</code> для комментариев низкой критичности. Оставляя такой комментарий вы должны быть готовы что его проигнорируют. Получая - вы можете его проигнорировать (но всё же стоит о нём хотя бы задуматься - может быть там действительно ценное замечание?)</p>
  <h2 id="Gw7X">Выводы?</h2>
  <p id="DVHK">Ну а тут должен идти какой то разумный вывод, который логически вытекает из всего этого потока мыслей. Что вот мол, если обращать внимание на то, какой “уровень” вы комментируете, и постоянно задумываться над вопросом “а что надо сделать чтобы больше таких коментов не писать” - можно получить быстрые и приятные код-ревью, которые будут приятны и ревьюверам, и авторам кода. Но пока этого вывода тут нет.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.akitov.info/js-tools-is-painfull</guid><link>https://blog.akitov.info/js-tools-is-painfull?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall</link><comments>https://blog.akitov.info/js-tools-is-painfull?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=heymdall#comments</comments><dc:creator>heymdall</dc:creator><title>Нытье про js тулинг</title><pubDate>Sat, 07 Sep 2024 06:57:18 GMT</pubDate><description><![CDATA[Иногда я напитываюсь огромных количеством ненависти к тому, как устроена вся “экосистема” фронтенда. Это просто дикий набор костылей, который работает просто на удаче.]]></description><content:encoded><![CDATA[
  <p id="9sxR">Иногда я напитываюсь огромных количеством ненависти к тому, как устроена вся “экосистема” фронтенда. Это просто дикий набор костылей, который работает просто на удаче.</p>
  <p id="g5h8">Исследую возможность добавить vite в свою обертку вокруг дев тулзов для дев режима. В целом понятно что это будет приносить проблемы, абсолютно ожидаемо я читаю огромное кол-во issue, разбираюсь какие отличия есть в разных методах настройки и сборки и так далее. Но по сути - за день я получил вполне рабочий прототип.</p>
  <p id="TRGR">В процессе обнаруживается что vite, будучи нацеленным в первую очередь на esm ругается на одну из зависимостей наших пакетов. Пакет <code>A</code> (библиотека компонентов) импортирует в себя пакет <code>B</code>(набор тулзов), а у него внутри некорректное поле main в package.json. Чтож, можно же поправить!</p>
  <p id="OoTh">Идем в пакет <code>B</code>, видим что там уже всё поправлено - добавлено поле <code>exports</code>, которое имеет более высокий приоритет, и все сборщики (что вебпак, что vite) прекрасно с ним работают. Нужно просто обновить версию - и все будет отлично.</p>
  <p id="SrZy">Идем, обновляем. Сборка проходит. Запускаем тесты - видим что теперь jest не понимает как с этим работать. Читаем внимательнее, понимаем что в библиотеке компонентов jest версии 26, а с полями exports jest научился работать только в 28.</p>
  <p id="LM9W">Обновляем до 28 версии - видим 100+ ошибок о том, что теперь jest вроде как встречает неизвестный токен <code>export</code> в зависимости зависимости! Хотя казалось бы, мы же вроде поддержку esm должны были получить после обновления…</p>
  <p id="l0EM">Смотрим в пакет на который ругается, видим что в его package.json написано такое:</p>
  <pre id="9XTu" data-lang="javascript">  &quot;main&quot;: &quot;./dist/index.js&quot;,
  &quot;exports&quot;: {
    &quot;.&quot;: {
      &quot;node&quot;: {
        &quot;module&quot;: &quot;./dist/esm-node/index.js&quot;,
        &quot;require&quot;: &quot;./dist/index.js&quot;,
        &quot;import&quot;: &quot;./wrapper.mjs&quot;
      },
      &quot;default&quot;: &quot;./dist/esm-browser/index.js&quot;
    },
    &quot;./package.json&quot;: &quot;./package.json&quot;
  },
</pre>
  <p id="A0m1">Ругается наш jest именно на <code>esm-browser/index.js</code>. Проверяем - руками в node_modules меняем default на <code>./dist/index.js</code> - тесты идут.</p>
  <p id="xQk0">Таак. И че делать? Наобум пробуем обновить jest еще дальше, на 29 версию, получаем полное расхождение всех снапшотов + проблемы с jsdom. Ок, не катит.</p>
  <p id="m4TO">Вроде vitest есть! Он же совместим почти полностью по апи, и построен сразу с идеей нормальной работы с esm-модулями!</p>
  <p id="onc4">Пробуем перейти на него. Мигрируем код <a href="https://github.com/trivikr/vitest-codemod" target="_blank">код-модом</a>, это же не долго! Запускаем. Получаем кучу изменений, но вроде бы вполне вменяемых. <code>yarn vitest</code>… не, ну конечно оно не запустилось. Выясняется что <code>window.computedStyle</code> нет в jsdom! Это патчится в jest какими то костылями, но vitest логично решили что это не их дело - пусть пользователи <a href="https://github.com/vitest-dev/vitest/issues/2061" target="_blank">сами разбираются</a>.</p>
  <p id="p29K">Напоминаю, я просто хотел апнуть версию одной зависимости. Кажется переход на другой тестовый фреймворк для этого - слишком жирно.</p>
  <p id="QGD8">Читаем внимательно то, как можно конфигурировать jest. Вроде в вебпаке можно было указывать поле в package, из которого должен браться resolution…</p>
  <p id="YCg7">Такого апи нет, но можно написать свой резолвер! Пробираемся через дебри не очень подробной документации, смотрим как написаны другие резолверы, делаем свой. Отлавливаем баги, вроде все запускается.</p>
  <p id="T34D">На данном этапе на это ушло уже несколько часов, а изначальная задачка еще совсем не решена. Но мы же уже близко?</p>
  <p id="lAGV">Локально тесты проходят. Создаем пр, пушим нашу ветку. Тесты падают в ci. Понимаем что наш резолвер работает не совсем корректно. Потом вспоминаем что часть разработчиков вообще сидит на windows, и наш резолвер вообще не умеет работать с отличными от <code>/</code> разделителями. Может пойти и просто поправить зависимости в core-components?</p>
  <p id="68Hl">Теперь все это напоминает чудесный отрывок из шоу “Malcolm in the middle “</p>
  <p id="SFy1"><a href="https://youtu.be/_UZFI-8D5uA?si=yzBwabQNHgtBYm9_" target="_blank">https://youtu.be/<em>UZFI-8D5uA?si=yzBwabQNHgtBYm9</em></a></p>
  <p id="FYS2">Короче говоря - в такие моменты хочется просто забить на весь этот тулинг, esm/cjs, тесты и вообще всё что связано с инструментами.</p>
  <p id="nbMY">Хочется писать в блокноте код на jquery, рисовать скруглённые уголки таблицами и заливать всё это на сервер через ftp. А не вот это вот все.</p>

]]></content:encoded></item></channel></rss>