<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: bsideeffect</title>
    <description>The latest articles on DEV Community by bsideeffect (@bsideeffect).</description>
    <link>https://dev.to/bsideeffect</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F793821%2Fe225e1af-c5bb-4c89-b417-3f55f8f4a684.jpeg</url>
      <title>DEV Community: bsideeffect</title>
      <link>https://dev.to/bsideeffect</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bsideeffect"/>
    <language>en</language>
    <item>
      <title>Creating Environment Files from Templates with Bash</title>
      <dc:creator>bsideeffect</dc:creator>
      <pubDate>Tue, 16 Dec 2025 12:20:22 +0000</pubDate>
      <link>https://dev.to/bsideeffect/creating-environment-files-from-templates-with-bash-2mh5</link>
      <guid>https://dev.to/bsideeffect/creating-environment-files-from-templates-with-bash-2mh5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Environment files tend to start simple and slowly turn into a liability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, you copy .env.template, change a few values, and move on. But as projects grow-multiple apps, multiple environments, multiple developers-that manual copying quickly becomes repetitive and error-prone.&lt;/p&gt;

&lt;p&gt;A small Bash script can turn this process into something safer and more intentional: generating environment files from a template and filling in the missing values interactively.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Idea: Treat .env as a Template
&lt;/h2&gt;

