<?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>Forem: Wojciech Maj</title>
    <description>The latest articles on Forem by Wojciech Maj (@wojtekmaj).</description>
    <link>https://forem.com/wojtekmaj</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%2F13177%2Fd3d82639-5888-47bf-89f0-3e8eb2ddc9b9.jpg</url>
      <title>Forem: Wojciech Maj</title>
      <link>https://forem.com/wojtekmaj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/wojtekmaj"/>
    <language>en</language>
    <item>
      <title>Why using Bun in production (maybe) isn't the best idea</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Sun, 14 Sep 2025 22:24:15 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/why-using-bun-in-production-maybe-isnt-the-best-idea-3deb</link>
      <guid>https://forem.com/wojtekmaj/why-using-bun-in-production-maybe-isnt-the-best-idea-3deb</guid>
      <description>&lt;p&gt;Bun deserves credit. It's fast, ambitious, and it shook a JavaScript ecosystem that had once been stagnating. The pace of exciting innovations sped up significantly after Bun showed what an integrated experience could feel like. Node.js, once conservative to a fault, suddenly delivered: native TypeScript support, &lt;code&gt;fetch&lt;/code&gt; in core, built-in watch mode, an official test runner, &lt;code&gt;.env&lt;/code&gt; support. Bun lit the fire, and the whole ecosystem got warmer.&lt;/p&gt;

&lt;p&gt;That's a win for everyone. But production is where optimism meets entropy.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Be everything” or “be sustainable”?
&lt;/h2&gt;

&lt;p&gt;When &lt;strong&gt;Bun 1.0&lt;/strong&gt; launched, the pitch wasn't just “another runtime”. It aimed to replace &lt;strong&gt;Node itself&lt;/strong&gt; &lt;em&gt;and&lt;/em&gt; a half-dozen tools around it: &lt;code&gt;npx&lt;/code&gt;, &lt;code&gt;dotenv&lt;/code&gt;, &lt;code&gt;cross-env&lt;/code&gt;, &lt;code&gt;nodemon&lt;/code&gt;, &lt;code&gt;pm2&lt;/code&gt;, &lt;code&gt;ws&lt;/code&gt;, &lt;code&gt;node-fetch&lt;/code&gt;/&lt;code&gt;isomorphic-fetch&lt;/code&gt;, &lt;code&gt;tsc&lt;/code&gt;, Babel, &lt;code&gt;ts-node&lt;/code&gt;, &lt;code&gt;tsx&lt;/code&gt;. At the time, that all-in-one story felt like the future we were longing for.&lt;/p&gt;

&lt;p&gt;Two years later, many of those headline features &lt;strong&gt;landed in Node&lt;/strong&gt;. The parts Node &lt;em&gt;didn't&lt;/em&gt; absorb (bundling, package management, etc.) are arguably better left in userland, where specialization and rapid iteration thrive (think: Rolldown or LightningCSS). Not everything should be integrated into one runtime, because, respectfully, no single team can possibly excel at &lt;em&gt;everything at once&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance: yeah, it's fast, but…
&lt;/h2&gt;

&lt;p&gt;Bun's launch aura was speed. While their obsession for performance still stands and continues to push the industry forward, some of the charts they advertised Bun with were questionable from the start - like comparing against &lt;strong&gt;Yarn v1&lt;/strong&gt; when Yarn v3 was already available. Worse yet, &lt;strong&gt;the same charts are still featured prominently two years later&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Other headline numbers often lack context. Take “Bun is 5× faster than Vitest”. Sounds impressive, until you note that Vitest and Jest deliberately add overhead for &lt;strong&gt;test isolation&lt;/strong&gt;, making tests way more deterministic and debuggable. It's part of the reason why Jest even earned its crown back in the Mocha days.&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%2F9rpvaff0oeuul0p4imlo.gif" 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%2F9rpvaff0oeuul0p4imlo.gif" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ignoring those trade-offs is misleading. At best, it's incomplete. At worst, dishonest.&lt;/p&gt;

&lt;p&gt;Since then, the rest of the JS ecosystem didn't stand still. Node, npm, pnpm, Vitest, and others, all continued to improve. On top of that, community initiatives (e.g., &lt;a href="https://e18e.dev/" rel="noopener noreferrer"&gt;e18e&lt;/a&gt;) are driving performance wins across the entire ecosystem, not just Bun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portability &amp;amp; lock-in: easy to start, hard to stop
&lt;/h2&gt;

&lt;p&gt;Bun ships &lt;strong&gt;non-standard APIs&lt;/strong&gt; that may feel great on day one - but quietly tether you to Bun itself. It's tempting to &lt;code&gt;bun init&lt;/code&gt;, &lt;code&gt;bun test&lt;/code&gt;, and lean on helpers like &lt;code&gt;Bun.file&lt;/code&gt;, &lt;code&gt;Bun.serve&lt;/code&gt;, and &lt;code&gt;Bun.YAML.stringify&lt;/code&gt;. Migrating away later if something goes south? Good luck.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2029685779413487776-473" src="https://platform.twitter.com/embed/Tweet.html?id=2029685779413487776"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2029685779413487776-473');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2029685779413487776&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Probably not what they had in mind&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Consider the long-standing “&lt;a href="https://github.com/oven-sh/bun/issues/4145" rel="noopener noreferrer"&gt;Support Vitest&lt;/a&gt;” request. It was opened before Bun 1.0 and remains open today. If you want to have a go with Bun seriously, you're effectively pushed into using &lt;strong&gt;Bun's own test runner&lt;/strong&gt;. That seems convenient, until you want to move back to Node or another runtime and face an tedious migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioning &amp;amp; stability: version numbers are a contract
&lt;/h2&gt;

&lt;p&gt;After announcing &lt;code&gt;1.0&lt;/code&gt;, Bun shipped dozens of &lt;code&gt;1.0.x&lt;/code&gt; releases that included &lt;strong&gt;new features&lt;/strong&gt; - not just bug fixes - attempting to keep &lt;code&gt;1.1&lt;/code&gt; for the elephant in the room - Windows support.&lt;/p&gt;

&lt;p&gt;That simply isn't how semantic versioning works; it's closer to the internet-famous “&lt;a href="https://pridever.org/" rel="noopener noreferrer"&gt;pride versioning&lt;/a&gt;” joke:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PROUD.DEFAULT.SHAME&lt;/strong&gt;&lt;br&gt;
PROUD for changes you're proud of, DEFAULT for routine releases, SHAME for fixes you hope nobody notices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If &lt;em&gt;patch&lt;/em&gt; releases include new &lt;em&gt;features&lt;/em&gt;, what stops them from releasing a &lt;em&gt;minor&lt;/em&gt; release from shipping &lt;em&gt;breaking changes&lt;/em&gt;? We don't need to wonder, because that's EXACTLY what happened already! &lt;br&gt;
For example, Bun 1.1 changed the default &lt;code&gt;NODE_ENV&lt;/code&gt; value, changed the way conditional exports are resolved, and 1.1.26 changed &lt;code&gt;idleTimeout&lt;/code&gt; in &lt;code&gt;node:http&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For production teams, version numbers are a contract. They signal when it's safe to upgrade and when to brace for impact. If those signals can't be trusted, upgrades become roulette.&lt;/p&gt;

