<?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: Dima Grossman</title>
    <description>The latest articles on Forem by Dima Grossman (@scopsy).</description>
    <link>https://forem.com/scopsy</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%2F238169%2F86161e27-3d14-4d17-a4f5-8dc42a183890.jpeg</url>
      <title>Forem: Dima Grossman</title>
      <link>https://forem.com/scopsy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/scopsy"/>
    <language>en</language>
    <item>
      <title>The Full-Stack Components Customization Pyramid</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Wed, 18 Sep 2024 12:50:39 +0000</pubDate>
      <link>https://forem.com/novu/the-full-stack-components-customization-pyramid-5e72</link>
      <guid>https://forem.com/novu/the-full-stack-components-customization-pyramid-5e72</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Component Anatomy&lt;/li&gt;
&lt;li&gt;The Customization Pyramid&lt;/li&gt;
&lt;li&gt;Appearance Prop&lt;/li&gt;
&lt;li&gt;Render props&lt;/li&gt;
&lt;li&gt;Composition&lt;/li&gt;
&lt;li&gt;React Hooks&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A while back, I came across a tweet by Colin from &lt;a href="http://clerk.com/" rel="noopener noreferrer"&gt;Clerk.com&lt;/a&gt; stating that "&lt;strong&gt;Components are the new API.&lt;/strong&gt;" I couldn't agree more. For years, we've been dedicated to building embeddable components for our customers. The objective is straightforward: How can we create a fully functional component that feels so integrated and seamless that it appears to be built in-house by the host application?&lt;/p&gt;

&lt;p&gt;Previously, a common pattern for embedding components using controllable iframes led to inconsistent behavior and, in many cases, was felt disconnected. The rise of the meta frameworks and the serverless motion provided an easier paradigm to embed native to the framework components that are one with the host application.&lt;/p&gt;

&lt;p&gt;You've probably encountered numerous examples already: Stripe, Clerk, Liveblocks, Algolia, and others.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Component anatomy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;All of the successful components I’ve interacted with showcased the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First-class User Experience (UX)&lt;/strong&gt;: It felt like a dedicated team crafted the component just for my application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazing Developer Experience (DX)&lt;/strong&gt;: It was intuitive and easy to get started within minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizability&lt;/strong&gt;: It could seamlessly blend into my host application, but still provided a strong opinion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight bundle size&lt;/strong&gt;: It was efficient and minimal in size&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common framework:&lt;/strong&gt; The component was available in the framework I used in my app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Did I miss anything you think is important? Share your observations in the comments section.&lt;/p&gt;

&lt;p&gt;In this article, we will focus on component customization and styling. I'll share some lessons we learned while building the new Novu &lt;code&gt;&amp;lt;Inbox /&amp;gt;&lt;/code&gt; component and how we approached meeting our customers' needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The customization pyramid&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg35sdrdmpbc2q3ri9i07.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg35sdrdmpbc2q3ri9i07.jpg" alt="Image description" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Customization and styling exist on a spectrum between more control and less control. Whether you are just starting out and want to get up and running quickly, or you are a Fortune 500 company with a strict design system, a team of designers, and complex requirements, you should always be able to achieve your goals in the least amount of time and still have an amazing developer experience.&lt;/p&gt;

&lt;p&gt;Let's explore the customization pyramid concept using Novu’s new &lt;code&gt;&amp;lt;Inbox /&amp;gt;&lt;/code&gt; component as an example. By the way, our source code is open-source and publicly available in the &lt;a href="https://github.com/novuhq/novu/tree/next/packages/js/src" rel="noopener noreferrer"&gt;Novu GitHub Repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we’ve also made our &lt;a href="https://www.figma.com/design/0FIyK1FshxvMeYtJL5xsAa/External-Inbox-Design-File?node-id=0-1&amp;amp;node-type=canvas&amp;amp;t=IOf6TltPigvjuk61-0" rel="noopener noreferrer"&gt;Figma design asset file&lt;/a&gt; publicly available, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Appearance Prop&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can think of the appearance prop as a white-labeled internal to the component UI system, that allows styling and modifying different aspects of the component.&lt;/p&gt;

&lt;p&gt;A component should be opinionated and render a beautifully crafted UI out of the box. For Novu’s &lt;code&gt;&amp;lt;Inbox /&amp;gt;&lt;/code&gt; component, it's as simple as rendering &lt;code&gt;&amp;lt;Inbox /&amp;gt;&lt;/code&gt; in your application. Instantly, you get a fully functional UI with a bell icon that opens a popover implementation.&lt;/p&gt;

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

