<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Patryk Staniewski</title>
    <description>The latest articles on DEV Community by Patryk Staniewski (@exihuatl).</description>
    <link>https://dev.to/exihuatl</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%2F676281%2F97810b5c-ccf9-4520-9ceb-314a68682d69.png</url>
      <title>DEV Community: Patryk Staniewski</title>
      <link>https://dev.to/exihuatl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/exihuatl"/>
    <language>en</language>
    <item>
      <title>You might not need your own UI library.</title>
      <dc:creator>Patryk Staniewski</dc:creator>
      <pubDate>Fri, 22 Oct 2021 16:04:28 +0000</pubDate>
      <link>https://dev.to/exihuatl/you-might-not-need-your-own-ui-library-2go0</link>
      <guid>https://dev.to/exihuatl/you-might-not-need-your-own-ui-library-2go0</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Over the years, I came across a lot of different projects with diverse backgrounds and goals. From small, or even tiny in size and scope, to large monolithic applications with multiple frameworks and few layers of legacy code.&lt;br&gt;
The vast majority of them had one key thing in common - they all had their own, custom library of UI components and various utils.&lt;/p&gt;

&lt;p&gt;I will try to describe my experiences and propose alternatives using popular libraries and frameworks. I’ll try my best to describe the benefits and drawbacks of each scenario.&lt;/p&gt;
&lt;h2&gt;
  
  
  Startup - low cost, high ambitions.
&lt;/h2&gt;

&lt;p&gt;When I joined this startup, let’s call it Guava to not use the real name, they were in the middle of launching their product to mobile (previously the application was only available for desktop users).  It was supposed to replace their legacy app and was, for all the shapes and purposes, a real RWD. In the meantime, they had another website up and running - classical landing pages with homepage, about us, contact, and so on. They didn’t share a single line of code between them even tho they looked alike.&lt;/p&gt;

&lt;p&gt;One of my responsibilities was creating a UI library. That way we could share and reuse the same components across both projects. We started with the design team. They prepared a style guide and described colors, buttons, inputs, etc. We discussed the details and created our own, beautiful and custom-made &lt;code&gt;guava-core&lt;/code&gt;. It had a building blocks and some helpful utilities that could be used in all of our current and future projects.&lt;/p&gt;

&lt;p&gt;Unfortunately, what I didn’t consider back then was the cost of developing this library. We spent few weeks discussing our APIs, another for initial implementation, another for polishing, and another for integration.&lt;/p&gt;

&lt;p&gt;When new features came, they all were first added to our style guide. Some new variants for inputs here, a different hover state over there, a little icon in some of the buttons that weren’t used previously. We didn't want to simply add another set of properties to our components without a really good reason. We asked for a meeting to discuss these differences, sorted them out, but it took another few hours of our time that could be used elsewhere. And, we still needed to code new functionalities.&lt;/p&gt;

&lt;p&gt;Our developer experience and user experience were good, great even. Our library had an elegant, extendable API that we based on &lt;a href="http://styled-system.com" rel="noopener noreferrer"&gt;Styled System&lt;/a&gt;. This doesn’t change the fact that we had to bid farewell to some of our team members, partially because of the rising costs of implementing new features, which increased a time-to-ship.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Our custom fontScale prop&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BoxProps&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;../Reflexbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;system&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;styled-system&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;transformFontScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BoxProps&lt;/span&gt;&lt;span class="p"&gt;)&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&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;fonts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;fonts&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sans-serif&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fontSize&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="nx"&gt;lineHeight&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="nx"&gt;fonts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fontScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BoxProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;fontScale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fontScales&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;font&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;transformFontScale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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="c1"&gt;// &amp;lt;Box fontScale={[2, 4]} /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of our components were kept small and by using atomic design we were able to extend them when needed.&lt;/p&gt;

&lt;p&gt;Looking back however, I would definitely go for &lt;a href="https://mui.com" rel="noopener noreferrer"&gt;Material UI &lt;/a&gt; as the designs were loosely based on material design and with some compromises in both design world and from development standpoint, we could create more features faster and at a fraction of a cost, even with half the team we had.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small company - design flexibility and development speed.
&lt;/h2&gt;