&lt;p&gt;Contrast with Node: today, Node ships fast on current releases, so you can try new features quickly. But there's also the &lt;strong&gt;battle-tested, super-stable LTS line&lt;/strong&gt; (that still receives some of the cool stuff from time to time!), and that dual model is critical. You can experiment at the edge, but when you need reliability, the LTS cadence gives you exactly that. That balance is what makes Node production-ready.&lt;/p&gt;
&lt;h2&gt;
  
  
  Questionable design choices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JSONC in &lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;: comments are handy, but making &lt;code&gt;package.json&lt;/code&gt; &lt;em&gt;not JSON&lt;/em&gt; breaks compatibility with every other tool. That's fragmentation, not progress.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Binary lockfile&lt;/strong&gt;: Bun originally shipped a binary lockfile that made PR reviews opaque - a dream scenario for anyone trying to sneak malicious code through. It later switched to text, but the format remains far less readable than Yarn's or pnpm's one. Hard-to-audit lockfiles weaken security culture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lifecycle scripts&lt;/strong&gt;: Bun doesn't run them by default (which partially explains its “faster installs” - less work is being done). Skipping scripts by default is a &lt;em&gt;fantastic&lt;/em&gt; idea that greatly improves ecosystem safety, and for this reason other package managers quickly adopted it as well. The problem lies in the details: Bun maintains an &lt;strong&gt;arbitrary allowlist of “popular packages”&lt;/strong&gt; whose scripts &lt;em&gt;do&lt;/em&gt; run. If you're listed, your &lt;code&gt;postinstall&lt;/code&gt; executes - great for you (or… for someone who &lt;a href="https://www.aikido.dev/blog/npm-debug-and-chalk-packages-compromised" rel="noopener noreferrer"&gt;compromised your npm account&lt;/a&gt;). If you're not, Bun users will need to run extra steps to make your package work. That's a perfect mix of no actual security and no actual convenience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  YOLO-driven roadmap &amp;amp; disregard for neighbors
&lt;/h2&gt;

&lt;p&gt;Bun often feels like it ships whatever won last week's Twitter poll. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/wqRnt1uwEjY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The speed Bun ships these features with can be intoxicating, but it also leads to overreach: &lt;strong&gt;a made-up &lt;code&gt;tsconfig.json&lt;/code&gt; flag&lt;/strong&gt;, &lt;code&gt;jsxSideEffects&lt;/code&gt;, was added in Bun 1.2.22. Think about it: this flag was dropped into TypeScript's namespace by a project other than TypeScript itself. If the TS team ever wanted to actually add that flag, confusion and breaking changes are inevitable.&lt;/p&gt;

&lt;p&gt;This also reminds me of &lt;strong&gt;the LightningCSS controversy&lt;/strong&gt; where instead of collaborating with the existing Rust project, whose author even provided C bindings and offered support, Bun &lt;strong&gt;ported it to Zig&lt;/strong&gt; and keeps a separate copy (did I mention something about userland and sustainability? I thought so…). &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1822020304753062281-495" src="https://platform.twitter.com/embed/Tweet.html?id=1822020304753062281"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1822020304753062281-495');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1822020304753062281&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Ouch. That's not how open source works. Whatever the license permits, &lt;strong&gt;ethics and ecosystem trust&lt;/strong&gt; matter.&lt;/p&gt;

&lt;p&gt;It paints a picture of a project more interested in going its own way than building alongside the wider community, and that's not the kind of foundation I would advise to rest production systems on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintenance signals: issue trackers don't lie
&lt;/h2&gt;

&lt;p&gt;As of today, Node - the runtime powering practically the entire planet, including your toothbrush, probably - carries about &lt;strong&gt;1.7k open issues&lt;/strong&gt;. Bun, much younger and - while popular - considerably far less adopted, has around &lt;strong&gt;4.7k&lt;/strong&gt;. Raw numbers are never telling us the full story, but the imbalance is striking. Node shoulders a global workload and yet manages a far leaner backlog. Bun, still in its infancy, is already swamped. That doesn't exactly inspire confidence for production workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  When would I &lt;em&gt;use&lt;/em&gt; Bun?
&lt;/h2&gt;

&lt;p&gt;This isn't “never use Bun.” It's “use it wisely.”&lt;/p&gt;

&lt;p&gt;Good fits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prototypes and playgrounds where the integrated DX speeds you up.&lt;/li&gt;
&lt;li&gt;Single-purpose CLIs or scripts where portability isn't critical.&lt;/li&gt;
&lt;li&gt;Projects in which performance matters more than anything else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guardrails if you adopt it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stick to &lt;strong&gt;standards&lt;/strong&gt;; isolate Bun specifics.&lt;/li&gt;
&lt;li&gt;Prefer &lt;strong&gt;portable tooling&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin versions&lt;/strong&gt;, read changelogs carefully, and test upgrades like you would a database migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Bun could do to earn a production seat
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treat &lt;strong&gt;semver as a contract&lt;/strong&gt;; features in minors, breakages in majors.&lt;/li&gt;
&lt;li&gt;Establish a &lt;strong&gt;clear LTS and release schedule&lt;/strong&gt; so teams know what's safe to adopt.&lt;/li&gt;
&lt;li&gt;Make &lt;strong&gt;benchmarks honest&lt;/strong&gt;: compare like with like, explain trade-offs.&lt;/li&gt;
&lt;li&gt;Prefer &lt;strong&gt;collaboration over duplication&lt;/strong&gt;: contribute upstream, coordinate publicly.&lt;/li&gt;
&lt;li&gt;Ship new features with a &lt;strong&gt;thoughtful, ecosystem-aware process&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Production depends on &lt;strong&gt;sustainability, predictability, and trust&lt;/strong&gt;. Right now, Bun's design choices, versioning, and marketing weaken those foundations. If these matter to you, think twice before building on Bun today.&lt;/p&gt;

&lt;p&gt;But don't get me wrong: Bun made the ecosystem better simply by existing. It reminded everyone what great DX can feel like, and it jolted Node into shipping long-awaited features. And it continues to do so! I'm genuinely thankful for that.&lt;/p&gt;

</description>
      <category>node</category>
      <category>bunjs</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Make your app install and run faster with nolyfill</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Wed, 25 Oct 2023 20:10:39 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/make-your-app-install-and-run-faster-with-nolyfill-25dk</link>
      <guid>https://forem.com/wojtekmaj/make-your-app-install-and-run-faster-with-nolyfill-25dk</guid>
      <description>&lt;p&gt;Do you use &lt;code&gt;eslint-plugin-import&lt;/code&gt;, &lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt;, &lt;code&gt;eslint-plugin-react&lt;/code&gt;? Of course you do! What do they have in common? They all contain &lt;strong&gt;tons of polyfills&lt;/strong&gt; to ensure backward compatibility. "With what?", you ask? With Node.js 4. NODE DOT JS VERSION FOUR. Released in 2015. "So?"&lt;/p&gt;

&lt;p&gt;These polyfills are &lt;strong&gt;totally useless&lt;/strong&gt;. Unless, of course, you run Node.js 4. They:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;impact install times,&lt;/li&gt;
&lt;li&gt;make your node_modules bigger,&lt;/li&gt;
&lt;li&gt;and make your app run slower (native implementations are rarely slower than their polyfills).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So what can you do?
&lt;/h2&gt;