&lt;p&gt;The first thing we might want to do is to make sure that our brand colors and design guidelines are matched within the component. This is where the &lt;code&gt;appearance&lt;/code&gt; prop comes into play&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="nc"&gt;Inbox&lt;/span&gt; &lt;span class="na"&gt;appereance&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;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;primaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pink&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;borderRadius&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;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;notificationSubject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;notificationPrimaryAction__button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;18px&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="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;
  
  
  &lt;strong&gt;Variables&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These are the variables that apply to all major elements in the UI. Adjusting just a few of these should allow the component to immediately adopt the look and feel of the host application. Variables for typography, colors, and spacing should be included here.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Elements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This section provides more in-depth control over visible elements within the component. At Novu, we namespace components as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;notificationSubject&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;notificationBody&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;notificationPrimaryAction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;notificationPrimaryAction__button&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;For sub-elements, we use an underscore notation to namespace repeated components such as buttons and labels.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Customers should be able to choose their preferred styling framework, whether it's Tailwind, CSS Modules, or plain CSS, and it should work seamlessly out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌟 Tip:&lt;/strong&gt; We've added a 🔔 icon to the class name list to help identify the element names. Everything before this emoji can be targeted and styled easily using the elements field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51lrw6nacoxrqbgyth18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51lrw6nacoxrqbgyth18.png" alt="Inbox side by side with outlines for composable components" width="800" height="171"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Render props&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In some use cases, styling with CSS alone isn't sufficient. For example, in our world, customers might want to render their own custom notification item components, enrich them with live data, or reuse existing UI elements as part of the notification flow.&lt;/p&gt;

&lt;p&gt;Here's how this can look:&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="nc"&gt;Inbox&lt;/span&gt; &lt;span class="na"&gt;renderNotification&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="nx"&gt;notification&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="nc"&gt;CustomersCustomItem&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&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;p&gt;This approach provides significantly more control over the look, feel, and behavior of the notifications while still abstracting away the complexities of layouts, real-time updates, fetching, and notification settings.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Composition&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;While your components should be opinionated, you should not limit your customers to achieving their end goal of implementation. In some cases, you cannot predict the UX pattern they want to use that fits the specifics of their business.&lt;/p&gt;

&lt;p&gt;There is a huge gap that sits between a “headless” mode, where you have to build everything from scratch, and the one-liner  component that abstracts away pretty much all the internals. Compostable sub-components should bridge this gap, by breaking the one-liner into multiple components that can be re-organized to match different UX patterns.  &lt;/p&gt;

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

&lt;p&gt;To facilitate this, your components should be composable. Break down the component structure into independent elements, each focusing on a single goal. In our example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Bell /&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Notifications /&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Preferences /&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Inbox /&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each element can be rendered as a standalone component and combined to create various layouts, still abstracting away complexity.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;React Hooks&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When customers have strict design and UX requirements, using React Hooks are invaluable. However, resorting to a headless approach like this sometimes indicates a failure to provide adequate styling and composition options, or potentially a framework-specific SDK. To better understand the reasoning, we engage with customers who choose this route to understand if their use case can benefit others.&lt;/p&gt;

&lt;p&gt;The React Hooks headless SDK allows customers to build any UI they want, managing the look and feel, state, interactions, and layout themselves.&lt;/p&gt;

&lt;p&gt;Here's an example:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Novu&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;@novu/js&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;novu&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;Novu&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;subscriberId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUBSCRIBER_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;applicationIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;APPLICATION_IDENTIFIER&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;novu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;novu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notifications.notification_received&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="nx"&gt;data&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new notification =&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&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;The headless SDK provides no UI but offers a straightforward set of wrappers around your component's most common API and server actions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thinking from the perspective of your users and setting up the right architecture in the beginning will go a long way. Invest the time debating DX, show this to your users, and try to understand the main friction points in their adoption. Lastly, think of your customization strategy in layers to allow your customers to start fast and not block them if they have more specific styling and UX requirements.&lt;/p&gt;

&lt;p&gt;I’m curious to see where the future of “Components are the new API” will take us as a team, and I'm looking forward to learning from our amazing community.&lt;/p&gt;

&lt;p&gt;Finally, I’d be remiss if I didn’t tell you to take a look at our result. &lt;a href="https://inbox.novu.co/?utm_campaign=blog-dg-component" rel="noopener noreferrer"&gt;Here, you’ll find a fully functional &lt;code&gt;&amp;lt;Inbox /&amp;gt;&lt;/code&gt; playground&lt;/a&gt; we styled to mimic popular apps (Notion and Reddit), and then you can also experiment by customizing your own.&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__238169"&gt;
    &lt;a href="/scopsy" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F238169%2F86161e27-3d14-4d17-a4f5-8dc42a183890.jpeg" alt="scopsy image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/scopsy"&gt;Dima Grossman&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/scopsy"&gt;Musician, Baker, and Maker. Creator of Novu - The open-source notification infrastructure for engineers.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>react</category>
      <category>javascript</category>
      <category>css</category>
      <category>programming</category>
    </item>
    <item>
      <title>A stage for our open-source contributors</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Wed, 08 Jun 2022 14:06:20 +0000</pubDate>
      <link>https://forem.com/scopsy/a-stage-for-our-open-source-contributors-1f52</link>
      <guid>https://forem.com/scopsy/a-stage-for-our-open-source-contributors-1f52</guid>
      <description>&lt;p&gt;When we first showed the world &lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;Novu&lt;/a&gt; (an open-source notification infrastructure) we were amazed by the incredible adoption by our community members and how the project was shaped by the dozen of individual contributors from around the world. &lt;/p&gt;

