<?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: Lukas Bombach</title>
    <description>The latest articles on Forem by Lukas Bombach (@lukasbombach).</description>
    <link>https://forem.com/lukasbombach</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%2F218544%2F789a773a-8726-4857-9b29-990a919b589a.jpg</url>
      <title>Forem: Lukas Bombach</title>
      <link>https://forem.com/lukasbombach</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lukasbombach"/>
    <language>en</language>
    <item>
      <title>How to write a tree-shakable component library</title>
      <dc:creator>Lukas Bombach</dc:creator>
      <pubDate>Thu, 06 Feb 2020 15:33:42 +0000</pubDate>
      <link>https://forem.com/lukasbombach/how-to-write-a-tree-shakable-component-library-4ied</link>
      <guid>https://forem.com/lukasbombach/how-to-write-a-tree-shakable-component-library-4ied</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;if you just want to cut to the chase, the final product can be seen, cloned and forked right here on GitHub:&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/LukasBombach/tree-shakable-component-library" rel="noopener noreferrer"&gt;https://github.com/LukasBombach/tree-shakable-component-library&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the beginning of this year I got hired by a new company to help with a new (but not public yet) project. For this, we want to get into design systems and component libraries.&lt;/p&gt;

&lt;p&gt;The topic itself isn't new to us, but implementing one ourselves is. I got the task at finding a setup that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lets us work in a monorepo where our ui library is one package and our app(s) is another&lt;/li&gt;
&lt;li&gt;the ui library must be tree-shakable because we have a keen eye on performance&lt;/li&gt;
&lt;/ul&gt;

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

root
 ∟ packages
    ∟ app
    ∟ ui-library


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

&lt;/div&gt;

&lt;p&gt;Let me elaborate the second point a but more as this is quite important. If you were to create a component library and bundle everything straight forward you would likely end up creating a single file in the CommonJS (CJS) format.&lt;/p&gt;

&lt;h2&gt;
  
  
  CommonJS and ES Modules
&lt;/h2&gt;

&lt;p&gt;Today we have several file formats for JS files in the wild and most of them are still actively used. You can read about the different formats in this very good article by &lt;a class="mentioned-user" href="https://dev.to/iggredible"&gt;@iggredible&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm"&gt;https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The non-deep-dive version is that there is a commonly used format, coincidently named CommonJS (or CJS) and there is a new_ish_ format that most will be familiar with, ES Modules (ESM).&lt;/p&gt;

