<?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: Oleksandr Fediashov</title>
    <description>The latest articles on Forem by Oleksandr Fediashov (@layershifter).</description>
    <link>https://forem.com/layershifter</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%2F242295%2Fcb2a42ae-3d4f-4922-91c7-9abf2c08ce7e.jpeg</url>
      <title>Forem: Oleksandr Fediashov</title>
      <link>https://forem.com/layershifter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/layershifter"/>
    <language>en</language>
    <item>
      <title>How to kill tree shaking in Webpack with static properties?</title>
      <dc:creator>Oleksandr Fediashov</dc:creator>
      <pubDate>Thu, 14 May 2020 12:10:48 +0000</pubDate>
      <link>https://forem.com/layershifter/how-to-kill-tree-shaking-in-webpack-with-static-properties-p72</link>
      <guid>https://forem.com/layershifter/how-to-kill-tree-shaking-in-webpack-with-static-properties-p72</guid>
      <description>&lt;p&gt;Modern JavaScript bundlers like &lt;a href="https://rollupjs.org/" rel="noopener noreferrer"&gt;rollup.js&lt;/a&gt; and &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;Webpack&lt;/a&gt; support the great feature that allows to decrease output bundle size and it's called &lt;a href="https://webpack.js.org/guides/tree-shaking/" rel="noopener noreferrer"&gt;tree shaking&lt;/a&gt; 🌲&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. It relies on the static structure of ES2015 module syntax, i.e. import and export. The name and concept have been popularized by the ES2015 module bundler rollup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usually it works like a charm, but sometimes something can go wrong... 🤭&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface the problem 📖
&lt;/h3&gt;

&lt;p&gt;The common pattern for React components is to have some static properties like &lt;code&gt;defaultProps&lt;/code&gt;, &lt;code&gt;propTypes&lt;/code&gt;, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;primary&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our case (I am working on a UI library called &lt;a href="https://github.com/microsoft/fluentui" rel="noopener noreferrer"&gt;Fluent UI React&lt;/a&gt;) we also have another static properties like &lt;code&gt;className&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt; and few others. So what can go wrong? 🤔&lt;/p&gt;

&lt;p&gt;Let's assume that we have such component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt; &lt;span class="c1"&gt;// This line breaks everything 💣&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonClassname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui-button&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we just want to import &lt;code&gt;buttonClassName&lt;/code&gt; variable from it:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buttonClassname&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;./Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buttonClassname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's compare the output produced with Webpack 4 with and without that line:&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%2Fi%2Flnt4yxxvqc38k56g1jn6.jpg" 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%2Fi%2Flnt4yxxvqc38k56g1jn6.jpg" alt="Comparison of Webpack bundles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spoiler alert:&lt;/strong&gt; Rollup handles this properly which can be checked in an &lt;a href="https://rollupjs.org/repl/?version=2.10.0&amp;amp;shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGJ1dHRvbkNsYXNzbmFtZSUyMCU3RCUyMGZyb20lMjAnLiUyRkJ1dHRvbiclM0IlNUNuJTVDbmNvbnNvbGUubG9nKGJ1dHRvbkNsYXNzbmFtZSklMjIlMkMlMjJpc0VudHJ5JTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMm5hbWUlMjIlM0ElMjJCdXR0b24uanMlMjIlMkMlMjJjb2RlJTIyJTNBJTIyZnVuY3Rpb24lMjBCdXR0b24oKSUyMCU3QiU1Q24lMjAlMjByZXR1cm4lMjBudWxsJTNCJTVDbiU3RCU1Q24lNUNuQnV0dG9uLmRlZmF1bHRQcm9wcyUyMCUzRCUyMCU3QiU3RCUzQiU1Q24lNUNuZXhwb3J0JTIwY29uc3QlMjBidXR0b25DbGFzc25hbWUlMjAlM0QlMjAlNUMlMjJ1aS1idXR0b24lNUMlMjIlM0IlNUNuZXhwb3J0JTIwZGVmYXVsdCUyMEJ1dHRvbiUzQiUyMiUyQyUyMmlzRW50cnklMjIlM0FmYWxzZSU3RCU1RCUyQyUyMm9wdGlvbnMlMjIlM0ElN0IlMjJmb3JtYXQlMjIlM0ElMjJlcyUyMiUyQyUyMm5hbWUlMjIlM0ElMjJteUJ1bmRsZSUyMiUyQyUyMmFtZCUyMiUzQSU3QiUyMmlkJTIyJTNBJTIyJTIyJTdEJTJDJTIyZ2xvYmFscyUyMiUzQSU3QiU3RCU3RCUyQyUyMmV4YW1wbGUlMjIlM0FudWxsJTdE" rel="noopener noreferrer"&gt;interactive playground&lt;/a&gt; that I have created.&lt;/p&gt;