&lt;p&gt;Over the past 6 months, more than 2,000 commits were made by more than 50 different contributors who sparked incredible ideas and helped with almost any aspect of &lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;Novu.co&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last couple of weeks, we thought of a way for us to showcase these incredible individuals who are bringing Novu to life.&lt;/p&gt;

&lt;p&gt;Excited to share with you the Novu Community Heroes program to highlight our contributors and showcase their work to the world. &lt;/p&gt;

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

&lt;p&gt;We created a unique page for every single contributor highlighting their:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latest pull request and contributions&lt;/li&gt;
&lt;li&gt;Their public GitHub profile bio&lt;/li&gt;
&lt;li&gt;Social Media Link&lt;/li&gt;
&lt;li&gt;Contribution Badges&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;You can find the link here:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://novu.co/contributors/" rel="noopener noreferrer"&gt;https://novu.co/contributors/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We encourage every open-source library to promote its contributors in every possible way. This project was not easy to make as we needed a way to automate all our contributor's actions.&lt;/p&gt;

&lt;p&gt;So we have created this public repository if you are curios on have it was implemented:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/novuhq/contributors" rel="noopener noreferrer"&gt;https://github.com/novuhq/contributors&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have been using &lt;a href="http://Orbit.love" rel="noopener noreferrer"&gt;Orbit.love&lt;/a&gt; and GitHub to sync our contributor's work, and grant them badged and medals once a PR was approved. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to earn a Novu Contributor Badge?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Head over to our Novu's issue page, find an issue that you might want to help with and get a PR ready (need any help? you can reach us on Discord).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The future of Novu Contributors Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's only the beginning of the project. We have an excellent roadmap of more things we want to feature, such as&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Discord Contributions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Github Discussions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Github Issues&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content creators&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do you think about something specific we should add? Happy to hear it in the comments&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>news</category>
    </item>
    <item>
      <title>Our open-source project got funded!</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Wed, 11 May 2022 14:02:14 +0000</pubDate>
      <link>https://forem.com/novu/our-open-source-project-got-funded-1bon</link>
      <guid>https://forem.com/novu/our-open-source-project-got-funded-1bon</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hi Community, We have exciting news to share!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/combarnea"&gt;@combarnea&lt;/a&gt; and I open-sourced the Novu project (check our &lt;a href="https://github.com/novuhq/novu"&gt;GitHub Page&lt;/a&gt;) because we both felt the pain of building a notification infrastructure from scratch. I have written about the inception of the idea and you can read it here: &lt;a href="https://dev.to/scopsy/building-the-first-open-source-notification-infrastructure-5h9k"&gt;Building the first open-source notification infrastructure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to the incredible interest of this fantastic community, our Github project became trending and grew from 200 stars to 2.2K stars, and today has more than 3,500 stars.&lt;br&gt;
We can’t thank the community enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Novu?
&lt;/h2&gt;

&lt;p&gt;Novu is the first open-source notifications infrastructure for developers.&lt;br&gt;
It solves developers the pain of building from scratch and maintaining their notification systems.&lt;br&gt;
That can be an in-app notification center (like you might know from platforms like Facebook) to transactional messages sent over multiple delivery channels.&lt;br&gt;
Our goal is to solve a large number of use-cases from digest engine, to advanced workflows management including user preferences, timezone awareness, and more. &lt;/p&gt;

&lt;p&gt;And the best part is - We are building this with the incredible help and involvement of the open-source community. Together. &lt;/p&gt;