&lt;p&gt;CJS is what Node.js traditionally used. ESM is newer and standardized (CJS isn't) and will be probably be Node.js' format in the future. It can natively be used &lt;a href="https://2ality.com/2019/04/nodejs-esm-impl.html" rel="noopener noreferrer"&gt;since Node.js 12&lt;/a&gt; and is currently &lt;a href="https://nodejs.org/api/esm.html#esm_ecmascript_modules" rel="noopener noreferrer"&gt;flagged as experimental&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyhow, using Webpack/Babel or TypeScript you will all be familiar with this format. It is the format that lets you write&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;X&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;y&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="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;👆 ESM&lt;/p&gt;

&lt;p&gt;instead of CJS 👇&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;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&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="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;So why is this important at all?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because of tree-shaking!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;If you bundle your ui library in a single CJS file that contains, let's say&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a headline&lt;/li&gt;
&lt;li&gt;a button&lt;/li&gt;
&lt;li&gt;a card and&lt;/li&gt;
&lt;li&gt;an image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and you would import only a single component from your library into your app &lt;strong&gt;your whole library would get loaded and bundled&lt;/strong&gt;. That means even if you only use your button in your app, the entirety of your ui library including the headline, the card and the image would end up in your bundle and make your app &lt;em&gt;sooooo&lt;/em&gt;  much bigger. &lt;a href="https://v8.dev/blog/cost-of-javascript-2019" rel="noopener noreferrer"&gt;Loading time, parsing and execution time would possibly blow up&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;...is of course tree-shaking.&lt;/em&gt; ES Modules make it possible for bundlers to tree-shake your code. If I am not mistaken, this is because the ESM syntax allows bundlers to statically check which parts of your code are used and which are not, which is harder with &lt;code&gt;require&lt;/code&gt; because it can be used in more dynamic ways, like this&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;var&lt;/span&gt; &lt;span class="nx"&gt;my_lib&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;my_lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;foo&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;my_lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;bar&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🤯&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;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So in short, if you want to create a component library, you should make it tree-shakable and if you want to do that, you must use ESM.&lt;/p&gt;

&lt;p&gt;There are other approaches to this. Material UI and Ant Design go in a different direction.&lt;/p&gt;

&lt;p&gt;Instead of creating a single bundle, that exports all components, they actually create &lt;em&gt;a gazillion&lt;/em&gt; tiny bundles, one for each component. So instead of &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Button&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;@material-ui&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;You will do this&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Button&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;@material-ui/core/Button&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;Notice that you load the button from a file (a small bundle) from inside the package &lt;code&gt;/core/Button&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;em&gt;does&lt;/em&gt; work but requires a particular bundling setup and if you're not careful there is a &lt;em&gt;big risk you bundle duplicate code over and over again for each component&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now some may have experience with MaterialUI and Ant Design and have noticed that you &lt;em&gt;can&lt;/em&gt; do this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;DatePicker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&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;antd&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;and everything seems to work alright, but this is just a trick. Ant requires you to install &lt;a href="https://github.com/ant-design/babel-plugin-import" rel="noopener noreferrer"&gt;babel-plugin-import&lt;/a&gt; and use a &lt;a href="https://ant.design/docs/react/use-with-create-react-app#Advanced-Guides" rel="noopener noreferrer"&gt;bonkers setup&lt;/a&gt; with &lt;code&gt;create-react-app&lt;/code&gt; that requires you to rewire your &lt;code&gt;react-scripts&lt;/code&gt;. What this babel plugin does is automatically translate this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;DatePicker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&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;antd&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;into this&lt;/p&gt;

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

import { Button } from 'antd';
ReactDOM.render(&amp;lt;Button&amp;gt;xxxx&amp;lt;/Button&amp;gt;);

      ↓ ↓ ↓ ↓ ↓ ↓

var _button = require('antd/lib/button');
ReactDOM.render(&amp;lt;_button&amp;gt;xxxx&amp;lt;/_button&amp;gt;);


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

&lt;/div&gt;

&lt;p&gt;😧&lt;/p&gt;

&lt;p&gt;The bottom line still is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;None of this is necessary with tree-shaking.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The How
&lt;/h2&gt;

&lt;p&gt;In the end, a setup for this can be simple. For the library I will be using&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Rollup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TypeScript&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and to create a complete setup I will be adding&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;StoryBook&lt;/code&gt; for developing components&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;Next.js&lt;/code&gt; app that consumes the library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will put everything in a monorepo. This will help us structure the code and we will have a single project, which is split into separate non-monolithic packages while with hot-module-reload and no manual steps while developing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;if you just want to cut to the chase, the final product can be seen, cloned and forked right here on GitHub:&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/LukasBombach/tree-shakable-component-library" rel="noopener noreferrer"&gt;https://github.com/LukasBombach/tree-shakable-component-library&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So to begin we have to create a monorepo. I won't explain every line of the code, feel free to ask me in the comments, I will happily try and answer. Also, I will write this using *nix commands as I am using a mac.&lt;/p&gt;

&lt;p&gt;So to create a monorepo I'll be using yarn workspaces with 2 packages, &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;ui-library&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; packages/app
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; packages/ui-library


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

&lt;/div&gt;

&lt;p&gt;You now should have a folder structure like this&lt;/p&gt;

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

root
 ∟ package.json
 ∟ packages
    ∟ app
    ∟ ui-library


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

&lt;/div&gt;

&lt;p&gt;Open your project in a code editor and edit your &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
Remove the &lt;code&gt;main&lt;/code&gt; field and add &lt;code&gt;private: true&lt;/code&gt; and &lt;code&gt;workspaces: ["packages/*"]&lt;/code&gt; so it looks 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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myproject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"workspaces"&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="s2"&gt;"packages/*"&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="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;You now have a &lt;code&gt;Yarn Workspaces MonoRepo&lt;/code&gt; with the packages &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;ui-library&lt;/code&gt;. &lt;code&gt;cd&lt;/code&gt; into &lt;code&gt;packages/ui-library&lt;/code&gt;, create a package and add the following dependencies:&lt;/p&gt;

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

&lt;span class="nb"&gt;cd &lt;/span&gt;packages/ui-library
yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;
yarn add &lt;span class="nt"&gt;-DE&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  @rollup/plugin-commonjs &lt;span class="se"&gt;\&lt;/span&gt;
  @rollup/plugin-node-resolve &lt;span class="se"&gt;\&lt;/span&gt;
  @types/react &lt;span class="se"&gt;\&lt;/span&gt;
  react &lt;span class="se"&gt;\&lt;/span&gt;
  react-dom &lt;span class="se"&gt;\&lt;/span&gt;
  rollup &lt;span class="se"&gt;\&lt;/span&gt;
  rollup-plugin-typescript2 &lt;span class="se"&gt;\&lt;/span&gt;
  typescript


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

&lt;/div&gt;

&lt;p&gt;Now open the &lt;code&gt;package.json&lt;/code&gt; inside &lt;code&gt;packages/ui-library&lt;/code&gt; remove the field for &lt;code&gt;main&lt;/code&gt; and add the following fields for , &lt;code&gt;scripts&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;module&lt;/code&gt;, &lt;code&gt;types&lt;/code&gt;, &lt;code&gt;peerDependencies&lt;/code&gt; so you &lt;code&gt;package.json&lt;/code&gt; looks 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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ui-library"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"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;"rollup -c rollup.config.ts"&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;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/index.cjs.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/index.esm.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/types"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&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;"@rollup/plugin-commonjs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11.0.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@rollup/plugin-node-resolve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.9.19"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.12.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.12.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rollup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.31.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rollup-plugin-typescript2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.25.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.7.5"&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;"peerDependencies"&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;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=16.8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=16.8"&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="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;in your &lt;code&gt;ui-library&lt;/code&gt; folder add a &lt;code&gt;rollup.config.ts&lt;/code&gt; and a &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nb"&gt;touch &lt;/span&gt;rollup.config.ts
&lt;span class="nb"&gt;touch &lt;/span&gt;tsconfig.json


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;rollup.config.ts&lt;/strong&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;commonjs&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;@rollup/plugin-commonjs&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="nx"&gt;resolve&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;@rollup/plugin-node-resolve&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="nx"&gt;typescript&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;rollup-plugin-typescript2&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="nx"&gt;pkg&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;./package.json&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="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;components/index.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cjs&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pkg&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="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&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="na"&gt;external&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="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;resolve&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;commonjs&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;typescript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;useTsconfigDeclarationDir&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;tsconfig.json&lt;/strong&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&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;"declaration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"declarationDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/types"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolveJsonModule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&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;"include"&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="s2"&gt;"components/**/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&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="s2"&gt;"components/**/*.stories.tsx"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now here's the part where I will do some explaining, because this really is the heart of it. The rollup config is set up so that it will load and transpile all TypeScript files using the &lt;code&gt;rollup-plugin-typescript2&lt;/code&gt; plugin. As of today, this one is still more suitable than the official &lt;code&gt;@rollup/plugin-typescript&lt;/code&gt; because the latter cannot emit TypeScript definition files. Which would mean that our UI Library would not export any types to consumers (boo!). We passed an option to the &lt;code&gt;typescript&lt;/code&gt; plugin called &lt;code&gt;useTsconfigDeclarationDir&lt;/code&gt;. This one tells the plugin to use the &lt;code&gt;declarationDir&lt;/code&gt; option from the &lt;code&gt;tsconfig.json&lt;/code&gt;. All other TypeScript options that we have set will already be read from the &lt;code&gt;tsconfig.json&lt;/code&gt;. This means we run TypeScript through Rollup, but all TypeScript related settings reside in the &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What is left to do for rollup is to bundle our files. we could apply anything else a bundler does, like minifying, here too. For now we just create an ES Module, but this setup lets you build on it. Now how do we create an ES Module? For this we have these 2 ouput settings:&lt;/p&gt;

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

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;output&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cjs&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&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;p&gt;This tells rollup to actually create 2 bundles, one in the CJS format, one in ESM. We take the file names for these from the &lt;code&gt;package.json&lt;/code&gt;, this way they are always in sync.&lt;/p&gt;

&lt;p&gt;Ok, but why the CJS option? I'm glad I pretended you asked. When you consume your library, Node.js and other bundlers will not recognize (i.e. pretend it's not even there) if there is no valid &lt;code&gt;main&lt;/code&gt; entry in your &lt;code&gt;package.json&lt;/code&gt; and that entry must be in the CJS format. Also, this will give you backwards compatibility, but without tree-shaking capabilities.&lt;/p&gt;