&lt;p&gt;This issue is well described in &lt;a href="https://github.com/webpack/webpack/issues/8308" rel="noopener noreferrer"&gt;webpack/webpack#8308&lt;/a&gt; and short outcome is that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code like this &lt;code&gt;g1.staticProperty2 = 'prop2';&lt;/code&gt; can actually cause side-effects, if setters are registered.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Solution 💡
&lt;/h3&gt;

&lt;p&gt;For classes it can be fixed by usage of &lt;a href="https://www.npmjs.com/package/babel-plugin-no-side-effect-class-properties" rel="noopener noreferrer"&gt;babel-plugin-no-side-effect-class-properties&lt;/a&gt; which moves class properties definition to IIFE:&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ui-button&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="c1"&gt;// will be compiled to ➡️&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/*#__PURE__*/&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/*#__PURE__*/&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;_classCallCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ui-button&lt;/span&gt;&lt;span class="dl"&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;Button&lt;/span&gt;&lt;span class="p"&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case there will be no side effects as static properties now defined inside of IIFE.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What about functions?&lt;/em&gt; I haven't found any ready to be used solution yet. On our side we are still discussing the proper solution. To immediately fix this issue the following workaround can be applied:&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;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&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;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultProps&lt;/span&gt; &lt;span class="o"&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;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonClassname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui-button&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it's obviously too hard to scale this approach. However, for React components it may be solved in a different way as there are two common static properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;defaultProps&lt;/code&gt; can be fixed in two ways: for class components the Babel plugin can be used, for functional component I suggest to inline them in &lt;code&gt;props&lt;/code&gt; destructuring as React team is going to &lt;a href="https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md" rel="noopener noreferrer"&gt;deprecate them&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;propTypes&lt;/code&gt; can be removed from production bundles via &lt;a href="https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types" rel="noopener noreferrer"&gt;babel-plugin-transform-react-remove-prop-types&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post can be considered as a followup for library authors, for example &lt;a href="https://github.com/downshift-js/downshift/pull/850" rel="noopener noreferrer"&gt;Downshift.js&lt;/a&gt; met this issue previously.&lt;/p&gt;

&lt;h4&gt;
  
  
  Webpack 5?
&lt;/h4&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%2Fi%2Fq8vn7j22ecmdqvd0h4mm.jpg" 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%2Fi%2Fq8vn7j22ecmdqvd0h4mm.jpg" alt="Output by Webpack 5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also tried the sample with &lt;code&gt;webpack@5.0.0-beta.16&lt;/code&gt; and it's the case there as well because Webpack relies on &lt;a href="https://terser.org/" rel="noopener noreferrer"&gt;Terser&lt;/a&gt; for dead code minification.&lt;/p&gt;




&lt;p&gt;As conclusion I would like to advice library authors rely on their tools as modern JavaScript toolkit is really powerful. &lt;em&gt;But&lt;/em&gt;, at the same time keep your eye on produced bundle size 🦅 &lt;a href="https://bundlephobia.com/" rel="noopener noreferrer"&gt;Bundlephobia&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/webpack-bundle-analyzer" rel="noopener noreferrer"&gt;webpack-bundle-analyzer&lt;/a&gt; can help you there 👋&lt;/p&gt;

</description>
      <category>react</category>
      <category>webpack</category>
    </item>
  </channel>
</rss>