&lt;p&gt;Lately, we have raised a $6.6m round. This means we can go and build this project full-time. A dream comes true. It will also enable us to grow it and become the de-facto solution for developers when thinking about notifications and product-based communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6ivhlinjfqmrupkmf8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6ivhlinjfqmrupkmf8s.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With our new funding, Novu recruited many of our contributors to work full-time on Novu and is now working on creating the best OSS notification infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So what happened since the funding?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have released our admin control panel for managing notifications (npx novu init) yay!.&lt;/li&gt;
&lt;li&gt;We have created a new website, updated with all the new features.&lt;/li&gt;
&lt;li&gt;We started to work closely with contributors and fund projects.&lt;/li&gt;
&lt;li&gt;We have sponsored events.&lt;/li&gt;
&lt;li&gt;Released our multi-environment support&lt;/li&gt;
&lt;li&gt;Released our In-app notification center as an Iframe or as a React component&lt;/li&gt;
&lt;li&gt;Released more providers and providers dashboard&lt;/li&gt;
&lt;li&gt;Added New team collaboration and invites&lt;/li&gt;
&lt;li&gt;Released a new monitor and observability page&lt;/li&gt;
&lt;li&gt;Created an awesome registration flow using a CLI :)&lt;/li&gt;
&lt;li&gt;All in open source!!!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The future?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support every possible notification channel: Direct, Push and others.&lt;/li&gt;
&lt;li&gt;Create an intelligent workflow for automating your notifications channels.&lt;/li&gt;
&lt;li&gt;Add digest capabilities to make end-user life so much easier&lt;/li&gt;
&lt;li&gt;Have a new user preference control within our in-app and as a system&lt;/li&gt;
&lt;li&gt;Many more to come&lt;/li&gt;
&lt;li&gt;Still all in open source!! :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven’t checked Novu yet, feel free to go to our Github page&lt;br&gt;
&lt;a href="https://github.com/novuhq/novu"&gt;https://github.com/novuhq/novu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy if you can write to me about what you lack in Novu so I can add it to our ideas list.&lt;br&gt;
Thank you. We couldn’t do it without you!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>Why we have built our main website in Gatsby + Strapi instead of WordPress.</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Sun, 08 May 2022 08:46:36 +0000</pubDate>
      <link>https://forem.com/scopsy/why-we-have-built-our-main-website-in-gatsby-strapi-instead-of-wordpress-4je7</link>
      <guid>https://forem.com/scopsy/why-we-have-built-our-main-website-in-gatsby-strapi-instead-of-wordpress-4je7</guid>
      <description>&lt;p&gt;Today WordPress is one of the most reliable CRMs in the world.&lt;br&gt;
I dare to say that this is one of the things that keeps PHP alive.&lt;br&gt;
And for a good reason, with website builders such as Elementor and Divi, Product Marketer jobs become accessible in a drag and drop environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  So why Gatsby?
&lt;/h3&gt;

&lt;p&gt;We can say that it's mainly for SSG and speed, but that's not the case.&lt;br&gt;
You can have amazing pre-render plugins to achieve almost the same results.&lt;/p&gt;

&lt;p&gt;We are building the 1st open-source notifications infrastructure at &lt;a href="https://github.com/novuhq/novu"&gt;https://github.com/novuhq/novu&lt;/a&gt; .&lt;br&gt;
Our product is built by the community, and there is no really a product without our community support.&lt;br&gt;
It means it should be fully available for the community to fork, contribute and use.&lt;/p&gt;

&lt;p&gt;This is why at Novu, we build everything public, you can find our website and backend source here:&lt;br&gt;
&lt;a href="https://github.com/novuhq/website"&gt;https://github.com/novuhq/website&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/novuhq/cms"&gt;https://github.com/novuhq/cms&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But digging deeper, you can find some other important notes, for example: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WordPress suffers from migrations. You won't find websites with both stage and production environments easily implemented.&lt;/li&gt;
&lt;li&gt;Our main application UI is built with React. So it's a lot easier for contributors to dive into the codebase without learning a new framework or language.&lt;/li&gt;
&lt;li&gt;CI/CD is a lot easier, just a few clicks away with Gatsby.&lt;/li&gt;
&lt;li&gt;We can run asynchronous code without using a hacky ubuntu cron jobs.&lt;/li&gt;
&lt;li&gt;We can use our Novu libraries directly with our website.&lt;/li&gt;
&lt;li&gt;We can query our database data easily with GraphQL. For example, have you tried to query wp_posts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you think we have made the right choice?&lt;br&gt;
Should we have gone with WordPress anyway?&lt;br&gt;
Should we have gone with Next.js or Remix?&lt;br&gt;
Let me know what you think.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding dark/light mode specific images to your GitHub readme page</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Thu, 28 Apr 2022 15:07:47 +0000</pubDate>
      <link>https://forem.com/scopsy/adding-darklight-mode-specific-images-to-your-github-readme-page-3cdj</link>
      <guid>https://forem.com/scopsy/adding-darklight-mode-specific-images-to-your-github-readme-page-3cdj</guid>
      <description>&lt;p&gt;Recently we finished designing a new logo for our open-source project &lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;Novu&lt;/a&gt; and discovered in the GitHub docs that you can specify an image for light and dark modes separately using the: &lt;code&gt;#gh-dark-mode-only&lt;/code&gt; on the .md src source suffix.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Logo Dark&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://image-link.png#gh-dark-mode-only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Logo Light&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://image-link.png#gh-light-mode-only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only a single image will be shown depending on the user theme preference. Let's see it in action:&lt;/p&gt;