&lt;p&gt;Development of this project started without a dedicated UI team. We had a rough idea of how it’s going to look like based on descriptions and small sketches of our creative director. We wanted to focus on developing core functionalities like sign-in &amp;amp; login, managing users, creating content, and so on. To speed things up, we decided to use &lt;a href="http://baseweb.design" rel="noopener noreferrer"&gt;Base Web&lt;/a&gt; (well, we started from material-ui, but we didn’t like its approach to styling back then).&lt;/p&gt;

&lt;p&gt;Implementing our views was trivial, each component is heavily tested, both through e2e and unit tests. It has thorough documentation with lots of examples.&lt;/p&gt;

&lt;p&gt;Sometimes later, the design came from a dedicated design studio. They were… let’s just say a lot, different than what we had in baseweb and they came a few weeks later than they supposed to. Because of that, we had a shorter time to adjust our frontend so we had to improvise.&lt;/p&gt;

&lt;p&gt;As it turned out, extending baseweb was rather easy, because of its &lt;a href="https://baseweb.design/guides/theming/" rel="noopener noreferrer"&gt;theming&lt;/a&gt; and &lt;a href="https://baseweb.design/guides/understanding-overrides" rel="noopener noreferrer"&gt;overrides API&lt;/a&gt;.  In our theme file, we defined the correct colors and customized some global overrides.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;inputBorder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputPlaceholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputPlaceholderDisabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tickFillSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tickFillSelectedHover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tickFillSelectedHoverActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;primitives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buttonPrimaryFill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buttonPrimaryHover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accent300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buttonPrimaryActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accent200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;borders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;buttonBorderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputBorderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;surfaceBorderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;popoverBorderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&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;We also created &lt;code&gt;ui&lt;/code&gt; catalog in our project and made reexports from &lt;code&gt;baseui/*&lt;/code&gt; to &lt;code&gt;ui/*&lt;/code&gt;. That allowed us to then make overrides per component without changing its API or modifying its import path, for example, our extended tooltip looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FC&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;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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StatefulTooltip&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;BaseStatefulTooltip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StatefulTooltipProps&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;baseui/tooltip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mergeOverrides&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;baseui/helpers/overrides&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="o"&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;baseui/tooltip&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;statefulTooltipOverrides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;280px&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="na"&gt;Inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;700&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StatefulTooltip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StatefulTooltipProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nc"&gt;BaseStatefulTooltip&lt;/span&gt; &lt;span class="na"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;mergeOverrides&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statefulTooltipOverrides&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&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;We couldn’t however, override some styles globally, without extending each component separately, like &lt;code&gt;border-width&lt;/code&gt; or &lt;code&gt;font-weight&lt;/code&gt; for labels.&lt;br&gt;
We decided that it would be more beneficial for us based on our team size (2 frontends and one full-stack) to create manual overwrites in one global CSS file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* --------- BASE WEB OVERRIDES -------------------- */&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-baseweb&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-baseweb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"checkbox"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"checkbox"&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-baseweb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"select"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border-top-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-bottom-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-left-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-right-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-baseweb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"form-control-label"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-baseweb&lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="s1"&gt;"typo-heading"&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-baseweb&lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="s1"&gt;"typo-label"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;${&lt;/span&gt;&lt;span class="n"&gt;baseTheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;primary700&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, it’s a little bit nasty, but it’s really easy to investigate when something is being overwritten by this code in dev tools, is contained in one, tiny CSS file, and well... works like a charm.&lt;/p&gt;

&lt;p&gt;We had a few situations, we couldn’t easily overwrite some of the design decisions. We reached out to our designers, and they were happy to help. We changed our UI just enough to not create custom components or large overrides to avoid maintenance costs and potential bugs.&lt;/p&gt;

&lt;p&gt;The project was launched successfully and is being used by people worldwide, our codebase is tiny compared to what is happening under the hood in baseweb, is easy to test, and cheap to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Large corporation - everything custom-tailored to the product.
&lt;/h2&gt;

&lt;p&gt;In larger companies, there is a strong tendency to do everything made in-house. The success of their UI libraries differs from company to company.&lt;/p&gt;

&lt;p&gt;In some of my projects, we had a dedicated team responsible for creation and maintenance. In both of them, designs are created based on the core style guide, developers create new features using provided components. In case of missing an element or design not matching used components, a developer makes a request for changes in the library and waits. This workflow, even though it has some clear limitations and disadvantages, works well in really large projects, where the time to develop new features is a lot longer. &lt;/p&gt;

&lt;p&gt;Other times, companies don’t see major value in these teams or are trying to reduce the costs of their IT departments. This is a long-term nightmare to maintain, as a large number of developers make changes and add components that will be used in their (sometimes very specific) use case without having a larger scope in mind. In this scenario, the codebase is getting ever larger without possible reductions insight without a huge amount of meetings and coordination between different teams. This is one of the major factors in having “legacy projects” and rewrites over time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ResetButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ButtonNoBackground&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`
  display: flex;
  position: absolute;
  top: 0;
  right: 0;
  cursor: pointer;
  min-height: 48px;
  min-width: 48px;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases, however, maintenance cost is really, really high. When a company chooses to pay for a dedicated team, they have to bear in mind a developer’s increasingly high salaries. Alternatively, when moving maintenance to individual developers ad-hoc, payment is made through a longer development time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;In my opinion, companies overvalue custom-tailored solutions and gloss over existing libraries based on hypothetical problems that might come in the future. &lt;br&gt;
Oftentimes, increased pace to mark a product as “legacy” and rewrites every few years are not mentioned in initial meetings. Each of us wants to create the best possible product that will last forever, but that is not the case, especially in the javascript world. New features, frameworks, libraries, and patterns come almost weekly and we all want to work in the latest stacks.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Journey to Svelte (through Gatsby)</title>
      <dc:creator>Patryk Staniewski</dc:creator>
      <pubDate>Thu, 23 Sep 2021 06:41:44 +0000</pubDate>
      <link>https://dev.to/exihuatl/journey-to-svelte-through-gatsby-1n1k</link>
      <guid>https://dev.to/exihuatl/journey-to-svelte-through-gatsby-1n1k</guid>
      <description>&lt;p&gt;Our journey began with… Gatsby, but let’s start from the beginning.&lt;/p&gt;

&lt;p&gt;We received designs from our UI team, project manager created stories for a new project - a promo site for a new product - and we started discussing technologies. We’ve decided to go the safest route and went for Gatsby - React static site generator. It gives a lot - image optimizations, themes, plugins, GraphQL API, you name it.&lt;/p&gt;

&lt;p&gt;We have created our &lt;a href="https://bradfrost.com/blog/post/atomic-web-design/" rel="noopener noreferrer"&gt;atomic components&lt;/a&gt;, made a static homepage, and connected it to our API.  Next, we’ve added the rest of the pages, such as various policies and user agreements, about us, pricing, and so on.&lt;br&gt;
After that, there was a design and QA review, and they reported their feedback. We’ve made fixes, adjusted our tests, and voilà, a website was born. Slowly we’ve been adding small, simple features while polishing our actual product - a collaborative content studio platform that empowers PR &amp;amp; IR professionals.&lt;/p&gt;

&lt;p&gt;And then one day, almost a year later, our planning session started. New business stories were presented - we were to add "News Hub" which would be a list of articles that we can click through with search, filters, and paginations, and a single article view with an ability to share articles on social media. Nothing extraordinary but as with almost all related sites, it had to be prerendered to have a satisfactory SEO experience. Since we didn’t know about it at the beginning, we didn’t prepare our stack accordingly hence we needed to figure out how to achieve server-side rendering in Gatsby.&lt;/p&gt;

&lt;p&gt;It was a real brick wall. Even if we were to compromise SEO, we weren’t able to make dynamic metatags that are needed for social media, such as &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;og:image&lt;/code&gt;, &lt;code&gt;og:url&lt;/code&gt; and so on that are needed before our JS could finish rendering the page.&lt;/p&gt;

&lt;p&gt;Finally, after few days of fighting with it, we decided we need to look for another way to avoid the &lt;em&gt;Sunk Cost Fallacy&lt;/em&gt;. We went to the drawing board and discussed our options. The most obvious one was NextJS which is another React framework, but what differentiates it from Gatsby is that it can handle both SSR and SSG. We spent a few hours replacing configuration files, moving files around, and renaming our environmental variables. The site was up and running on our develop tier, but after running performance tests, we found out that it was a lot worse than before.&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%2Ff5k8m0ji8p1ozgaly5m5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5k8m0ji8p1ozgaly5m5.png" alt="lighthouse performance screen after migrating to nextjs" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We understood that more changes were needed to match standard NextJS performance that usually reaches upwards of 80 in LH. But how many changes? How much time would we need? These were difficult questions to answer at that time and frankly, we weren’t exactly looking forward to profiling individual components to increase our score.&lt;/p&gt;

&lt;p&gt;By that time, we had some troubles with virtual dom itself in our custom rich text editor that we based on &lt;a href="https://docs.slatejs.org/" rel="noopener noreferrer"&gt;slate&lt;/a&gt; - it was getting a bit laggy when creating huge financial documents (they usually have enormous tables and a lot of infographics) -so we were already thinking about other options and that’s where &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;svelte&lt;/a&gt; comes into the light - especially &lt;a href="https://sapper.svelte.dev/" rel="noopener noreferrer"&gt;sapper&lt;/a&gt; which was de facto default framework to be used with &lt;code&gt;svelte&lt;/code&gt; at that time (&lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt; wasn’t even announced).&lt;/p&gt;

&lt;p&gt;We didn’t have any plans for that weekend anyway so we decided to try it out in our own free time, because well, why not. It turned out to be a lot easier than we were expecting (although not as trivial as one would hope).&lt;/p&gt;

&lt;p&gt;First of all, we started by creating a separate branch and run &lt;code&gt;rm -rf *&lt;/code&gt;. After a few commands and we were greeted by a sapper page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx degit "sveltejs/sapper-template#webpack" .
npm install
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We got familiar with folder structure and get to work.&lt;/p&gt;

&lt;p&gt;Our components in React were based on &lt;a href="https://styled-system.com/" rel="noopener noreferrer"&gt;Styled System&lt;/a&gt;, which we had huge success with previously. It let us quickly build components with responsive styles based on scales defined in our theme object. Under the hood, it uses &lt;a href="https://emotion.sh/docs/introduction" rel="noopener noreferrer"&gt;Emotion&lt;/a&gt; to create dynamic styles on page creation.&lt;/p&gt;

&lt;p&gt;Our components looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ContentHeader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Flex&lt;/span&gt;
    &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;mb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&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="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h1"&lt;/span&gt; &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Flex&lt;/span&gt;&lt;span class="p"&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;Although Svelte supports CSS-in-JS and we could theoretically make it work, we thought it would be better to keep it simple. We added one of the most popular CSS framework to our setup &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;, adjusted &lt;code&gt;tailwind.config.js&lt;/code&gt; according to our previous theme, and started converting our components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-center mb-4 text-white bg-secondary lg:md-8"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-3xl lg:text-5xl"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;slot&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;49% fewer characters were used to create the same component (even better than Rich has promised us in &lt;a href="https://svelte.dev/blog/write-less-code" rel="noopener noreferrer"&gt;Write less code&lt;/a&gt;). But maybe it works great for simple, presentational components. What about more advanced examples like components with custom hooks and refs?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// REACT&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;useClickOutside&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&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;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&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;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;useOnClickOutside&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;{&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;testid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dropdown&lt;/span&gt;&lt;span class="dl"&gt;"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SVELTE&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;useClickOutside&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultPrevented&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&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;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;useClickOutside&lt;/span&gt; &lt;span class="na"&gt;data-testid&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dropdown"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another win for Svelte, this time by around 35%. The pattern continued with all of our components, hooks, and pages. Our codebase shrunk by just a shy of 45% characters, was easier to read and maintain. &lt;/p&gt;

&lt;p&gt;It took the two of us about 20 hours to complete the rewrite. We’ve made the finishing touches on Monday and ran our tests again on develop tier. &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%2Fdr1tg0iylhyu5rynoyr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr1tg0iylhyu5rynoyr5.png" alt="lighthouse performance screen after rewrite" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Performance on our develop tier matched our production which has additional optimizations like CDN and caching.&lt;/p&gt;

&lt;p&gt;We presented our results, send the project to our QA team for another session, and in less than our two-week sprint - our website was redeployed and ready to add additional pages and functionalities - ready for SSR-ed articles for the world to see.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>svelte</category>
      <category>react</category>
    </item>
    <item>
      <title>Vertical teams at scale a.k.a how to scale frontend work in growing organisation</title>
      <dc:creator>Patryk Staniewski</dc:creator>
      <pubDate>Wed, 22 Sep 2021 08:59:03 +0000</pubDate>
      <link>https://dev.to/exihuatl/vertical-teams-at-scale-a-k-a-how-to-scale-frontend-work-in-growing-organisation-4lef</link>
      <guid>https://dev.to/exihuatl/vertical-teams-at-scale-a-k-a-how-to-scale-frontend-work-in-growing-organisation-4lef</guid>
      <description>&lt;h2&gt;
  
  
  What we were trying to achieve?
&lt;/h2&gt;

&lt;p&gt;We want to scale our work between multiple independent teams each with its product owner, designer, and multiple engineers. To do that we have a few solutions that we’ll discuss and I’ll try to explain our logic behind making our final decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are our options?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Separate applications with a host.
&lt;/h3&gt;

&lt;p&gt;Creating independent applications that would live in separate repositories is one of the most popular way of building frontend. Each team has its own technologies, tools, and buildchain which some of them really value. There is unfortunately one hefty problem - versioning. In this setup, after making a change in our application we would have to update version in package registry and then bump version inside our “host application”. And then there is our UI library that each app is using.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monorepo to the rescue?
&lt;/h3&gt;

&lt;p&gt;Our current application is a monorepo, rather large monorepo.&lt;br&gt;
At the time of writing this article, we have 19290 files with 3580303 lines of code with 89 authors in the last few months.&lt;br&gt;
To create new applications we don’t have to think about build configurations. Linters, unit tests, e2e tests are all already set up and ready for development. It’s as simple as adding a new directory and path to our app routing. It comes at a cost of being forced to use specific technologies and tools. Changing them would need to be approved and developed by each individual team and it’s a nightmare to coordinate.&lt;br&gt;
Additionally, our pipeline’s duration is already ranging between tiresome and infinite (our last worked for 52 minutes). Merge requests are happening on average every hour so we have a constant stream of workers…ehm…working.&lt;br&gt;
Unfortunately, deployment is shared across all teams so even the smallest of changes needs to be verified through multiple people in code review and needs to pass our pipelines two times (one before making a merge and one after on master branch).&lt;/p&gt;
&lt;h3&gt;
  
  
  Microfrontend to the rescue?
&lt;/h3&gt;

&lt;p&gt;A microfrontend is a microservice that exists within a browser. Each microfrontend has its own repository, its own build configuration and process, and is being able to be deployed individually. There is a lot of implementation of this concept. One of the most popular tool that helps is &lt;a href="https://single-spa.js.org/" rel="noopener noreferrer"&gt;single-spa&lt;/a&gt; - a framework for bringing together multiple JavaScript microfrontends in a frontend application. It is an incredible tool and should be considered for greenfield projects. It gives a lot of tools and features, such as being able to use different frameworks in the same application.&lt;/p&gt;

&lt;p&gt;These additional features however would mean increased initial payload and memory allocation. Although performance overhead is minor, when we don’t use these additional functionalities it’s a waste of resources, especially when setting up &lt;code&gt;single-spa&lt;/code&gt; would be costly to implement in our existing setup.&lt;/p&gt;
&lt;h3&gt;
  
  
  Module federation to the rescue?
&lt;/h3&gt;

&lt;p&gt;Finally, we decided to integrate new applications using Webpack’s latest feature - module federation. It integrates nicely with our webpack configuration, has a tiny boilerplate, and is straightforward to read (after understanding the complexity of webpack itself).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Multiple separate builds should form a single application. These separate builds should not have dependencies between each other, so they can be developed and deployed individually. - Webpack team  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We distinguish between local and remote modules. Local modules are normal modules that are part of the current application. Remote modules are modules that are being loaded at the runtime.&lt;/p&gt;

&lt;p&gt;The idea is simple. An application references a remote using a configured name that is not known at compile time. That reference is only resolved at runtime by the so-called remote entry point. It’s a minimal script that provides actual external.&lt;/p&gt;

&lt;p&gt;In its simplest form, the code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// webpack.config.js&lt;/span&gt;
&lt;span class="kr"&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="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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModuleFederationPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mother&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;remotes&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="s2"&gt;remote&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="s2"&gt;remote@http://localhost:3001/remoteEntry.js&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;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RemoteApp&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;remote/App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our remote application will be imported from an external URL instead of our local repository and loaded at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we gained by adopting microservice architecture?
&lt;/h2&gt;

&lt;p&gt;Microfrontend gave us a lot of benefits and resolved a lot of issues we had. We’ll walk through in a bit more details.&lt;/p&gt;

&lt;h5&gt;
  
  
  Independent teams - independent applications
&lt;/h5&gt;

&lt;p&gt;Our vertical teams can work on their own in separate repositories and are free to choose the technologies they need to create the best user experience.&lt;/p&gt;

&lt;h5&gt;
  
  
  Autonomous deployments
&lt;/h5&gt;

&lt;p&gt;Our team can now deploy features without being dependent on the mother app. We were able to set up our pipelines that on average last about 8 minutes. &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%2Fsc8gxtjspgjyryuuhub4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc8gxtjspgjyryuuhub4.png" alt="pipeline preview" width="295" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Code trimming
&lt;/h5&gt;

&lt;p&gt;We are not adding additional code to the already humongous codebase of our monorepo.&lt;/p&gt;

&lt;h5&gt;
  
  
  Onboarding new people
&lt;/h5&gt;

&lt;p&gt;Onboarding can be overwhelming for new developers, especially juniors that join our teams. We eased the process and new friends were able to contribute even on their first day with confidence.&lt;/p&gt;

&lt;h5&gt;
  
  
  Developer experience
&lt;/h5&gt;

&lt;p&gt;It’s often overlooked, but developer experience is crucial for every successful project. Because we created a new project and were independent of our monorepo application, we were able to integrate Snowpack into our day-to-day work. It gave us instant startup time with a fast refresh and cleaner configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What problems we've encountered?
&lt;/h2&gt;

&lt;p&gt;On a road to production, we had a few blockades that none of us had met before. We had to be a little bit more creative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Singleton libraries
&lt;/h3&gt;

&lt;p&gt;In libraries such as React, we cannot run multiple versions of the same library at once if they don’t share the same version. We updated to the latest version in both applications which was a lengthy process. After that, we added our react library to shared dependencies in Wepback configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModuleFederationPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;shared&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="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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;singleton&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;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Preview environment
&lt;/h3&gt;

&lt;p&gt;Our monorepo is using preview deployments to be able to test changes both manually and using e2e tests. By using module federation, we are not creating branches in our mother app - code is dynamically run directly on the client and server-side.&lt;br&gt;
The way we were able to get around that was by dynamically injecting the correct remote based on the parameter in the URL. It was not as easy as we thought. To achieve that we had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy our remote application to be available through some dynamic URL on each pull request. We created a deploy preview step in our CI that created dynamic storage using Amazon’s Simple Storage Service.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://&lt;span class="nv"&gt;$bucketName&lt;/span&gt;.s3.eu-central-1.amazonaws.com/federated/remoteEntry.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Inject this dynamic remote into our living staging environment.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://website.com?remoteApp1=https://$bucketName.s3.eu-central-1.amazonaws.com/federated/remoteEntry.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;remoteApp1&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;ol&gt;
&lt;li&gt;Insert script tag with this remote.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&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="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt;&lt;span class="p"&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;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Load actual component to be used in our code.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;module&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="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Learning curve
&lt;/h3&gt;

&lt;p&gt;Our setup has a steep learning curve. There is a lot to learn and understand to get a grasp for some of the low-level concepts and webpack documentation isn’t much easier to read with its building blocks defined as &lt;code&gt;ContainerPlugin&lt;/code&gt;, &lt;code&gt;ContainerReferencePlugin&lt;/code&gt;, and &lt;code&gt;ModuleFederationPlugin&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Module federation filled an enormous gap in the frontend world. Lessons learned can help us extract some of the self-contained applications currently living inside monorepo to speed our development and give a lot of freedom to autonomous teams. &lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Our current setup is impressive for us. With our fast pipelines, separate deployments, and independent teams we are more agile than ever.&lt;br&gt;
But we must not rest on our laurels. There is a new version of React coming and we need to figure out a way of introducing backward-incompatible changes such as this. And we have our eyes on the new cool kids on the block - Javascript’s native module system (ESM) and non-JS bundlers such as esbuild written in Go.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>architecture</category>
      <category>microfrontend</category>
    </item>
  </channel>
</rss>