&lt;p&gt;Instead of committing a ready-to-use .env.example, we start with a true template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;{APP_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;{DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every required value is marked explicitly using placeholders. If a variable exists in the template, it must be filled in.&lt;/p&gt;

&lt;p&gt;This makes missing configuration impossible to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a Bot-Specific Env File
&lt;/h2&gt;

&lt;p&gt;The script starts by copying the template into a new, app-specific file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ENV_TEMPLATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./.env.template"&lt;/span&gt;
&lt;span class="nv"&gt;ENV_OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./.env.&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.local"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"📝 Creating env file at &lt;/span&gt;&lt;span class="nv"&gt;$ENV_OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ENV_TEMPLATE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ENV_OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Detect All Placeholders Automatically
&lt;/h2&gt;

&lt;p&gt;Instead of hardcoding variable names, the script scans the file for placeholders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;placeholders&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oE&lt;/span&gt; &lt;span class="s1"&gt;'\{\{[^}]+\}\}'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ENV_OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Prompt the User for Values
&lt;/h2&gt;

&lt;p&gt;For each placeholder, the script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;removes the curly braces&lt;/li&gt;
&lt;li&gt;asks the user for a value&lt;/li&gt;
&lt;li&gt;replaces it everywhere in the file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;placeholder &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$placeholders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;clean_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;clean_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;clean_name&lt;/span&gt;&lt;span class="p"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Enter value for &lt;/span&gt;&lt;span class="nv"&gt;$clean_name&lt;/span&gt;&lt;span class="s2"&gt;: "&lt;/span&gt; value

  &lt;span class="nv"&gt;safe_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[\/&amp;amp;]/\\&amp;amp;/g'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;safe_placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$placeholder&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[\/&amp;amp;]/\\&amp;amp;/g'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s2"&gt;"s/&lt;/span&gt;&lt;span class="nv"&gt;$safe_placeholder&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$safe_value&lt;/span&gt;&lt;span class="s2"&gt;/g"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ENV_OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User input can contain special characters, so the script escapes both the placeholder and the value&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This kind of script doesn't replace a secrets manager or a full provisioning system - but it fills an important gap between "manual copying" and "heavy infrastructure tooling."&lt;/p&gt;

&lt;p&gt;Sometimes the best automation is small, local, and boring.&lt;/p&gt;

&lt;p&gt;And that's exactly what you want for environment variables.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>automation</category>
    </item>
    <item>
      <title>Ускоряем запуск юнит-тестов</title>
      <dc:creator>bsideeffect</dc:creator>
      <pubDate>Sat, 06 Jan 2024 18:53:56 +0000</pubDate>
      <link>https://dev.to/bsideeffect/uskoriaiem-zapusk-iunit-tiestov-15p0</link>
      <guid>https://dev.to/bsideeffect/uskoriaiem-zapusk-iunit-tiestov-15p0</guid>
      <description>&lt;p&gt;С ростом проекта юнит-тестов становится все больше, а время их выполнения увеличивается. Медленная работа Jest ухудшает DX и замедляет прохождение CI/CD. Это можно исправить.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Дисклеймер&lt;/strong&gt;. Показанные ниже способы ускорения Jest будут отличаться в зависимости от мощности устройства, среды разработки, количества и качества тестов.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Теория
&lt;/h2&gt;

&lt;p&gt;Давайте разберемся, как Jest использует ресурсы системы при выполнении тестов.&lt;/p&gt;

&lt;p&gt;Одно ядро резервируется для работы CLI. Для остальных ядер создается по воркеру. Воркеры выполняют тесты параллельно друг другу. На устройстве с 8-ядерным процессором параллельно работают 7 воркеров.&lt;/p&gt;

&lt;p&gt;Проверить количество воркеров можно с помощью команды&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx jest --showConfig | grep maxWorkers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;При запуске Jest с флагом &lt;code&gt;--watch&lt;/code&gt;, воркеров будет в 2 раза меньше.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jest распределяет тестовые наборы по воркерам &lt;a href="https://jestjs.io/blog/2016/03/11/javascript-unit-testing-performance" rel="noopener noreferrer"&gt;равномерно&lt;/a&gt;. Благодаря этому воркеры заканчивают выполнение тестов одновременно.&lt;/p&gt;

&lt;h2&gt;
  
  
  Замеряем текущую скорость
&lt;/h2&gt;

&lt;p&gt;Замерим исходное время прохождения тестов:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx jest --no-cache --coverage=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Обратим внимание на 2 вещи: время работы команды (внизу) и время выполнения каждого отдельного файла (справа).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS tests/test-suite-1.test.ts (10.045s)
PASS tests/test-suite-2.test.ts (9.152s)
PASS tests/test-suite-3.test.ts (15.538s)
...
PASS tests/test-suite-146.test.ts (3.522s)
PASS tests/test-suite-147.test.ts (4.958s)
PASS tests/test-suite-148.test.ts (2.216s)

Test Suites: 148 passed, 148 total
Tests:       478 passed, 478 total
Snapshots:   0 total
Time:        152.774 s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Если тесты в файле выполняются дольше 5 секунд, Jest выводит затраченное время рядом с именем файла. Это значение настраивается с помощью опции &lt;a href="https://jestjs.io/ru/docs/configuration#slowtestthreshold-number" rel="noopener noreferrer"&gt;&lt;code&gt;slowTestThreshold&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Итак, 148 тестовых наборов выполняются за 152 секунды. Максимальное время выполнения одного набора – 19.5 секунд. Минимальное – 0.25 секунд. Среднее – 6.6 секунд.&lt;/p&gt;

&lt;h2&gt;
  
  
  Уменьшаем количество воркеров
&lt;/h2&gt;

&lt;p&gt;Jest сильно нагружает систему, используя большинство ядер для выполнения тестов. Из-за этого ухудшается итоговая производительность, что приводит к появлению флаки-тестов.&lt;/p&gt;

&lt;p&gt;Проверим, уменьшится ли время работы Jest, если использовать только три четверти ядер:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx jest --maxWorkers=75% --no-cache --coverage=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Задавать значения &lt;code&gt;maxWorkers&lt;/code&gt; можно в числах, либо в процентах.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Можно провести бенчмарк для разных значений &lt;code&gt;--maxWorkers&lt;/code&gt;, чтобы найти оптимальное количество воркеров. В моем случае это 4 воркера.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workers&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Max&lt;/th&gt;
&lt;th&gt;Avg&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;152s&lt;/td&gt;
&lt;td&gt;26.7s&lt;/td&gt;
&lt;td&gt;7.9s&lt;/td&gt;
&lt;td&gt;1161s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;114s (-25%)&lt;/td&gt;
&lt;td&gt;15.5s&lt;/td&gt;
&lt;td&gt;4.4s&lt;/td&gt;
&lt;td&gt;652s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;95s  (-37%) 🏆&lt;/td&gt;
&lt;td&gt;8.2s&lt;/td&gt;
&lt;td&gt;2.4s&lt;/td&gt;
&lt;td&gt;363s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;105s (-30%)&lt;/td&gt;
&lt;td&gt;5.8s&lt;/td&gt;
&lt;td&gt;1.4s&lt;/td&gt;
&lt;td&gt;209s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;161s (+6%)&lt;/td&gt;
&lt;td&gt;4.9s.&lt;/td&gt;
&lt;td&gt;1.1s&lt;/td&gt;
&lt;td&gt;159s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Любопытно, что с одним ядром тесты выполняются всего на 6% медленнее, чем при использовании всех 7 ядер. При этом, каждый тестовый набор в среднем (&lt;em&gt;Avg&lt;/em&gt;) прогоняется почти в 8 раз быстрее.&lt;/p&gt;

&lt;h2&gt;
  
  
  Используем более производительный компилятор TS
&lt;/h2&gt;

&lt;p&gt;Jest использует &lt;code&gt;babel-jest&lt;/code&gt; для компиляции TypeScript. Если использовать более быстрые инструменты, можно ускорить общее время выполнения тестов.&lt;/p&gt;

&lt;p&gt;Одним из возможных решений является &lt;code&gt;swc/jest&lt;/code&gt;. Это трансформер, использующий производительный Rust для компиляции TS-файлов.&lt;/p&gt;

&lt;p&gt;Чтобы его подключить, установим его в качестве dev-зависимости:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @swc/jest -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Затем обновим конфиг Jest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// jest.config.js

module.exports = {
  transform: {
    '.*\\.(tsx?)$': [
      '@swc/jest',
      {
        jsc: {
          transform: {
            react: {
              runtime: 'automatic',
            },
          },
        },
      },
    ],
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Проверим, ускорится ли время работы Jest при использовании SWC:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workers&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Max&lt;/th&gt;
&lt;th&gt;Avg&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;118s&lt;/td&gt;
&lt;td&gt;17.1s&lt;/td&gt;
&lt;td&gt;5.9s&lt;/td&gt;
&lt;td&gt;866s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;104s (-12%)&lt;/td&gt;
&lt;td&gt;21.5s&lt;/td&gt;
&lt;td&gt;3.9s&lt;/td&gt;
&lt;td&gt;590s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;77s  (-34%) 🏆&lt;/td&gt;
&lt;td&gt;6.1s&lt;/td&gt;
&lt;td&gt;1.9s&lt;/td&gt;
&lt;td&gt;294s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;98s  (-17%)&lt;/td&gt;
&lt;td&gt;3.9s&lt;/td&gt;
&lt;td&gt;1.3s&lt;/td&gt;
&lt;td&gt;193s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;134s (+13%)&lt;/td&gt;
&lt;td&gt;3.1s.&lt;/td&gt;
&lt;td&gt;1.1s&lt;/td&gt;
&lt;td&gt;130s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Как видно, 4 воркера снова показали лучший результат. При этом, скорость увеличилась на 50% относительно изначального значения.&lt;/p&gt;

&lt;h2&gt;
  
  
  Избавляемся от утечек памяти
&lt;/h2&gt;

&lt;p&gt;Перед выполнением каждого теста Jest формирует &lt;em&gt;require cache&lt;/em&gt;. Это дерево зависимостей, необходимых для этого теста. После выполнения теста дерево зависимостей очищается. Таким образом Jest создает изолированную среду для выполнения тестов.&lt;/p&gt;

&lt;p&gt;Если Jest эффективно чистит require cache, то память, выделенная под дерево зависимостей, полностью высвобождается. Однако в некоторых ситуациях garbage collector не срабатывает, в результате чего происходит утечка памяти.&lt;/p&gt;

&lt;p&gt;Причины утечки могут быть различные. Одна из часто встречающихся – использование файлов реэкспорта. Это файлы, которые экспортируют другие модули, при этом сами по себе не содержат кода. Jest не знает, где именно в этом файле находится нужный модуль, поэтому при построении дерева зависимостей добавляет туда все экспортируемые модули (а также их зависимости). Такой паттерн часто встречается в больших библиотеках вроде MUI (Material UI).&lt;/p&gt;

&lt;p&gt;Проверим, есть ли подобная проблема с нашими тестами. Для этого запустим Jest в режиме профилирования используемой памяти (&lt;code&gt;--logHeapUsage&lt;/code&gt;). Необходимо запускать все тесты последовательно в одном треде, поэтому нужно поставить флаг &lt;code&gt;--maxWokers=1&lt;/code&gt; или его аналог &lt;code&gt;--runInBand&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --expose-gc ./node_modules/.bin/jest --logHeapUsage --maxWorkers=1 --no-cache --coverage=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Если количество выделенной памяти не увеличивается – значит, утечек памяти нет. Jest успешно чистит кэш между тестами, а Garbage collector высвобождает ненужную память.&lt;/p&gt;

&lt;p&gt;Если же количество выделенной памяти стремительно растет, то она очищается не эффективно.&lt;/p&gt;

&lt;p&gt;В моем случае каждый тест увеличивал используемую память на 100-200Мб.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS tests/test-suite-1.test.ts (502 MB heap size)
PASS tests/test-suite-2.test.ts (576 MB heap size)
PASS tests/test-suite-3.test.ts (646 MB heap size)
...
PASS tests/test-suite-146.test.ts (3179 MB heap size)
PASS tests/test-suite-147.test.ts (3183 MB heap size)
PASS tests/test-suite-148.test.ts (3190 MB heap size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;На графике видно, что память принудительно очистилась, достигнув лимита на уровне около 3500Мб.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ks9j2xzhqss7djwo86c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ks9j2xzhqss7djwo86c.png" alt="Память очистилась, достигнув лимита на уровне около 3500Мб" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Чтобы найти проблемные файлы, можно воспользоваться экспериментальным флагом &lt;code&gt;--detectLeaks&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx jest --detectLeaks --no-cache --coverage=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Чтобы найти конкретное место протечки, запустим Jest через &lt;code&gt;node&lt;/code&gt; с флагом &lt;code&gt;--inspect-brk&lt;/code&gt;. Так мы сможем использовать Chrome DevTools для дебага:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --inspect-brk --expose-gc ./node_modules/.bin/jest --logHeapUsage --maxWorkers=1 --no-cache --coverage=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Затем откроем &lt;code&gt;chrome://inspect&lt;/code&gt; в Chrome и нажмем &lt;em&gt;Open dedicated DevTools for Node&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0yh5pwcyto3wfh5p36r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0yh5pwcyto3wfh5p36r.png" alt="DevTools" width="681" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Откроем вкладку &lt;em&gt;Memory&lt;/em&gt; и запустим профилирование в режиме &lt;em&gt;Allocation instrumentaion on timeline&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qqlejlamk6iddm5mgc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qqlejlamk6iddm5mgc9.png" alt="Вкладка Memory" width="781" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;После замены всех импортов иконок MUI с &lt;code&gt;named-импорта&lt;/code&gt; на &lt;code&gt;path-import&lt;/code&gt;, прирост утекающей памяти сократился в разы.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS tests/test-suite-1.test.ts (286 MB heap size)
PASS tests/test-suite-2.test.ts (277 MB heap size)
PASS tests/test-suite-3.test.ts (306 MB heap size)
PASS tests/test-suite-146.test.ts (289 MB heap size)
PASS tests/test-suite-147.test.ts (330 MB heap size)
PASS tests/test-suite-148.test.ts (364 MB heap size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Тесты стали выполняться за 24 секунды, что в 6 раз быстрее изначального значения!&lt;/p&gt;

&lt;p&gt;Чтобы избежать подобных проблем в будущем, можно добавить правило ESLint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  'no-restricted-imports': [
    'error',
    {
      paths: [
        {
          name: '@mui/icons-material',
          message: 'Please use path imports like @mui/icons-material/Alarm instead.',
        },
      ],
    },
  ],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Дополнительные ресурсы:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.developer.adobe.com/improve-jest-runner-performance-a8f56708ba94" rel="noopener noreferrer"&gt;Improve Jest Runner Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jestjs.io/blog/2016/03/11/javascript-unit-testing-performance" rel="noopener noreferrer"&gt;JavaScript Unit Testing Performance
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/vantanev/make-your-jest-tests-up-to-20-faster-by-changing-a-single-setting-i36"&gt;Make Your Jest Tests up to 20% Faster by Changing a Single Setting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://miyauchi.dev/posts/speeding-up-jest/" rel="noopener noreferrer"&gt;Speed ​​up TypeScript with Jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://making.close.com/posts/finding-the-cause-of-a-memory-leak-in-jest" rel="noopener noreferrer"&gt;Finding the cause of a memory leak in Jest tests&lt;/a&gt;
&lt;a href="https://plazagonzalo.medium.com/how-to-solve-memory-leak-problems-on-node-js-while-running-jest-a33839d49bb1&amp;amp;sca_esv=591216765&amp;amp;strip=1&amp;amp;vwsrc=0" rel="noopener noreferrer"&gt;How to solve the Memory Leak problem on Node.js while running Jest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://copyprogramming.com/howto/what-are-the-steps-to-follow-to-debug-memory-leak-in-jest" rel="noopener noreferrer"&gt;The process to identify and resolve memory leaks in Jest: A step-by-step guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@curtis.porter/jest-memory-in-kubernetes-833a25fc4838" rel="noopener noreferrer"&gt;Jest Memory in Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>jest</category>
      <category>unittest</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