&lt;h3&gt;
  
  
  Light Mode
&lt;/h3&gt;

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

&lt;h3&gt;
  
  
  Dark Mode
&lt;/h3&gt;

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

&lt;h2&gt;
  
  
  Centering the image
&lt;/h2&gt;

&lt;p&gt;It's common that you want to center a smaller image to the center of the screen. Luckily we can use the &lt;code&gt;align="center"&lt;/code&gt; property on the supported &lt;code&gt;div&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  !&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Logo Dark&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://user-images.githubusercontent.com/8872447/165779319-34962ccc-3149-466c-b1da-97fd93254520.png#gh-dark-mode-only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  !&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Logo Light&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://user-images.githubusercontent.com/8872447/165779274-22a190da-3284-487e-bd1e-14983df12cbb.png#gh-light-mode-only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The new lines after the starting and before closing of the div are important, otherwise the image won't be rendered.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think the new theme matched logo looks great and it's another touch of detail that makes your GitHub personal or open-source project readme standout.&lt;/p&gt;

&lt;p&gt;Post your results in the comments!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>tutorial</category>
      <category>html</category>
      <category>github</category>
    </item>
    <item>
      <title>How we reduced our nodejs monorepo build time by 70%</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Mon, 10 Jan 2022 16:13:26 +0000</pubDate>
      <link>https://forem.com/novu/how-we-reduced-our-nodejs-monorepo-build-time-by-70-3oma</link>
      <guid>https://forem.com/novu/how-we-reduced-our-nodejs-monorepo-build-time-by-70-3oma</guid>
      <description>&lt;p&gt;At &lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;Novu&lt;/a&gt;, we use a monorepo to manage our 24 libraries and apps. There are many debates over whether you should use a monorepo or a poly-repo. For us, visibility, code sharing, standardization, easier refactoring, and a few other reasons were the critical factors for choosing this approach for our open-source notification infrastructure project.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR;
&lt;/h2&gt;

&lt;p&gt;We migrated from &lt;a href="https://classic.yarnpkg.com/lang/en/docs/workspaces/" rel="noopener noreferrer"&gt;yarn workspaces&lt;/a&gt; &amp;amp; &lt;a href="https://github.com/lerna/lerna" rel="noopener noreferrer"&gt;lerna&lt;/a&gt; to &lt;a href="https://pnpm.io/" rel="noopener noreferrer"&gt;PNPM&lt;/a&gt; and &lt;a href="https://nx.dev" rel="noopener noreferrer"&gt;nx.dev&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The bigger, the slower
&lt;/h2&gt;

&lt;p&gt;With all the advantages, there are a few drawbacks to using monorepos. We noticed a particular drawback when scaling the number of packages and amount of code in each one: The &lt;strong&gt;time&lt;/strong&gt; it takes to bootstrap the project and then build any packages within. So a typical GitHub action for a service would run anywhere between 11 to 30 minutes. And that's for each time a PR was created or a code was pushed to remote. &lt;/p&gt;

&lt;p&gt;More than that, installing a package locally with &lt;code&gt;yarn install&lt;/code&gt; could take around 5 minutes to install and build all the dependencies.&lt;/p&gt;

&lt;p&gt;This amount of time spent bootstrapping and building reduced the developer experience and wasted collectively so much talented people's time. Being an open-source project with a growing number of contributors, this was unacceptable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging the slowest tasks
&lt;/h2&gt;

&lt;p&gt;Inspecting a typical 12 minutes GitHub action, it was clear that two specific steps took almost 70-80% of the overall time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;yarn install&lt;/strong&gt; - takes 5-6 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;yarn build:{package}&lt;/strong&gt; - could take from 3-6 minutes to build the selected package and its dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migrating from yarn workspaces to PNPM
&lt;/h2&gt;

&lt;p&gt;PNPM is a fast, disk space-efficient package manager(as stated on their website), and from some of the &lt;a href="https://pnpm.io/benchmarks" rel="noopener noreferrer"&gt;benchmarks&lt;/a&gt;, there was a massive improvement in install time against &lt;code&gt;yarn workspaces&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Moving from &lt;code&gt;yarn install&lt;/code&gt; that took around 6 minutes, the migration to pnpm was effortless: Just adding a &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; to the project's root and running &lt;code&gt;pnpm install&lt;/code&gt;, that's all. The symlinks and dependencies for each package we're efficiently installed, in... wait for it... &lt;strong&gt;just 1.5 minutes&lt;/strong&gt;! And that's without any cache at all! After PNPM caches the majority of the dependencies, it takes &lt;strong&gt;less than 40 seconds&lt;/strong&gt; to build and install the dependencies from the cached store.&lt;/p&gt;