&lt;p&gt;The interesting part is the entry for &lt;code&gt;es&lt;/code&gt;. We get the files name from the &lt;code&gt;module&lt;/code&gt; entry of our &lt;code&gt;package.json&lt;/code&gt;. Bundlers like Webpack and Rollup will recognize that entry and when set up properly use it and expect an ES Module behind it (while ignoring the &lt;code&gt;main&lt;/code&gt; entry).&lt;/p&gt;

&lt;p&gt;And...&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;Ok well, we do want to test this out. So let's give it a spin:&lt;/p&gt;

&lt;p&gt;In your terminal you should still be in the &lt;code&gt;ui-library&lt;/code&gt; folder. You can confirm that by entering &lt;code&gt;pwd&lt;/code&gt;, which will show you your current working directory.&lt;/p&gt;

&lt;p&gt;If you're there enter&lt;/p&gt;

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

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; components/Button
&lt;span class="nb"&gt;touch &lt;/span&gt;components/index.ts
&lt;span class="nb"&gt;touch &lt;/span&gt;components/Button/Button.tsx


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

&lt;/div&gt;

&lt;p&gt;That should have created the files&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;packages/ui-library/components/Button/Button.tsx&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;packages/ui-library/components/index.ts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;in your project. Edit them as follows&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.ts&lt;/strong&gt; &lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Button&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/Button&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;strong&gt;Button.tsx&lt;/strong&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="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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default &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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I SHOULD BE HERE&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  🎉 🎉 🎉 Now you can run 🎉 🎉 🎉
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yarn build


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