&lt;p&gt;One way to deal with it is by forking such packages, stripping off useless dependencies, and re-releasing them under new names. This, however, is rarely worth it. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;eslint-plugin-i&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/un-es/eslint-plugin-i"&gt;&lt;code&gt;eslint-plugin-i&lt;/code&gt;&lt;/a&gt;, a fork of &lt;code&gt;eslint-plugin-import&lt;/code&gt;, is a good example of when it IS worth it. Not only they do the above, but also replace &lt;code&gt;tsconfig-paths&lt;/code&gt; and heavy typescript under the hood with &lt;code&gt;get-tsconfig&lt;/code&gt;. This resolves security issues &lt;code&gt;eslint-plugin-import&lt;/code&gt; has, vastly improves performance, and adds support for new TypeScript features. I highly recommend you replacing &lt;code&gt;eslint-plugin-import&lt;/code&gt; with &lt;code&gt;eslint-plugin-i&lt;/code&gt;, and if I'm not convincing enough, perhaps &lt;a href="https://github.com/import-js/eslint-plugin-import/pull/2447"&gt;pure madness exhibited by &lt;code&gt;eslint-plugin-import&lt;/code&gt;'s lead maintainer in this issue&lt;/a&gt; will convince you to.&lt;/p&gt;

&lt;p&gt;But usually, there's an easier way!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;nolyfill&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;SukkaW created an amazing project called &lt;strong&gt;nolyfill&lt;/strong&gt;. nolyfill is leveraging npm's, yarn's and pnpm's capabilities to replace heavy polyfills with so-called "nolyfills".&lt;/p&gt;

&lt;p&gt;Nolyfills are tiny wrappers around what Node.js already offers. You must check it out!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SukkaW/nolyfill"&gt;https://github.com/SukkaW/nolyfill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npx nolyfill&lt;/code&gt; on your repo, and see for yourself, how many redundant dependencies you have!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@yarnpkg/plugin-nolyfill&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;On top of SukkaW's work, I've built another thing: &lt;a href="https://github.com/wojtekmaj/yarn-plugin-nolyfill/"&gt;&lt;code&gt;@yarnpkg/plugin-nolyfill&lt;/code&gt;&lt;/a&gt;.It does the same thing &lt;code&gt;nolyfill&lt;/code&gt;'s CLI does, but hooks directly into Yarn resolution step, replacing the polyfills in question &lt;em&gt;on the fly&lt;/em&gt;. It has the added benefit of "install and forget" - plugin will work every time you install your repository, so it guarantees no new redundant polyfills will ever appear in your repository.&lt;/p&gt;

&lt;p&gt;If you use Yarn (2+), check it out as well!&lt;/p&gt;

&lt;p&gt;Install it by running &lt;code&gt;yarn plugin import https://raw.githubusercontent.com/wojtekmaj/yarn-plugin-nolyfill/v0.1.2/bundles/@yarnpkg/plugin-nolyfill.js&lt;/code&gt;. Then, reinstall repository by running &lt;code&gt;yarn install&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Package manager wars. The real picture</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Sat, 21 Oct 2023 22:37:03 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/package-manager-wars-the-real-picture-e9p</link>
      <guid>https://forem.com/wojtekmaj/package-manager-wars-the-real-picture-e9p</guid>
      <description>&lt;p&gt;"pnpm has surpassed Yarn!" I've read on Twitter the other day. &lt;em&gt;"In what exactly?"&lt;/em&gt; - I thought to myself. The answer to this question turned out to be: &lt;em&gt;"In npm downloads"&lt;/em&gt;. However, this doesn't mean anything at all!&lt;/p&gt;

&lt;p&gt;In this article, we'll explore why it's a horrible way of comparing different package managers popularity, and we'll find out the real answer to the question: "Which package managers are the most popular?".&lt;/p&gt;

&lt;h3&gt;
  
  
  Why npm downloads can't be counted?
&lt;/h3&gt;

&lt;p&gt;The most obvious problem with counting npm downloads is that &lt;strong&gt;npm ships with Node.js&lt;/strong&gt;. This means that, in theory, everyone can use npm in Node.js project with no additional downloads. You don't &lt;em&gt;download npm from npm&lt;/em&gt; to obtain it, only to update it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why Yarn downloads can't be counted?
&lt;/h3&gt;

&lt;p&gt;First, I need you to know that Yarn Classic (v1) and Yarn Modern (also known as Yarn Berry; v2+) are completely different things.&lt;/p&gt;

&lt;h4&gt;
  
  
  Let's look at Yarn Classic first.
&lt;/h4&gt;

&lt;p&gt;Yarn Classic was indeed shipped as an npm package called &lt;code&gt;yarn&lt;/code&gt;. The recommended way of installing it was by running &lt;code&gt;npm install -g yarn&lt;/code&gt;. However, &lt;strong&gt;it is not the only way of downloading Yarn Classic&lt;/strong&gt;. Among many others you could use &lt;code&gt;brew&lt;/code&gt;, &lt;a href="https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/y/yarn.rb" rel="noopener noreferrer"&gt;config of which&lt;/a&gt; unveils that, unsurprisingly, it downloads Yarn binary from yarnpkg.com rather than npm.&lt;/p&gt;

&lt;h4&gt;
  
  
  For Yarn Modern, things got complicated.
&lt;/h4&gt;