&lt;p&gt;Reducing ~4 minutes from the bootstrap time for every CI run and locally for first-time contributors is a HUGE win. But wait, we can do even better.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Lerna to NX.dev
&lt;/h2&gt;

&lt;p&gt;After seeing the &lt;a href="https://dev.toTurborepo%20Demo%20and%20Walkthrough%20(High-Performance%20Monorepos)"&gt;Turborepo demo&lt;/a&gt; by vercel, I was intrigued by their distributed caching mechanism. With such a mechanism, we can reuse the already built packages by other maintainers and download the &lt;code&gt;dist&lt;/code&gt; assets instead of rebuilding them each time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;turborepo&lt;/strong&gt; vs &lt;strong&gt;nx.dev&lt;/strong&gt;?&lt;br&gt;
After brief research, we decided to go with nx.dev for multiple reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maturity&lt;/strong&gt; - nx was in the market for a while now, and they have a pretty big community around them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; - Seeing some of the &lt;a href="https://github.com/vsavkin/large-monorepo" rel="noopener noreferrer"&gt;benchmarks&lt;/a&gt; nx looks like a faster build system overall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our community member &lt;a href="https://github.com/nishit-g" rel="noopener noreferrer"&gt;nishit-g&lt;/a&gt; took over the open GitHub &lt;a href="https://github.com/novuhq/novu/issues/164" rel="noopener noreferrer"&gt;issue&lt;/a&gt; and quickly after we had a PR open, the results astonished us: &lt;strong&gt;30 seconds&lt;/strong&gt; the building step! (Instead of the previous 3-6 minutes building a specific set of packages).&lt;/p&gt;

&lt;p&gt;After implementing the nx.cloud for distributed caching, the entire 24 packages take less than &lt;strong&gt;5 seconds&lt;/strong&gt; when fully cached building. But even without being fully cached due to the intelligent parallelism nx performs and builds our target package in less than &lt;strong&gt;30 seconds&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Reducing our build times from 12+ minutes to around 3 minutes significantly impacts the developer experience of our maintainers. It also reduces the feedback loop from creating a PR to running our test suite to merging the feature.&lt;/p&gt;

&lt;p&gt;HUGE Kudos to &lt;a href="https://github.com/nishit-g" rel="noopener noreferrer"&gt;nishit-g&lt;/a&gt; for migrating us from Lerna to NX. Check him out on his &lt;a href="https://twitter.com/sh1nXan" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; as well!&lt;/p&gt;




&lt;p&gt;You can check the final configuration on our &lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>You can now add projects to personal lists on GitHub</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Tue, 16 Nov 2021 07:24:08 +0000</pubDate>
      <link>https://forem.com/scopsy/you-can-now-add-projects-to-personal-lists-on-github-4cao</link>
      <guid>https://forem.com/scopsy/you-can-now-add-projects-to-personal-lists-on-github-4cao</guid>
      <description>&lt;p&gt;Wondered on the GitHub IOS mobile app to check on some of my projects and stumbled upon the ability to add projects to lists. You can choose one of the predefined lists: "My stack", "Inspiration" and "Check Later". After selecting one you can also create custom lists of your choice. &lt;/p&gt;

&lt;p&gt;This is similar to other products like Pinterest, Behance or instagram that allow you to bookmark interesting projects and organize them into lists.&lt;/p&gt;

&lt;p&gt;Not sure yet how the lists will be represented later on, but a good guess will be that they will be listed on your profile page and you can mark some lists as private. Even following some peoples lists could be a great feature as-well :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds7myhunnukgxrrzjvpd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds7myhunnukgxrrzjvpd.jpeg" alt="New feature screenshot from the app"&gt;&lt;/a&gt;&lt;br&gt;
My first list entry was &lt;a href="https://github.com/notifirehq/notifire/" rel="noopener noreferrer"&gt;Notifire&lt;/a&gt; because that's where i've seen it first 😅 &lt;/p&gt;

&lt;p&gt;What projects are you going to add first and to what lists?&lt;/p&gt;

</description>
      <category>news</category>
      <category>opensource</category>
      <category>github</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How we got 2,000 stars in 4 days from a dev.to post</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Thu, 04 Nov 2021 09:59:51 +0000</pubDate>
      <link>https://forem.com/scopsy/how-we-got-2000-stars-in-4-days-from-a-devto-post-hlb</link>
      <guid>https://forem.com/scopsy/how-we-got-2000-stars-in-4-days-from-a-devto-post-hlb</guid>
      <description>&lt;p&gt;After years of struggling when building a notification infrastructure for different projects I was involved with. My partner and I finally decided to open-source most of the work and bring it back to the community instead of building it all over again closed-source.&lt;/p&gt;