&lt;/div&gt;

&lt;p&gt;There is a new folder now called &lt;code&gt;lib&lt;/code&gt;. In that you have 1 folder and 2 files. open &lt;code&gt;index.esm.js&lt;/code&gt;. You should see an ES Module formatted build of your library:&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;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;var&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="o"&gt;=&amp;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;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;button&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I SHOULD BE HERE&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="p"&gt;{&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;🎉 🎉 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming it
&lt;/h2&gt;

&lt;p&gt;Ok, now we can finally harvest the fruits of our labor. We will create a Next.js app in our monorepo and use our typed, tree-shook library.&lt;/p&gt;

&lt;p&gt;So, from your &lt;code&gt;ui-library&lt;/code&gt; folder &lt;code&gt;cd&lt;/code&gt; into your &lt;code&gt;app&lt;/code&gt; folder and create a next app:&lt;/p&gt;

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

&lt;span class="nb"&gt;cd&lt;/span&gt; ../app
yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;
yarn add &lt;span class="nt"&gt;-E&lt;/span&gt; next react react-dom
yarn add &lt;span class="nt"&gt;-DE&lt;/span&gt; @types/node typescript
&lt;span class="nb"&gt;mkdir &lt;/span&gt;pages
&lt;span class="nb"&gt;touch &lt;/span&gt;pages/index.tsx


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

&lt;/div&gt;

&lt;p&gt;Add the Next &lt;code&gt;scripts&lt;/code&gt; to your &lt;code&gt;package.json&lt;/code&gt; just like you know it from Next:&lt;/p&gt;

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

{
  "name": "app",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "9.2.1",
    "react": "16.12.0",
    "react-dom": "16.12.0"
  },
  "devDependencies": {
    "@types/node": "13.7.0",
    "typescript": "3.7.5"
  }
}
```

And implement your {% raw %}`pages/index.tsx` like so

**index.tsx**

```tsx
import { Button } from "ui-library";

function HomePage() {
  return (
    &amp;lt;div&amp;gt;
      Welcome to Next.js! Check out my &amp;lt;Button /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default HomePage;
```

Now all that is left to do is start your project and see if your button is there:

```bash
yarn dev
```

You should see this now:

![Next App with Component visible on the screen](https://dev-to-uploads.s3.amazonaws.com/i/szaf3c8b6kze7qcm910r.png)

Ok, that was a long ride for a small visible thing. But now you *do* have a lot:

* You have a monorepo with separate independent packages for your ui library and your app(s)
* Your app can be implemented with any JS based technology
* You can have multiple apps in your monorepo comsuming your component library
* Your UI library is tree-shakable and typed with TypeScript
* You can build on your build setup and apply anything from the Rollup cosmos to it

## Bonus

**Hot-Module-Reloading works!** If you in parallel do

```bash
cd packages/app
yarn dev
```

and

```bash
cd packages/ui-library
yarn build -w
```

you can edit your components in your library, they will be watched and rebundled, your Next app will recognize these changes in your monorepo and update automatically too!

If you want to save some time, I have set up a demo project at

https://github.com/LukasBombach/tree-shakable-component-library/

in which I have also added **StoryBook**. In the readme of that project I have also added some instruction in which you can see the tree-shaking for yourself to make sure it works.

Happy coding ✌️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>design</category>
    </item>
  </channel>
</rss>