&lt;p&gt;Before Corepack (I'll cover it later) became a thing, Yarn 2 installation was &lt;em&gt;weeeird&lt;/em&gt;. To install Yarn 2, you had to install Yarn 1 first. Then, &lt;em&gt;in every repository&lt;/em&gt;, you had to run &lt;code&gt;yarn set version berry&lt;/code&gt;, which installed Yarn 2 &lt;em&gt;in this repository&lt;/em&gt;, specifically in &lt;code&gt;.yarn/releases&lt;/code&gt;. While doing so, you could see the console output:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Resolving berry to a url...
Downloading https://github.com/yarnpkg/berry/raw/master/packages/berry-cli/bin/berry.js...
Saving it into /private/tmp/my-app/.yarn/releases/yarn-berry.js...
Updating /private/tmp/my-app/.yarnrc...
Done!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So, again, &lt;em&gt;not npm&lt;/em&gt;. In fact, &lt;strong&gt;you cannot download Modern Yarn from npm at all!&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Corepack
&lt;/h4&gt;

&lt;p&gt;Nowadays, the recommended way of installing Yarn is through Corepack, a tool shipped (although not &lt;em&gt;enabled&lt;/em&gt; - yet) by default with Node.js.&lt;/p&gt;

&lt;p&gt;Slight off-topic: I highly recommend you to familiarize yourself with Corepack, regardless of your package manager of choice. Once enabled, it transparently downloads a binary for a package manager a given project requires, as specified in &lt;code&gt;packageManager&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;. You don't need to install Yarn or pnpm manually at all!&lt;/p&gt;

&lt;p&gt;Back to the topic. Where does Corepack downloads Yarn from? &lt;a href="https://github.com/nodejs/corepack/blob/0bd2577bb4c6c3a5a33ecdb3b6ca2ff244c54f28/config.json#L131-L152" rel="noopener noreferrer"&gt;Corepack's config&lt;/a&gt; makes it clear: it's yarnpkg.com, so again, &lt;strong&gt;not npm&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why pnpm downloads can't be counted?
&lt;/h3&gt;

&lt;p&gt;pnpm's 1st (and thus preferred) installation method &lt;a href="https://pnpm.io/installation" rel="noopener noreferrer"&gt;installation instructions&lt;/a&gt; is "Using standalone script". Looking at script source, we quickly learn it downloads its binaries from GitHub. So… &lt;strong&gt;not npm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unlike Yarn, pnpm &lt;em&gt;can&lt;/em&gt; actually be downloaded from npm. Corepack &lt;a href="https://github.com/nodejs/corepack/blob/0bd2577bb4c6c3a5a33ecdb3b6ca2ff244c54f28/config.json#L79-L95" rel="noopener noreferrer"&gt;takes advantage of that&lt;/a&gt;, and uses npm under the hood to download pnpm binaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  What do we know so far?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;npm is underreported on npm downloads stats. You don't need to download it to use it.&lt;/li&gt;
&lt;li&gt;Yarn Classic is underreported. You can download it from other sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yarn Modern is not reported at all&lt;/strong&gt;. You can't download it from npm.&lt;/li&gt;
&lt;li&gt;pnpm is underreported. You can download it from other sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;And perhaps the most importantly, more npm downloads != more popularity&lt;/strong&gt;. It just means… There is more downloads. If package manager A is updated weekly, and package manager B is updated once per year, A will get more downloads than B, even if B is technically more popular.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  So what can we measure?
&lt;/h3&gt;

&lt;p&gt;Here's my plan.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get as many most starred GitHub JavaScript and TypeScript repositories as I can.&lt;/li&gt;
&lt;li&gt;Figure out package manager each repo is using.

&lt;ul&gt;
&lt;li&gt;Check if &lt;code&gt;packageManager&lt;/code&gt; is present in &lt;code&gt;package.json&lt;/code&gt;. If present, count as whatever is specified.&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;package-lock.json&lt;/code&gt; or &lt;code&gt;npm-shrinkwrap.json&lt;/code&gt;. If present, count as npm.&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;yarn.lock&lt;/code&gt;, and…&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;.yarnrc.yml&lt;/code&gt;. If present, count as Yarn Modern.&lt;/li&gt;
&lt;li&gt;If not, count as Yarn Classic.&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;pnpm-lock.yaml&lt;/code&gt;. If present, count as pnpm.&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;bun.lockb&lt;/code&gt;. If present, count as Bun.&lt;/li&gt;
&lt;li&gt;If all else fails, check documentation for commands that would hint on package manager used.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  And so, the script was born.
&lt;/h3&gt;

&lt;p&gt;Without further ado, here are the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F399h3plfdh5kds2t5heo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F399h3plfdh5kds2t5heo.png" alt="Pie chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package manager&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;npm&lt;/td&gt;
&lt;td&gt;978 (53%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yarn Classic&lt;/td&gt;
&lt;td&gt;471 (26%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yarn Modern&lt;/td&gt;
&lt;td&gt;75 (4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pnpm&lt;/td&gt;
&lt;td&gt;105 (6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bun&lt;/td&gt;
&lt;td&gt;4 (0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unknown&lt;/td&gt;
&lt;td&gt;203 (11%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stat&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;Projects examined&lt;/td&gt;
&lt;td&gt;2040&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projects with &lt;code&gt;package.json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1836&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projects using Corepack&lt;/td&gt;
&lt;td&gt;179&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projects not using Corepack, but with a lockfile&lt;/td&gt;
&lt;td&gt;1657&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So there you have it. The real picture of package manager wars. &lt;/p&gt;

&lt;p&gt;pnpm does, indeed, appear to have surpassed Yarn Modern (v2 and v3). But it is nowhere near to Yarn Classic's (v1) popularity, which, in turn, is not nearly as popular as npm.&lt;/p&gt;

&lt;p&gt;npm is the absolute king with whopping 53% of the "market". In reality, it's likely even more than that. 11% of the projects examined did not have lockfile committed. My suspicion is that the vast majority of maintainers of these projects are in fact using npm, as there is no (machine-readable) indication that something other than the "default" is being used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final words
&lt;/h3&gt;

&lt;p&gt;If you'd like to see how the script was done, or would like to improve it, please visit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wojtekmaj/package-manager-stats" rel="noopener noreferrer"&gt;https://github.com/wojtekmaj/package-manager-stats&lt;/a&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>yarn</category>
      <category>pnpm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Migrating your React app from Webpack to Vite</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Thu, 07 Apr 2022 22:47:13 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/migrating-your-react-app-from-webpack-to-vite-inp</link>
      <guid>https://forem.com/wojtekmaj/migrating-your-react-app-from-webpack-to-vite-inp</guid>
      <description>&lt;h2&gt;
  
  
  What is Vite?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; is a "next generation front-end tooling", as its maintainers claim. Instant dev server, fast Hot Module Reload, easy configuration, optimized production builds - it's all there. &lt;/p&gt;

&lt;p&gt;But… Vite's documentation doesn't say how to migrate your existing Webpack app 🤷 Worry not! In this guide, we'll get through this together!&lt;/p&gt;

&lt;h2&gt;
  
  
  Change your repo to ES modules
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;package.json&lt;/code&gt;, add the following entry:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Embrace modernity! Reject tradition! That's why we're switching to Vite anyway!&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Vite and its plugins
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vite @vitejs/plugin-react vite-plugin-simple-html


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yarn add vite @vitejs/plugin-react vite-plugin-simple-html &lt;span class="nt"&gt;--dev&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Replace scripts
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;package.json&lt;/code&gt;, you'll probably have scripts similar to these:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=production webpack"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=development webpack serve"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;build&lt;/code&gt; command, invoked by &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;yarn build&lt;/code&gt;, builds your app for production. &lt;code&gt;dev&lt;/code&gt; command starts a development server.&lt;/p&gt;

&lt;p&gt;These scripts needs to be replaced with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite build"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite serve"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On top of that, you can add one extra command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite preview"&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;preview&lt;/code&gt; command will start a server running your app built for production.&lt;/p&gt;

&lt;p&gt;Let's run the development server!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  vite v2.9.1 dev server running at:

  &amp;gt; Local: http://localhost:3000/
  &amp;gt; Network: use --host to expose

  ready in 261ms.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;👁👄👁 Wow, that is fast. &lt;/p&gt;

&lt;h2&gt;
  
  
  Teach Vite where the root is
&lt;/h2&gt;

&lt;p&gt;If you started the development server now, Vite will look for &lt;code&gt;index.html&lt;/code&gt; in your project's root directory. If it's anywhere else, Vite will not be able to find it and will display an empty page instead.&lt;/p&gt;

&lt;p&gt;To fix this, you need to either move &lt;code&gt;index.html&lt;/code&gt; to your root directory, or specify a different root directory for Vite to look for &lt;code&gt;index.html&lt;/code&gt; in. In my case, it's located at &lt;code&gt;src/index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can do this by adding root directory path to your commands, like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite build src"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite serve src"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, you can also do this by creating a &lt;code&gt;vite.config.js&lt;/code&gt; file in your project root. You will need it in a short while anyway, so why not create one now to keep all the configuration in one place?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Relative to the root&lt;/span&gt;
    &lt;span class="na"&gt;outDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configure &lt;code&gt;vite-plugin-simple-html&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now that Vite knows where to find your &lt;code&gt;index.html&lt;/code&gt; file, it will try and parse it.&lt;/p&gt;

&lt;p&gt;You may encounter an error like me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx8m125n9gtkyx4q631ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx8m125n9gtkyx4q631ex.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to deal with it? I was using &lt;code&gt;HtmlWebpackPlugin&lt;/code&gt;'s &lt;code&gt;templateParameters&lt;/code&gt; option to dynamically inject custom title and other info into &lt;code&gt;index.html&lt;/code&gt; file, like so:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HtmlWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateParameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`My site [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}),&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Thankfully, we can do the same with &lt;code&gt;vite-plugin-simple-html&lt;/code&gt;. In your &lt;code&gt;vite.config.js&lt;/code&gt;, add the following bits:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;simpleHtmlPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-simple-html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// …&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;simpleHtmlPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`My site [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Add entry module to your &lt;code&gt;index.html&lt;/code&gt; file
&lt;/h2&gt;

&lt;p&gt;At this point, your &lt;code&gt;index.html&lt;/code&gt; file should be served just fine. But the app still won't load!&lt;/p&gt;

&lt;p&gt;If you used Webpack, you probably have also used &lt;code&gt;html-webpack-plugin&lt;/code&gt; to handle injecting &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag(s) with your entry module(s) to &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vite will not inject these tags automatically. You will need to add them by yourself. For example:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./index.jsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Aaah, that's better. Something came to life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fugbjxree5xrnxymx6gza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fugbjxree5xrnxymx6gza.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure &lt;code&gt;@vitejs/plugin-react&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Okay, as you can see, we're not &lt;em&gt;quite&lt;/em&gt; there yet. We need to configure &lt;code&gt;@vitejs/plugin-react&lt;/code&gt; to make it work with React.  &lt;/p&gt;

&lt;p&gt;If you still used classic JSX runtime, your app may already load at this point, but you'll want to follow these steps anyway. This plugin will not only handle automatic JSX runtime (the one thanks to which you don't need to manually import React in every file), but also add features like Fast Refresh, enable Babel integration, and much, much more.&lt;/p&gt;

&lt;p&gt;Add it to your &lt;code&gt;vite.config.js&lt;/code&gt; file like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// …&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// …&lt;/span&gt;
    &lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// Use React plugin in all *.jsx and *.tsx files&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/*.{jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;p&gt;At this point, if you were using aliases (to write e.g. &lt;code&gt;import Button from 'src/components/Button'&lt;/code&gt; instead of &lt;code&gt;import Button from '../../../../../components/Button'&lt;/code&gt;), your build may fail. Easy fix!&lt;/p&gt;

&lt;p&gt;Webpack:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Vite:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Wait a second, same thing? 🤔 Yes! Well, kinda. You have &lt;a href="https://vitejs.dev/config/shared-options.html#resolve-alias" rel="noopener noreferrer"&gt;more options to choose from&lt;/a&gt;, but most of the time, your aliases should work when copied over.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static files handling
&lt;/h2&gt;

&lt;p&gt;By default, files from &lt;code&gt;public&lt;/code&gt; directory placed &lt;em&gt;in your root directory&lt;/em&gt; are going to be copied over at build time. If  you have these files elsewhere, you can use &lt;code&gt;publicDir&lt;/code&gt; option like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// …&lt;/span&gt;
  &lt;span class="na"&gt;publicDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  SVG handling
&lt;/h2&gt;

&lt;p&gt;If you used to import SVG icons to use not as static files but rather as React components, &lt;a class="mentioned-user" href="https://dev.to/cassidoo"&gt;@cassidoo&lt;/a&gt; just wrote &lt;a href="https://dev.to/cassidoo/importing-svg-files-as-react-components-with-vite-l3n"&gt;an interesting article on that matter&lt;/a&gt; - be sure to check it out!&lt;/p&gt;
&lt;h2&gt;
  
  
  Babel plugins
&lt;/h2&gt;

&lt;p&gt;You might not need Babel at all, as &lt;code&gt;@babel/preset-env&lt;/code&gt; and &lt;code&gt;@babel/preset-react&lt;/code&gt; are of no use.&lt;/p&gt;

&lt;p&gt;But sometimes Babel plugins may still come in handy. For example, there's a &lt;a href="https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types" rel="noopener noreferrer"&gt;plugin to remove PropTypes&lt;/a&gt; you can use to make bundle size a bit smaller, and there's a &lt;a href="https://www.npmjs.com/package/babel-plugin-styled-components" rel="noopener noreferrer"&gt;dedicated plugin for styled-components&lt;/a&gt; that makes development and testing easier by, among others, adding component display names.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@vitejs/plugin-react&lt;/code&gt; will come to the rescue here, with &lt;code&gt;babel&lt;/code&gt; option. For example, to add &lt;code&gt;babel-plugin-styled-components&lt;/code&gt; plugin:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

    &lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// …&lt;/span&gt;
      &lt;span class="na"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;babel-plugin-styled-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;process.env.*&lt;/code&gt; problem
&lt;/h2&gt;

&lt;p&gt;I was using &lt;code&gt;process.env.NODE_ENV&lt;/code&gt; in a bunch of places in my app. This resulted in the following error being thrown in the console:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Uncaught ReferenceError: process is not defined


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In Vite, you can use &lt;code&gt;import.meta.env.*&lt;/code&gt; instead. For example, &lt;code&gt;process.env.NODE_ENV&lt;/code&gt; can be replaced with &lt;code&gt;import.meta.env.NODE_ENV&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enjoy!
&lt;/h2&gt;

&lt;p&gt;Now you should see your app, powered by Vite!&lt;/p&gt;

&lt;p&gt;We're not done yet; we'll still need to tweak a few things before running it in production. For this, you'll have to wait for the second part of this guide. Subscribe to get notified!&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning up
&lt;/h2&gt;

&lt;p&gt;You can safely remove these dependencies, which are now unused:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;core-js&lt;/code&gt; (unless you've been using it directly)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;webpack&lt;/code&gt; (duh)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;webpack-cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;webpack-dev-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*-loader&lt;/code&gt; (e.g. &lt;code&gt;babel-loader&lt;/code&gt;, &lt;code&gt;style-loader&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*-webpack-plugin&lt;/code&gt; (e.g. &lt;code&gt;html-webpack-plugin&lt;/code&gt;, &lt;code&gt;mini-css-extract-plugin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@babel/preset-react&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@pmmmwh/react-refresh-webpack-plugin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-refresh&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt; Webpack config file can also be deleted.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;babel.config.js&lt;/code&gt;, &lt;code&gt;babel.config.json&lt;/code&gt;, or &lt;code&gt;.babelrc&lt;/code&gt; can be deleted, provided that you didn't use it as your Babel config in &lt;code&gt;@vitejs/plugin-react&lt;/code&gt; configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anything missing?
&lt;/h2&gt;

&lt;p&gt;Do you think there's anything else that needs to be addressed, that may be a common problem when migrating from Webpack to Vite? Please, please let me know in the comments!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>vite</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Enzyme is dead. Now what?</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Mon, 20 Dec 2021 10:59:30 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/enzyme-is-dead-now-what-ekl</link>
      <guid>https://forem.com/wojtekmaj/enzyme-is-dead-now-what-ekl</guid>
      <description>&lt;p&gt;I'm the maintainer of &lt;code&gt;@wojtekmaj/enzyme-adapter-react-17&lt;/code&gt;. &lt;strong&gt;I'm here to warn you. Enzyme&lt;/strong&gt;, a popular utility to test React components, &lt;strong&gt;is dead&lt;/strong&gt;. It's time to move on. Here's why I think so.&lt;/p&gt;

&lt;p&gt;For a long time, Enzyme has been the 1st choice when it comes to testing React applications, despite of how bumpy the road to Enzyme React 16 support was. Even today, &lt;a href="https://npm-stat.com/charts.html?package=%40testing-library%2Freact&amp;amp;package=enzyme"&gt;&lt;strong&gt;1/3 of React apps are still being tested using Enzyme!&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How &lt;code&gt;@wojtekmaj/enzyme-adapter-react-17&lt;/code&gt; came to life
&lt;/h2&gt;

&lt;p&gt;Back in August 2020, React 17 Release Candidate &lt;a href="https://reactjs.org/blog/2020/08/10/react-v17-rc.html"&gt;came out&lt;/a&gt;. Shortly after, an &lt;a href="https://github.com/enzymejs/enzyme/issues/2429"&gt;issue has been raised&lt;/a&gt; in Enzyme repository to add support for React 17. Immediately after, &lt;a class="mentioned-user" href="https://dev.to/layershifter"&gt;@layershifter&lt;/a&gt; has &lt;a href="https://github.com/enzymejs/enzyme/pull/2430"&gt;opened a PR&lt;/a&gt; adding an official &lt;code&gt;enzyme-adapter-react-17&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, there were (and, spoiler alert, still are) some issues with testing that prevented this PR from being merged.&lt;/p&gt;

&lt;p&gt;Now, here's the thing. I'm the maintainer of many popular React packages, &lt;a href="https://www.npmjs.com/package/react-pdf"&gt;React-PDF&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/react-calendar"&gt;React-Calendar&lt;/a&gt;, and &lt;a href="https://www.npmjs.com/package/react-date-picker"&gt;React-Date-Picker&lt;/a&gt; just to name a few. Professionally, I maintain several large projects, which collectively have more than 30,000 Enzyme-based unit tests.&lt;/p&gt;

&lt;p&gt;I was in no position to wait for Enzyme to add support for React 17 to support React 17 in my packages. Rewriting all unit tests also looked like no fun to me. So, I've decided to act and publish a temporary adapter based on Oleksandr's work.&lt;/p&gt;

&lt;p&gt;It wasn't only the adapter though: certain changes were also necessary in Enzyme adapter utils, which all Enzyme adapters depend on, so a fork of them was also needed. A couple of tireless evenings later, &lt;code&gt;@wojtekmaj/enzyme-adapter-react-17&lt;/code&gt; was born.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast-forward one year
&lt;/h2&gt;

&lt;p&gt;The issue for adding React 17 support remains open and has become nothing but a source of bitter comments mixed with unproductive "any updates?". Oleksandr's PR remains unmerged. &lt;code&gt;enzyme-adapter-react-17&lt;/code&gt; is nowhere in sight. &lt;strong&gt;The unofficial adapter I published&lt;/strong&gt; with an intention of being just a stepping stone before everyone eventually migrates to &lt;code&gt;enzyme-adapter-react-17&lt;/code&gt;, &lt;strong&gt;has become &lt;em&gt;de facto&lt;/em&gt; the default adapter for React 17&lt;/strong&gt;, with 16 million downloads so far.&lt;/p&gt;

&lt;p&gt;Retrospectively, &lt;strong&gt;I'm not sure if publishing the package was a good decision.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On one hand, this move has helped thousands of developers worldwide to upgrade to React 17, relatively hassle-free. &lt;/p&gt;

&lt;p&gt;On the other, I helped prolonging Enzyme's inevitable death and thus gave many developers hope and a sense of safety they shouldn't get to feel. &lt;strong&gt;And I'm sorry for that.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  React 18
&lt;/h2&gt;

&lt;p&gt;Before I came to this conclusion though, React 18 beta was announced, and of course, I jumped to see &lt;strong&gt;if &lt;code&gt;@wojtekmaj/enzyme-adapter-react-18&lt;/code&gt; could be released.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The big thing in React 18 are concurrent features. To opt-in, after upgrading to React 18, you also need to switch to the new &lt;code&gt;createRoot&lt;/code&gt; API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Until you switch to the new API, your app will behave as if it's running React 17. So if you don't plan to do this, there's no point of upgrading!&lt;/p&gt;

&lt;p&gt;I quickly realized that the API changes in React 18 meant that &lt;strong&gt;releasing a React 18 Enzyme adapter will not be possible&lt;/strong&gt; without a huge rework of not only the adapter itself, but also Enzyme, &lt;code&gt;enzyme-adapter-utils&lt;/code&gt; and &lt;code&gt;enzyme-adapter-react-helper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Trust me, it's not gonna happen. It's over. No more "stepping stones". And certainly no more official adapters. &lt;strong&gt;Whether or not you plan to upgrade to React 18 in the near future, you should consider looking for Enzyme alternative right now.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What should I do? 😱
&lt;/h2&gt;

&lt;p&gt;The answer is, as always, it depends. You don't &lt;em&gt;have&lt;/em&gt; to upgrade React, after all.&lt;/p&gt;

&lt;p&gt;Here's what I would do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start &lt;a href="https://testing-library.com/docs/react-testing-library/intro/"&gt;familiarizing yourself with React Testing Library&lt;/a&gt;, an officially recommended library for React components.&lt;/li&gt;
&lt;li&gt;Make a rule to write new tests using RTL only.&lt;/li&gt;
&lt;li&gt;Consider making a rule to rewrite tests to RTL whenever you need to touch them and/or the component they are testing.&lt;/li&gt;
&lt;li&gt;In your designated time for repaying technical debt (you have designated time for repaying technical debt, right? …right?), rewrite your remaining Enzyme-based tests to RTL.&lt;/li&gt;
&lt;li&gt;Clean up your repo from Enzyme-specific bits&lt;/li&gt;
&lt;li&gt;When you're ready, upgrade to React 18.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A bit of personal advice
&lt;/h3&gt;

&lt;p&gt;While &lt;a href="https://testing-library.com/docs/react-testing-library/migrate-from-enzyme"&gt;Migrate from Enzyme support article&lt;/a&gt; is available, I suggest you to just start fresh, forgetting that Enzyme has ever existed. &lt;strong&gt;RTL is by no means an Enzyme drop-in replacement&lt;/strong&gt;, so having a completely fresh mindset will help you getting the most of it.&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
    </item>
    <item>
      <title>Optimizing React apps: Hardcore edition</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Fri, 20 Aug 2021 15:30:52 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/optimizing-react-app-hardcore-edition-2h1</link>
      <guid>https://forem.com/wojtekmaj/optimizing-react-app-hardcore-edition-2h1</guid>
      <description>&lt;p&gt;You've heard of minifying. You've heard of lazy-loading. You've heard of tree shaking. You've done it all. Or did you? Here are some optimizations you may have never heard of before. Until now!&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable "loose" transformations in &lt;code&gt;@babel/preset-env&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Enabling &lt;a href="http://2ality.com/2015/12/babel6-loose-mode.html"&gt;"loose" transformations&lt;/a&gt; may make your application considerably smaller. I &lt;strong&gt;shaved off roughly 230.9 KB, or 16.2%&lt;/strong&gt; from my bundle!&lt;/p&gt;

&lt;p&gt;This, however, comes at a price: your application may break, both when enabling, and disabling these transformations.&lt;/p&gt;

&lt;p&gt;In my case, the only fix I needed to do was related to iterating over &lt;code&gt;HTMLCollection&lt;/code&gt; (&lt;code&gt;document.querySelectorAll(…)&lt;/code&gt;, &lt;code&gt;document.getElementsByTagName(…)&lt;/code&gt; and &lt;code&gt;HTMLFormControlsCollection&lt;/code&gt; (&lt;code&gt;form.elements&lt;/code&gt;). I was no longer able to do e.g. &lt;code&gt;[...form.elements]&lt;/code&gt;, I had to swap it out for &lt;code&gt;Array.from(form.elements)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Still tempted by the large savings? Give it a go by enabling &lt;code&gt;loose&lt;/code&gt; flag in Babel config:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;babel.config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "presets": [
&lt;span class="gd"&gt;-   "@babel/preset-env"
&lt;/span&gt;&lt;span class="gi"&gt;+   ["@babel/preset-env", {
+     "loose": true
+   }]
&lt;/span&gt;  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Remove prop-types from your production bundle
&lt;/h2&gt;

&lt;p&gt;PropTypes are incredibly helpful during development, but they are of no use for your users. You can use &lt;code&gt;babel-plugin-transform-react-remove-prop-types&lt;/code&gt; to remove PropTypes from your bundle.&lt;/p&gt;

&lt;p&gt;To install, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev babel-plugin-transform-react-remove-prop-types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D babel-plugin-transform-react-remove-prop-types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add it to your Babel config like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;babel.config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "env": {
    "production": {
      "plugins": [
&lt;span class="gi"&gt;+        "transform-react-remove-prop-types"
&lt;/span&gt;      ]
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Savings will vary depending on the size of your app. In my case, &lt;strong&gt;I shaved off 16.5 KB or about 1.2%&lt;/strong&gt; from my bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consider &lt;code&gt;unsafe-wrap&lt;/code&gt; mode
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;unsafe-wrap&lt;/code&gt; mode is, as the name states, a bit &lt;em&gt;unsafe&lt;/em&gt; for the reasons &lt;a href="https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types#options"&gt;well explained in plugin's docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, in my case, PropTypes were not accessed from anywhere and the application worked flawlessly.&lt;/p&gt;

&lt;p&gt;To enable this mode, you need to change your Babel config like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;babel.config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "env": {
    "production": {
      "plugins": [
&lt;span class="gd"&gt;-       "transform-react-remove-prop-types"
&lt;/span&gt;&lt;span class="gi"&gt;+       ["transform-react-remove-prop-types", {
+         "mode": "unsafe-wrap"
+       }]
&lt;/span&gt;      ]
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, &lt;strong&gt;I shaved off a total of 35.9 KB or about 2.5%&lt;/strong&gt; from my bundle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable new JSX transform
&lt;/h2&gt;

&lt;p&gt;Enabling new JSX transform will change the way Babel React preset transpiles JSX to pure JavaScript. &lt;/p&gt;

&lt;p&gt;I explained the benefits of enabling it in my other article: &lt;a href="https://dev.to/wojtekmaj/how-to-enable-automatic-runtime-in-react-17-with-babel-preset-react-52l"&gt;How to enable new JSX transform in React 17?&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I highly recommend you to have a read. If that's TL;DR though, all you need to do for quick results is make sure that &lt;code&gt;@babel/core&lt;/code&gt; and &lt;code&gt;@babel/preset-env&lt;/code&gt; in your project are both on version &lt;code&gt;7.9.0&lt;/code&gt; or newer, and change your Babel config like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;babel.config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "presets": [
&lt;span class="gd"&gt;-   "@babel/preset-react"
&lt;/span&gt;&lt;span class="gi"&gt;+   ["@babel/preset-react", {
+     "runtime": "automatic"
+   }]
&lt;/span&gt;  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And poof! Roughly &lt;strong&gt;10.5 KB, or 0.7%&lt;/strong&gt; of my bundle was gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minify your HTML
&lt;/h2&gt;

&lt;p&gt;Chances are your bundler is smart enough to minify JavaScript by default when ran in production mode. But did you know you can minify HTML, too? And JavaScript &lt;em&gt;in that HTML&lt;/em&gt; as well?&lt;/p&gt;

&lt;p&gt;You're in? Great! Here's what you need to do:&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;html-minifier-terser&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;npm install --save-dev html-minifier-terser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D html-minifier-terser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and change your Webpack config to use it. Define minifier options:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minifyOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Defaults used by HtmlWebpackPlugin&lt;/span&gt;
  &lt;span class="na"&gt;collapseWhitespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeComments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeRedundantAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeScriptTypeAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeStyleLinkTypeAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;useShortDoctype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Custom&lt;/span&gt;
  &lt;span class="na"&gt;minifyCSS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;minifyJS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use them in &lt;code&gt;HtmlWebpackPlugin&lt;/code&gt;…:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    new HtmlWebpackPlugin({
&lt;span class="gi"&gt;+     minify: minifyOptions,
&lt;/span&gt;      template: 'index.html',
    }),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…as well as in &lt;code&gt;CopyWebpackPlugin&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;minify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html-minifier-terser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'index.html',
          to: '',
&lt;span class="gi"&gt;+         transform(content) {
+           return minify(content.toString(), minifyOptions);
+         },
&lt;/span&gt;        },
      ]
    }),
  ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use &lt;code&gt;babel-plugin-styled-components&lt;/code&gt; (&lt;code&gt;styled-components&lt;/code&gt; users only)
&lt;/h2&gt;

&lt;p&gt;If you use &lt;code&gt;styled-components&lt;/code&gt;, make sure to use &lt;a href="https://styled-components.com/docs/tooling#babel-plugin"&gt;their Babel plugin&lt;/a&gt;, too. Not only it adds minification of styles, but also adds support for server-side rendering, and provides with a nicer debugging experience.&lt;/p&gt;

&lt;p&gt;To install, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev babel-plugin-styled-components
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D babel-plugin-styled-components
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add it to your Babel config like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;babel.config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "env": {
    "production": {
      "plugins": [
&lt;span class="gi"&gt;+        "styled-components"
&lt;/span&gt;      ]
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will shave off a few kilobytes on its own, but due to added &lt;code&gt;displayName&lt;/code&gt;s the savings will not be so apparent just yet. So now…&lt;/p&gt;

&lt;h3&gt;
  
  
  Disable &lt;code&gt;displayName&lt;/code&gt; in production builds
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;babel.config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "env": {
    "production": {
      "plugins": [
&lt;span class="gi"&gt;+       ["styled-components", {
+         "displayName": false,
+       }]
&lt;/span&gt;      ]
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing so in my app gave me a &lt;strong&gt;surprisingly large savings of 50.4 KB or 3.5%&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap &lt;code&gt;createGlobalStyle&lt;/code&gt; contents in &lt;code&gt;css&lt;/code&gt; (&lt;code&gt;styled-components&lt;/code&gt; users only)
&lt;/h2&gt;

&lt;p&gt;Apparently, while &lt;code&gt;babel-plugin-styled-components&lt;/code&gt; is capable of minifying styles, it doesn't minify anything within &lt;code&gt;createGlobalStyle&lt;/code&gt;. So, chances are you're shipping your app with tons of unnecessary whitespace.&lt;/p&gt;

&lt;p&gt;Remove them by simply wrapping &lt;code&gt;createGlobalStyle&lt;/code&gt; contents in &lt;code&gt;css&lt;/code&gt; as well, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-const GlobalStyle = createGlobalStyle`
&lt;/span&gt;&lt;span class="gi"&gt;+const GlobalStyle = createGlobalStyle`${css`
&lt;/span&gt;   // Your global style goes here
&lt;span class="gd"&gt;-`;
&lt;/span&gt;&lt;span class="gi"&gt;+`}`;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Replace &lt;code&gt;react-lifecycles-compat&lt;/code&gt; with an empty mock
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;react-lifecycles-compat&lt;/code&gt; is a dependency that polyfills lifecycle methods introduced in React 16.3 so that the components polyfilled would work with older React versions. Some dependencies may still use this polyfill in order not to break older React version support.&lt;/p&gt;

&lt;p&gt;If you use React 16.3 or newer, you don't need &lt;code&gt;react-lifecycles-compat&lt;/code&gt;. You can replace it with a mocked version like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;__mocks__/reactLifecyclesCompatMock.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;polyfill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  resolve: {
    alias: {
&lt;span class="gi"&gt;+     'react-lifecycles-compat': path.resolve(__dirname, '__mocks__', 'reactLifecyclesCompatMock.js'),
&lt;/span&gt;    },
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing so &lt;strong&gt;will save you 2.5 KB&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace &lt;code&gt;classnames&lt;/code&gt; with &lt;code&gt;clsx&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;classnames&lt;/code&gt; is not a large dependency, only 729 bytes, but &lt;code&gt;clsx&lt;/code&gt; is fully compatible with &lt;code&gt;classnames&lt;/code&gt; at just 516 bytes. So, replacing &lt;code&gt;classnames&lt;/code&gt; with &lt;code&gt;clsx&lt;/code&gt; in your app &lt;strong&gt;will save you 213 bytes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Chances are you'll have &lt;em&gt;both&lt;/em&gt; &lt;code&gt;classnames&lt;/code&gt; and &lt;code&gt;clsx&lt;/code&gt; in your app, e.g. because dependencies may require one or the other. In this case, you can use Webpack's &lt;code&gt;alias&lt;/code&gt; to get rid of &lt;code&gt;classnames&lt;/code&gt; from your bundle:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;webpack.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  resolve: {
    alias: {
&lt;span class="gi"&gt;+     classnames: 'clsx',
&lt;/span&gt;    },
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing so &lt;strong&gt;will save you 729 bytes&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing something?
&lt;/h2&gt;

&lt;p&gt;Please share your ideas for not-so-obvious optimizations in the comments below!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webpack</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to enable new JSX transform in React?</title>
      <dc:creator>Wojciech Maj</dc:creator>
      <pubDate>Tue, 11 Aug 2020 15:07:32 +0000</pubDate>
      <link>https://forem.com/wojtekmaj/how-to-enable-automatic-runtime-in-react-17-with-babel-preset-react-52l</link>
      <guid>https://forem.com/wojtekmaj/how-to-enable-automatic-runtime-in-react-17-with-babel-preset-react-52l</guid>
      <description>&lt;p&gt;The biggest feature of React 17, as React team claims, is that there are no new features. This isn't however entirely true.&lt;/p&gt;

&lt;p&gt;In Babel 7.9.0, a &lt;a href="https://babeljs.io/blog/2020/03/16/7.9.0#a-new-jsx-transform-11154-https-githubcom-babel-babel-pull-11154"&gt;new JSX transform&lt;/a&gt; was announced. It could only be used in experimental React releases. Until now!&lt;/p&gt;

&lt;p&gt;Before we dive into how to enable this feature, let's see the advantages:&lt;/p&gt;

&lt;h3&gt;
  
  
  No more &lt;code&gt;import React from 'react'&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Yes! You'll no longer need to import React to each. and. every. component. you write. Instead, it will be imported automatically!&lt;/p&gt;

&lt;p&gt;Well, not &lt;em&gt;quite&lt;/em&gt;. If you use hooks, &lt;code&gt;lazy&lt;/code&gt;, &lt;code&gt;Suspense&lt;/code&gt; or any other import, you will still need to import them all manually. But no more importing &lt;code&gt;React&lt;/code&gt; if you're not using &lt;code&gt;React&lt;/code&gt; explicitly in your code, e.g. by calling &lt;code&gt;React.useState&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Smaller bundle
&lt;/h3&gt;

&lt;p&gt;A side effect of this change is also a slightly smaller bundle. In my case, on a moderately sized commercial application with ~1500 components, the savings were around 10.5 KiB. It ain't much, but arguably a welcome improvement.&lt;/p&gt;

&lt;p&gt;Where do the savings come from? Take a look at transpiled code, before &amp;amp; after the change we're about to make:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jsx&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;_jsx&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react/jsx-runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_jsx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out, this can add up!&lt;/p&gt;

&lt;h2&gt;
  
  
  Enough talking, let's do it!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Make sure you're all up to date
&lt;/h3&gt;

&lt;p&gt;To continue, you're going to need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Babel &amp;amp; &lt;code&gt;@babel/preset-react&lt;/code&gt; &lt;code&gt;7.9.0&lt;/code&gt; or later&lt;/li&gt;
&lt;li&gt;React:

&lt;ul&gt;
&lt;li&gt;17: &lt;code&gt;17.0.0&lt;/code&gt; or later, &lt;/li&gt;
&lt;li&gt;16: &lt;code&gt;16.14.0&lt;/code&gt; or later,&lt;/li&gt;
&lt;li&gt;15: &lt;code&gt;15.7.0&lt;/code&gt; or later,&lt;/li&gt;
&lt;li&gt;0.14: &lt;code&gt;0.14.10&lt;/code&gt; or later&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, you can use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @babel/core@^7.9.0 @babel/preset-react@^7.9.0 &lt;span class="nt"&gt;--dev&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;react@^16.14.0 react-dom@^16.14.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @babel/core@^7.9.0 @babel/preset-react@^7.9.0 &lt;span class="nt"&gt;--dev&lt;/span&gt;
yarn add react@^16.14.0 react-dom@^16.14.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to update your React 16 app. &lt;/p&gt;

&lt;p&gt;You can also jump straight to React 17. &lt;em&gt;Note that React 17 contains some breaking changes when compared to React 16. Upgrade carefully!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Babel configuration
&lt;/h3&gt;

&lt;p&gt;Your Babel configuration (&lt;code&gt;.babelrc&lt;/code&gt;, &lt;code&gt;.babelrc.json&lt;/code&gt;, or similar) needs a small change: In &lt;code&gt;presets&lt;/code&gt; section, to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"@babel/preset-react"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;preset you'll now need to pass &lt;code&gt;"runtime": "automatic"&lt;/code&gt; option. Change the above line to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@babel/preset-react"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"runtime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"automatic"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You're done! 🥳&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaning up
&lt;/h3&gt;

&lt;p&gt;Alright, not quite. You're now left with redundant React imports. Cleaning them up is optional, because modern bundlers will ignore unused imports. If you still want to do the cleaning, continue reading.&lt;/p&gt;

&lt;p&gt;If you used e.g. &lt;code&gt;React.useState&lt;/code&gt; or &lt;code&gt;&amp;lt;React.Fragment&amp;gt;&lt;/code&gt; (as opposed to &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;), the easiest approach would be to get rid of all &lt;code&gt;React.*&lt;/code&gt; occurrences first.&lt;/p&gt;

&lt;p&gt;Then, you'll be free to remove "pure" React imports by replacing (using RegEx):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from ['"]react['"];?\n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with an empty string, and replacing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React,\s?(\{.*\})\s?from (['"]react['"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import $1 from $2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which should leave only named imports in a vast majority of cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  ESLint configuration
&lt;/h3&gt;

&lt;p&gt;Changes are ESLint will complain about you no longer importing &lt;code&gt;React&lt;/code&gt; in files where you're using JSX. If that's the case, all you need to do is simply turn off these rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "react/jsx-uses-react": "off",
  "react/react-in-jsx-scope": "off",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Happy coding!
&lt;/h2&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>babel</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