&lt;p&gt;I've not even imagined the amount of traction the repository got in the last couple of days. How did happen you ask?&lt;/p&gt;

&lt;p&gt;When first releasing the library we only introduced a node.js library to unify all the notification channels into a single API. Send emails, SMS, and other mediums with the same code. Need to change SES to SendGrid? No problem. Just a single line of code.&lt;/p&gt;

&lt;p&gt;This got some traction, but nothing impressive so far.&lt;/p&gt;

&lt;p&gt;Next comes, building and restructuring our major infrastructure blocks in preparation for a big open-source release. With a bigger picture including An Embeddable Notification Center widget, monitoring for delivered notifications and channels, an admin panel to manage notifications channels and content, and other cool features, basically, everything you need for a Notifications Infrastructure.&lt;/p&gt;

&lt;p&gt;Before jumping to code, I decided to compose a quick blog post outlining the proposed features to the community and to hear their thoughts about this. At this point, I was not even sure somebody else had this issue before.&lt;/p&gt;

&lt;p&gt;One day after publishing to dev.to we've noticed thousands of people visiting the post from the dev.to analytics dashboard. Further investigation showed that a lot of people came from Google. Turned out that we have been selected for the Google Discover timeline 🤯&lt;/p&gt;

&lt;p&gt;The next day GitHub trending picked the project and it's just exploded from there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We've been trending on GitHub for 4 consecutive days 🤯&lt;/li&gt;
&lt;li&gt;More than 50 people joined our discord&lt;/li&gt;
&lt;li&gt;10 new amazing contributors created PR's and contributed back&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2,100&lt;/strong&gt; Total stars as of posting this post&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;We are working hard on releasing the next huge release of notifire to the community with all the amazing features we discussed in the post as a Docker-based environment for easy implementation.&lt;/p&gt;

&lt;p&gt;If you're interested in any of this check us out at: &lt;a href="https://github.com/notifirehq/notifire"&gt;https://github.com/notifirehq/notifire&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The original dev.to post: &lt;a href="https://dev.to/scopsy/building-the-first-open-source-notification-infrastructure-5h9k"&gt;https://dev.to/scopsy/building-the-first-open-source-notification-infrastructure-5h9k&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to say thank you to all the amazing contributors I had the luck to meet in the last past days check them out!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/deepak-sreekumar"&gt;@deepak-sreekumar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/artfuldev"&gt;@artfuldev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/diganta413"&gt;@diganta413&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/davidsoderberg"&gt;@davidsoderberg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/SachinHatikankar100"&gt;@SachinHatikankar100&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/davidsoderberg"&gt;@davidsoderberg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tonytangdev"&gt;@tonytangdev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/akhil-gautam"&gt;@akhil-gautam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/painotpi"&gt;@painotpi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ulentini"&gt;@ulentini&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Wyfy0107"&gt;@Wyfy0107&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/LuigiZaccagnini"&gt;@LuigiZaccagnini&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>news</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Building the first open-source notification infrastructure</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Thu, 28 Oct 2021 12:34:22 +0000</pubDate>
      <link>https://forem.com/scopsy/building-the-first-open-source-notification-infrastructure-5h9k</link>
      <guid>https://forem.com/scopsy/building-the-first-open-source-notification-infrastructure-5h9k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hi Community!&lt;/strong&gt;&lt;br&gt;
Looking forward to hear your thoughts about this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;Novu&lt;/a&gt; was started out of pain me and &lt;a class="mentioned-user" href="https://dev.to/combarnea"&gt;@combarnea&lt;/a&gt; felt when developing products that required product based notifications. We've built the infrastructure so many times that we decided to take it out to the world. That's when Novu was born. We took the multi-channel notifications and provided a unified set of API's to generate notification content and simplify delivery across multiple channels. &lt;/p&gt;

&lt;h3&gt;
  
  
  It's more than just sending an email or push
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F8872447%2F139248224-f35b2dc2-daa9-4976-ae58-b120d3561c49.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F8872447%2F139248224-f35b2dc2-daa9-4976-ae58-b120d3561c49.jpg" alt="C6ROe0mU0AEmpzz"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Part of slacks notification system)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From our past experience, we know that a wholesome notification infrastructure requires more than a unified API. We believe that building a solid notification infrastructure is something that is accessible not only to fortune 500 companies but to every developer out there. &lt;/p&gt;

&lt;h2&gt;
  
  
  Notificaiton infrastructure foundations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Smart Notification Engine
&lt;/h3&gt;

&lt;p&gt;Using a stateful API instead of local config files can provide further functionality like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run time &lt;strong&gt;changes&lt;/strong&gt; without redeploying your code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digest&lt;/strong&gt; mechanism that allows to aggregate multiple events/messages to a single email or in-app notification for the customer. For example, a user received an email a minute ago, we don't want to send him the next one immediately and wait if further messages are planning to arrive. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User preferences&lt;/strong&gt; - With the ever-growing number of channels, an end-user can get notifications can create a lot of noise. Notification preferences are an expected thing from most users this day. A stateful API can manage all the complexities of it out of the box. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priority management&lt;/strong&gt; - Not all notifications created equally, while password reset email must be delivered in real-time. Repeatable and frequent notifications can be throttled or scheduled to a later time.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Timezone awareness&lt;/strong&gt; - Send a specific set of notifications only in the user wake hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; and &lt;strong&gt;webhook&lt;/strong&gt; integrations to all the delivery providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze&lt;/strong&gt; sending patterns and &lt;strong&gt;debug deliverability&lt;/strong&gt; across multiple channels&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  In-app notification center
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An embeddable widget that is easy to integrate and customize.&lt;/li&gt;
&lt;li&gt;Real-time update using a socket.&lt;/li&gt;
&lt;li&gt;User preference widget to control the channels and motivation groups he would love to receive.&lt;/li&gt;
&lt;li&gt;The ability of the user to Snooze, mute and hide notifications easily.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would love that everyone can have the best notification infrastructure possible without investing thousands of hours on it again and again. By the community. For the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;We are working on porting parts of the closed source platform we developed over the years to OSS. This includes an out-of-the-box API for managing notifications, an embeddable notifications widget, activity monitoring and more. &lt;/p&gt;

&lt;p&gt;Star or follow us on twitter to get notified when we release the first  API version, embeddable widget and admin panel to the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F8872447%2F139250840-23b0141f-6d0c-479f-9706-8ca46a78f6d4.png" class="article-body-image-wrapper"&gt;&lt;img alt="Screen Shot 2021-10-28 at 14 53 57" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F8872447%2F139250840-23b0141f-6d0c-479f-9706-8ca46a78f6d4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What are your thoughts about the need for such a system? Have you built something similar with your team? What would expect to see there?&lt;/p&gt;

&lt;p&gt;Feel free to comment here or at our Github page &lt;a href="https://github.com/novuhq/novu/" rel="noopener noreferrer"&gt;https://github.com/novuhq/novu/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Open-source multi-channel notification management library</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Tue, 05 Oct 2021 18:50:59 +0000</pubDate>
      <link>https://forem.com/scopsy/open-source-multi-channel-notification-management-library-40nc</link>
      <guid>https://forem.com/scopsy/open-source-multi-channel-notification-management-library-40nc</guid>
      <description>&lt;p&gt;After years of writing a multichannel notification management systems from scratch for every project i've been involved with. Me and my partner in crime Tomer Barnea decided to solve this thing once and for all and created the opensource library called Notifire.&lt;/p&gt;

&lt;p&gt;Are main goal is to abstract the heavy lifting of managing notifications in code, provide a single API to work with all communication providers (Email, SMS, InApp, Push). &lt;/p&gt;

&lt;p&gt;And later help with: Timezone awareness, priority, channel selection, templating, subscription management, in app widgets and etc...&lt;/p&gt;

&lt;p&gt;Would to hear your thoughts about the API and library. Any help will be appreciated.&lt;/p&gt;

&lt;p&gt;Our GitHub Page: &lt;a href="https://github.com/notifirehq/notifire/"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>news</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Excited to release my first side project on ProductHunt</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Wed, 30 Oct 2019 10:56:46 +0000</pubDate>
      <link>https://forem.com/scopsy/excited-to-release-my-first-side-project-on-producthunt-njo</link>
      <guid>https://forem.com/scopsy/excited-to-release-my-first-side-project-on-producthunt-njo</guid>
      <description>&lt;p&gt;Hi guys,&lt;/p&gt;

&lt;p&gt;I've created releasly with a couple of friends in the office. This is a free tool to get notifications on new open-source releases and awesome-list links. &lt;/p&gt;

&lt;p&gt;Come see us on producthunt and let us know what you think&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/releasly"&gt;https://www.producthunt.com/posts/releasly&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Webpack released v5.0 beta</title>
      <dc:creator>Dima Grossman</dc:creator>
      <pubDate>Fri, 11 Oct 2019 14:21:42 +0000</pubDate>
      <link>https://forem.com/scopsy/webpack-released-v5-0-beta-333o</link>
      <guid>https://forem.com/scopsy/webpack-released-v5-0-beta-333o</guid>
      <description>&lt;p&gt;Webpack just announced v5.0 Beta. Check out the full &lt;a href="https://app.releasly.co/releases/webpack/webpack/5_0_0-beta_0?utm_campaign=devto_webpack_beta"&gt;release note&lt;/a&gt;&lt;/p&gt;

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