<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mathias Remshardt</title>
    <description>The latest articles on DEV Community by Mathias Remshardt (@remshams).</description>
    <link>https://dev.to/remshams</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%2F454589%2F8ef04500-1a36-45ce-817d-fa20094c11b3.jpeg</url>
      <title>DEV Community: Mathias Remshardt</title>
      <link>https://dev.to/remshams</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/remshams"/>
    <language>en</language>
    <item>
      <title>Let's build - Autohide tooltip in Angular</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 05 Aug 2023 11:07:29 +0000</pubDate>
      <link>https://dev.to/remshams/lets-build-autohide-tooltip-in-angular-3nep</link>
      <guid>https://dev.to/remshams/lets-build-autohide-tooltip-in-angular-3nep</guid>
      <description>&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;We want to show/hide a tooltip for some text depending on whether there is enough room for the text.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;A directive that checks the width of the text and compares it against the width of the container. If the latter is smaller than the former the tooltip will be shown.&lt;br&gt;
To focus on the directive implementation we are going to use the tooltips provided by angular material.&lt;/p&gt;
&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;
&lt;h2&gt;
  
  
  TooltipIfCollapsedDirective
&lt;/h2&gt;

&lt;p&gt;The directive reads the width of the component it is applied to to check if the tooltip needs to enabled or disabled.&lt;br&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HostListener&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;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatTooltip&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;@angular/material/tooltip&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="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[appTooltipIfCollapsed]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TooltipIfCollapsedDirective&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;tooltip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MatTooltip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngAfterViewInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The requestAnimationFrame gives the browser some time to calculate the scrollWidth which is required&lt;/span&gt;
    &lt;span class="c1"&gt;// to determine if the tooltip should be hidden or not.&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateTooltip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;window:resize&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="nf"&gt;onResize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateTooltip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;updateTooltip&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollWidth&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tooltip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tooltip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&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;It compares the &lt;code&gt;width&lt;/code&gt; of the component against the &lt;code&gt;scrollWidth&lt;/code&gt;. If the latter is larger than the former it means that the text does not completely fit into the container.&lt;br&gt;
The first call to &lt;code&gt;updateTooltip&lt;/code&gt; is in &lt;code&gt;ngAfterViewInit&lt;/code&gt; so that the container &lt;code&gt;width&lt;/code&gt; is available. The same call is made whenever the browser window is changed.&lt;/p&gt;

&lt;p&gt;As mentioned in the comment, &lt;code&gt;requestAnimationFrame&lt;/code&gt; gives the browser some time to recalculate the &lt;code&gt;scrollWidth&lt;/code&gt;. Without it I had some instances where the &lt;code&gt;scrollWidth&lt;/code&gt; was not up to date leading to the tooltip being shown/hidden when it should not.&lt;/p&gt;
&lt;h1&gt;
  
  
  Example
&lt;/h1&gt;

&lt;p&gt;The directive is added to the node which also defines the tooltip (&lt;code&gt;matToolbar&lt;/code&gt; in the case of Angular Material).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;[matTooltip]=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;appTooltipIfCollapsed&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ text }}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;container-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;white-space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ellipsis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@container&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&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;For the sake of the example the &lt;code&gt;width&lt;/code&gt; of the text container is restricted to &lt;code&gt;100px&lt;/code&gt;  when the containing component (&lt;code&gt;AppComponent&lt;/code&gt;) &lt;code&gt;width&lt;/code&gt; drops below &lt;code&gt;600px&lt;/code&gt;.&lt;br&gt;
Resizing the browser window now shows or hides the &lt;code&gt;tooltip&lt;/code&gt; when the &lt;code&gt;width&lt;/code&gt; is larger or smaller than &lt;code&gt;600px&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The code can be found &lt;a href="https://github.com/remshams/angular-hide-tooltip" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Let's build - Feature flags in Angular</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 24 Jun 2023 15:03:01 +0000</pubDate>
      <link>https://dev.to/remshams/lets-build-feature-flags-in-angular-1ee1</link>
      <guid>https://dev.to/remshams/lets-build-feature-flags-in-angular-1ee1</guid>
      <description>&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;In one of the projects I'm working on we wanted to show/hide certain elements/features at runtime.&lt;br&gt;
The requirements were pretty simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manually enable and disable the toggle in a configuration file &lt;/li&gt;
&lt;li&gt;It should be possible to change the value at runtime&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;A well known solution for this are Feature Flags or Feature Toggles. A lot has already been written about this topic e.g. you can find some details &lt;a href="https://martinfowler.com/articles/feature-toggles.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
There are quite some ready made solutions out there. However most of the available solutions are SaaS offerings and these are not always an option (for technical or financial reasons).&lt;br&gt;
So, as we don't have many (complicated) requirements, it shouldn't be too hard to build our own, local version.&lt;/p&gt;
&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;The following diagram gives an overview of the main elements&lt;br&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%2Fa788zeit2vo1oasfyr8p.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%2Fa788zeit2vo1oasfyr8p.png" alt="Overview"&gt;&lt;/a&gt; &lt;br&gt;
As mentioned previously, we are aiming for a rather simple solution so there is not too much going on.&lt;/p&gt;
&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Store
&lt;/h2&gt;

&lt;p&gt;All of the configuration is stored in the &lt;code&gt;feature.json&lt;/code&gt; file. It has a pretty simple structure with the key being the name of the feature and the value a boolean which indicates if the feature is enabled or not.&lt;br&gt;
This is enough for basic use cases. However if there are a lot flags it could make sense to add bit more structure here e.g. nesting the different flags under a key which represents the pages or components they are associated with.&lt;/p&gt;

&lt;p&gt;It is also possible to define different &lt;code&gt;feature.json&lt;/code&gt; files as a sort of template for a specific configuration e.g. if the application is deployed for multiple customers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newFeature"&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="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;h2&gt;
  
  
  FeatureService
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bootstrapping
&lt;/h3&gt;

&lt;p&gt;The root injected service loads the &lt;code&gt;feature.json&lt;/code&gt; file and stores it in memory.&lt;br&gt;
The file could be validated and typed after loading (e.g. using something like &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;zod&lt;/a&gt;).&lt;br&gt;
I personally did not see any advantage in doing that as the file is only used in the &lt;code&gt;isFeatureEnabled&lt;/code&gt; method which checks if the provided key is truthy. Having it typed would not give any benefit and has the drawback that the validation and type definition has to be updated whenever a new property is added to the &lt;code&gt;feature.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ReplaySubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featuresFlags&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assets/feature.json&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featuresFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;For the sake of the example the loading mechanismn is kept pretty simple (e.g. it does not include any error handling, it hard codes the path...).&lt;/p&gt;

&lt;p&gt;The init method is called by an &lt;code&gt;APP_INITIALIZER&lt;/code&gt; at application start up.&lt;br&gt;
It returns an &lt;code&gt;Observable&lt;/code&gt; to make sure the first render does not happen before the &lt;code&gt;feature.json&lt;/code&gt; file has been loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initFeatureServiceFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&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="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;BrowserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;HttpClientModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;WithoutDirectiveComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;WithDirectiveComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&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;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_INITIALIZER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;initFeatureServiceFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;FeatureService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;multi&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="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  IsFeatureEnabled
&lt;/h3&gt;

&lt;p&gt;The aformentioned &lt;code&gt;isFeatureEnabled&lt;/code&gt; method returns if the feature is enabled or not. &lt;br&gt;
The implementation is pretty straight forward at the moment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nf"&gt;isFeatureEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featuresFlags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&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;Having a dedicated function hides the storage mechanism and allows for changing to a different approach in the future with minor impact on the using components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;For demonstration purposes two components have been added to the project&lt;/p&gt;

&lt;h3&gt;
  
  
  WithoutDirectiveComponent
&lt;/h3&gt;

&lt;p&gt;As the name implies the component does the feature check for itself by directly calling the &lt;code&gt;isFeatureEnabled&lt;/code&gt; with the feature name.&lt;br&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WithoutDirectiveComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;isNewFeatureEnabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isNewFeatureEnabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFeatureEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;newFeature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isNewFeatureEnabled; else featureDisabled"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  WithoutDirectiveComponent: Feauture enabled
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#featureDisabled&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;WithoutDirectiveComponent: Feature disabled&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  FeatureDirective
&lt;/h3&gt;

&lt;p&gt;Repeating the "check and render" is a bit tedious and identical for every using component. Therefore a directive has been added to the project that takes care of this part. It's working similar to &lt;code&gt;ngIf&lt;/code&gt;  but takes the feature name instead of a &lt;code&gt;boolean&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The directive passes the provided feature name to the &lt;code&gt;FeatureService&lt;/code&gt; and leverages the &lt;code&gt;ngIf&lt;/code&gt; directive for hiding or showing the feature flagged element.&lt;br&gt;
Similar to &lt;code&gt;ngIf&lt;/code&gt; it also allows for displaying an alternative &lt;code&gt;template&lt;/code&gt; should the feature be disabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[appIfFeatureEnabled]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hostDirectives&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;directive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgIf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ngIfElse: appIfFeatureEnabledElse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IfFeatureEnabledDirective&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;appIfFeatureEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appIfFeatureEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngIf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ngIf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFeatureEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;appIfFeatureEnabled&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;ngIf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgIf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;featureService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WithDirectiveComponent
&lt;/h3&gt;

&lt;p&gt;The component just needs to pass to feature name to the &lt;code&gt;FeatureDirective&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;*appIfFeatureEnabled=&lt;/span&gt;&lt;span class="s"&gt;"'newFeature'; else featureDisabled"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  WithDirectiveComponent: Feature enabled
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#featureDisabled&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;WithDirectiveComponent: Feature disabled&lt;span class="nt"&gt;&amp;lt;/ng-template&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This is it, a simple solution for feature flagging templates elements in Angular.&lt;br&gt;
As mentioned in the beginning, the implementation only covers simple hide/show use cases which can often be enough, especially in the beginning.&lt;br&gt;
In our project, it has served us as well so far.&lt;br&gt;
It was easy and fast to build, it's easy to maintain (e.g. adding new feature flags) and avoids adding another dependency to a third party library (or company) and, most importantly, it fulfils all of our current requirements.&lt;/p&gt;

&lt;p&gt;The code can be found &lt;a href="https://github.com/remshams/angular-feature-flags" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescipt</category>
      <category>angular</category>
    </item>
    <item>
      <title>Derive union of string literal types with lookup types in Typescript</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 04 Sep 2021 07:56:45 +0000</pubDate>
      <link>https://dev.to/remshams/derive-union-of-string-literal-types-with-lookup-types-in-typescript-1kkf</link>
      <guid>https://dev.to/remshams/derive-union-of-string-literal-types-with-lookup-types-in-typescript-1kkf</guid>
      <description>&lt;p&gt;Recently I started playing with unions of string literals as an alternative to enums. I did not experience any issues while using enums. I just prefer the string literals as these, in contrast to enums, do not lead additional code generated during compilation.&lt;/p&gt;

&lt;p&gt;One thing that has bothered me so far is that I could not find an easy way to store all strings of a string literal union in an array. This can be useful if you want to e.g. randomly select one of the string literals in the union as part of creating mock/fixture data.&lt;br&gt;&lt;br&gt;
Of course you can define both the unions of string literals and an array with the same strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;podcast&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;postTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;podcast&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;This duplication is error prone in case a new option needs to be added, removed and the like. So I was searching for a means to either derive the array from the type or the type from the array.&lt;br&gt;&lt;br&gt;
With lookup types this is exactly possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;podcast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;postTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fhao3bf2e780ktlpublbv.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%2Fhao3bf2e780ktlpublbv.png" alt="Screenshot of derived post types in VSCode" width="410" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First &lt;code&gt;typeof&lt;/code&gt; in combination with &lt;code&gt;as const&lt;/code&gt; is used to infer the type of the defined array. &lt;code&gt;as const&lt;/code&gt; is important here as Typescript otherwise defines the type as &lt;code&gt;Array&amp;lt;string&amp;gt;&lt;/code&gt; instead of an array of string literals.&lt;br&gt;&lt;br&gt;
Using &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types" rel="noopener noreferrer"&gt;indexed access types/lookup types&lt;/a&gt; gives the union of string literals. This is somehow equivalent to using an index in an "normal" Javascript/Typescript to get a specific element like &lt;code&gt;list[0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lookup types can be used for more sophisticated use case e.g. like deriving all properties in an object the values of which are e.g. a &lt;code&gt;string&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;views&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostStringKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fn2dz9vjzb7s672xl13km.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%2Fn2dz9vjzb7s672xl13km.png" alt="Screenshot of extracted string property names in VSCode" width="436" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's quickly break this down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;P keyof Post&lt;/code&gt; gives all keys of &lt;code&gt;Post&lt;/code&gt; (&lt;code&gt;title&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Post[P] extends string ? P : never&lt;/code&gt; checks if the value of property &lt;code&gt;P&lt;/code&gt; in &lt;code&gt;Post&lt;/code&gt; is of type &lt;code&gt;string&lt;/code&gt;. If true the property name is set as value otherwise the property is not included in the newly created type.&lt;/li&gt;
&lt;li&gt;With the help of lookup types the union of property names/string literals is derived using &lt;code&gt;keyof Post&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;The set of keys in &lt;code&gt;Post&lt;/code&gt; is a superset of the keys of the derived type and can therefor be used as an index&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This can be made generic like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostStringKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostNumberKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare to the previous example &lt;code&gt;T == Post&lt;/code&gt; and &lt;code&gt;K == string&lt;/code&gt;. This provides the additional possibility to include properties with different value types like &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;Author&lt;/code&gt; using unions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostStringAndAuthorKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&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%2Fmj65bvm53oboz4y515hg.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%2Fmj65bvm53oboz4y515hg.png" alt="Screenshot of extracted property names with type number and author" width="474" height="39"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code snippets can be found &lt;a href="https://github.com/remshams/ts-literal-and-lookup-types" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's it and as always, thanks for reading.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Racing condition in RxJs event order (with multiple subscriptions)</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Tue, 31 Aug 2021 17:03:08 +0000</pubDate>
      <link>https://dev.to/remshams/racing-condition-in-rxjs-event-order-with-multiple-subscriptions-2m37</link>
      <guid>https://dev.to/remshams/racing-condition-in-rxjs-event-order-with-multiple-subscriptions-2m37</guid>
      <description>&lt;p&gt;This is another short article about a "strange issue while working on a project" which took me a while to resolve.&lt;br&gt;
The problem was that the order of events got mixed up in a observable chain, so the first event arrived after the second one (and no there were no http calls or other &lt;code&gt;async&lt;/code&gt; operations involved).&lt;br&gt;
As it is hard to explain just in words I created a simplified &lt;a href="https://github.com/remshams/rxjs-event-order" rel="noopener noreferrer"&gt;example application&lt;/a&gt; to better show the issue (and help me figure out the root cause).&lt;/p&gt;

&lt;h1&gt;
  
  
  Example application
&lt;/h1&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%2F8upk4ow0041qkr14khjw.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%2F8upk4ow0041qkr14khjw.png" alt="Overview of example application components" width="800" height="820"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;The main components and dependencies are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TasksService&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Stores tasks (a task is a string to keep it simple) in a &lt;code&gt;ReplaySubject&lt;/code&gt; which is accessible to other components by the &lt;code&gt;tasks$&lt;/code&gt; property.&lt;/li&gt;
&lt;li&gt;Contains a &lt;code&gt;setTasks&lt;/code&gt; method as a means for other components to update the tasks.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;TasksFilterService&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Stores a filter pattern (again a simple string) to match against the stored tasks.&lt;/li&gt;
&lt;li&gt;Subscribes to &lt;code&gt;tasks$&lt;/code&gt;, filters the received tasks and updates &lt;code&gt;tasks$&lt;/code&gt; in &lt;code&gt;TasksService&lt;/code&gt; by calling &lt;code&gt;setTasks$&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;An infinite loop is avoided by using &lt;code&gt;distinctUntilChanged&lt;/code&gt; --&amp;gt; so &lt;code&gt;tasks$&lt;/code&gt; is only updated in case the filter pattern does lead to a change in the current list of tasks&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Component&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Subscribes to &lt;code&gt;tasks$&lt;/code&gt; and &lt;code&gt;tasksFilterPattern$&lt;/code&gt; to derive a &lt;code&gt;areTasksValid$&lt;/code&gt; property. Tasks are considered valid if all of them are matching against the filter pattern. In contrast to what is done in &lt;code&gt;TasksFilterService&lt;/code&gt; it only checks the list of tasks but does not perform any update in &lt;code&gt;TasksService&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Template&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Subscribes to &lt;code&gt;areTasksValid$&lt;/code&gt; and renders the boolean value using the &lt;code&gt;async&lt;/code&gt; pipe.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;When looking at the structure some may spot the circular dependency between &lt;code&gt;TasksService&lt;/code&gt; and &lt;code&gt;TasksFilterService&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;TasksFilterService&lt;/code&gt; filters (based on the set filter pattern) and updates the tasks in &lt;code&gt;TasksService&lt;/code&gt; whenever &lt;code&gt;tasks$&lt;/code&gt; emit. To avoid an infinite loop the &lt;code&gt;TasksFilterService&lt;/code&gt; should only perform the update in case the filtered list is different to the current one. As mentioned above this can be done using &lt;code&gt;distinctUntilChanged&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Component&lt;/code&gt; sets the tasks filter pattern on init and updates the tasks after two seconds using &lt;code&gt;setTimeout&lt;/code&gt;.&lt;br&gt;
As both the &lt;code&gt;Component&lt;/code&gt; as well as the &lt;code&gt;TasksFilterService&lt;/code&gt; subscribe to &lt;code&gt;task$&lt;/code&gt; my initial guess was that there are two routes the application can take when &lt;code&gt;setTimeout&lt;/code&gt; is triggered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tasks are first received by the &lt;code&gt;Component&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;Component&lt;/code&gt; checks if tasks are valid which is then displayed in the &lt;code&gt;Template&lt;/code&gt; (&lt;code&gt;areTasksValid$&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Next &lt;code&gt;TasksFilterService&lt;/code&gt; filters and updates the tasks. The second emit of &lt;code&gt;tasks$&lt;/code&gt; does not lead to another update due to &lt;code&gt;distinctUntilChanged&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Component&lt;/code&gt; receives the filtered tasks which are again displayed in the &lt;code&gt;Template&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Tasks are first received by the &lt;code&gt;TasksFilterService&lt;/code&gt;

&lt;ol&gt;
&lt;li&gt;Same as step 2 in the first option (&lt;code&gt;TasksFilterService&lt;/code&gt; updates the task list)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Component&lt;/code&gt; first receives the unfiltered list of tasks and checks for their validity. Next the filtered tasks are received (set in step 1) and again checked against the current filter pattern.&lt;/li&gt;
&lt;li&gt;As the complete execution is synchronous the change detection runs once and the result from the last task list processed is displayed in &lt;code&gt;Template&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;As it turned out none of these routes are taken. What actually is executed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tasks are received by the &lt;code&gt;FiltersService&lt;/code&gt;, filtered and updated&lt;/li&gt;
&lt;li&gt;Second emit of &lt;code&gt;tasks$&lt;/code&gt; is ignored in &lt;code&gt;FiltersService&lt;/code&gt; (due to not having changed)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Component&lt;/code&gt; first receives &lt;strong&gt;filtered&lt;/strong&gt; tasks list and then the &lt;strong&gt;unfiltered&lt;/strong&gt; one&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Template&lt;/code&gt; renders the final value&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The actual sequence is pretty close to the second guess. The important difference (marked in &lt;strong&gt;bold&lt;/strong&gt;) is that the tasks received by &lt;code&gt;Component&lt;/code&gt; are out of order. As shown in the sequence diagram below, the filtered tasks list comes before the unfiltered one. My assumption was that the order of events is guaranteed, so I expected the &lt;code&gt;Component&lt;/code&gt; to receive the task lists in the order these have been set in &lt;code&gt;TasksService&lt;/code&gt; (the initial list before the filtered one).&lt;br&gt;&lt;br&gt;
This explained the bug I was facing in my project where one of the &lt;code&gt;Components&lt;/code&gt; was rendering outdated/old values.&lt;br&gt;
Basically one cannot assume emissions to be in order in case of multiple subscriptions to the same &lt;code&gt;Observable&lt;/code&gt; where one of them is again updating the source stream (&lt;code&gt;tasks$&lt;/code&gt; in the example). Of course, the problem only occurs in case processing and updating the streams happens within the same &lt;code&gt;tick&lt;/code&gt; of the event loop.&lt;/p&gt;

&lt;p&gt;The sequence diagram below shows what has been described above.&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%2Fraw.githubusercontent.com%2Fremshams%2Frxjs-event-order%2F030ac35e9354e96ab0b776ff64c04fb3a62a070b%2Fimages%2Fexample-application-issue-flow.svg" 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%2Fraw.githubusercontent.com%2Fremshams%2Frxjs-event-order%2F030ac35e9354e96ab0b776ff64c04fb3a62a070b%2Fimages%2Fexample-application-issue-flow.svg" alt="Sequence diagram of example application program flow" width="870" height="732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition there have been log statements added indicating where and when the task list update is processed (triggered by &lt;code&gt;setTimeout&lt;/code&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%2Fnv1q9pxdpsyf9ufpvomd.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%2Fnv1q9pxdpsyf9ufpvomd.png" alt="Console output for example application" width="619" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result rendered in the &lt;code&gt;Template&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt; because the final list received is the unfiltered one and therefor not valid for the applied task filter pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;p&gt;I could come up with two options to guarantee the order of the task list received by &lt;code&gt;Component&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Directly perform the filtering in &lt;code&gt;FiltersService&lt;/code&gt; so that only the already filtered task list is emitted.&lt;/li&gt;
&lt;li&gt;Put the update in &lt;code&gt;TasksFilterService&lt;/code&gt; on next &lt;code&gt;tick&lt;/code&gt; of the event loop. This can be done by using any of the available asynchronous schedulers (like &lt;code&gt;asapScheduler&lt;/code&gt; or &lt;code&gt;requestAnimationFrameScheduler&lt;/code&gt;). That way it is guaranteed that the filtered task list is emitted after the initial one. In contrast to the first solution it does lead to both tasks list being emitted and, depending on which async scheduler is chosen, two change detection cycles.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To me the first solution has the advantage it is easier to understand and straight forward. In contrast the second solution has the benefit of clearly separating the concern of storing tasks and filtering.&lt;br&gt;&lt;br&gt;
In my project I opted for the second solution since there was a lot more going on in the services and migrating everything into one would have lead to a huge class and a (more) severe violation of Separation of Concerns.&lt;/p&gt;

&lt;p&gt;Both versions are implemented in the &lt;a href="https://github.com/remshams/rxjs-event-order" rel="noopener noreferrer"&gt;example application&lt;/a&gt; and can be tested by commenting in the associated component in &lt;code&gt;app.component.html&lt;/code&gt;. &lt;code&gt;app-tasks-scheduled&lt;/code&gt; represents the scheduled implementation and &lt;code&gt;app-tasks-single-stream&lt;/code&gt; the version directly filtering in &lt;code&gt;TasksService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>angular</category>
    </item>
    <item>
      <title>Optional content projection/injection in Angular</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 08 May 2021 11:23:10 +0000</pubDate>
      <link>https://dev.to/remshams/optional-content-projection-injection-in-angular-2jnn</link>
      <guid>https://dev.to/remshams/optional-content-projection-injection-in-angular-2jnn</guid>
      <description>&lt;h1&gt;
  
  
  Optional content projection/injection in Angular
&lt;/h1&gt;

&lt;p&gt;Recently I had the requirement to make part of a component (the header of a custom table) replaceable with custom content. In case nothing is provided the implementation was supposed to render "default" content. A simple property was not sufficient as the injected/projected content could be anything ranging from simple text to a slider/toggle...&lt;br&gt;&lt;br&gt;
The requirements could be summarized as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render custom content in case it is provided&lt;/li&gt;
&lt;li&gt;Render default content otherwise&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was torn between using &lt;code&gt;ng-content&lt;/code&gt; or &lt;code&gt;ng-template&lt;/code&gt; to solve the problem. To make an informed decision I created a POC implementing both options to see if one is superior to the other. In contrast to the requirements, the created &lt;a href="https://github.com/remshams/optional-content-projection" rel="noopener noreferrer"&gt;POC&lt;/a&gt; allows for replacing multiple contents (like a header and a footer) to verify that the solution could be extended in the future (if needs arise). The next sections describe the alternatives I could come up with.&lt;/p&gt;
&lt;h1&gt;
  
  
  ng-content
&lt;/h1&gt;

&lt;p&gt;This is usually the first option as it is simple to implement and use. The custom contents are provided as children using &lt;code&gt;ng-content&lt;/code&gt;. By using a &lt;code&gt;select&lt;/code&gt; attribute multiple contents can be projected as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='header']"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='footer']"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers the first requirement. The second is more difficult to realize using &lt;code&gt;ng-content&lt;/code&gt; alone. The figure out whether to render the custom or default content requires some means to determine if something has been passed as &lt;code&gt;ng-content&lt;/code&gt; or not. I was not able to find any build-in feature to query/get that information from the component or template so a custom solution is required.&lt;br&gt;&lt;br&gt;
One option is to create a directive which is put on the content to be projected (&lt;code&gt;appSlot&lt;/code&gt; in the example below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-render-slot&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;appSlot&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Custom Header&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;appSlot&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Custom Footer&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/app-render-slot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component can search for the directive(s) using a &lt;code&gt;@ContentChildren&lt;/code&gt; query. In case something is found for the placeholder the custom content is used, otherwise it falls back to the default content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-render-slot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RenderSlotComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContentChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SlotDirective&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;slotDirectives&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeSlots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;nativeSlots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;slotNames$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SlotNames&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeSlots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slotNames$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSlotsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeSlots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;isSlotSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slotName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SlotName&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slotNames$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;slotNames&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;slotNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slotName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setSlotsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;slots$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SlotNames&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;slots$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;slots&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;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;slot&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;slot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the example, the "name" of the slot ("header" or "footer") is extracted based on what has been set for the custom "slot" attribute on the projected content. The &lt;code&gt;ElementRef&lt;/code&gt; to look for is marked/identified by the &lt;code&gt;SlotDirective&lt;/code&gt; and extracted with the &lt;code&gt;@ContentChildren&lt;/code&gt; query. The other part of the implementation just maps the list of &lt;code&gt;ElementRef&lt;/code&gt;s to the slot names.&lt;br&gt;&lt;br&gt;
With help of the &lt;code&gt;isSlotSet&lt;/code&gt; method, the template can either render the custom content (in case the slot is found) or fall back to a default content.&lt;/p&gt;

&lt;p&gt;For the sake of the example, the template of the component is kept simple containing only the &lt;code&gt;ng-content&lt;/code&gt; placeholders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt;
  &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='header']"&lt;/span&gt;
  &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isSlotSet('header') | async; else defaultHeader"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt;
  &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='footer']"&lt;/span&gt;
  &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isSlotSet('footer') | async; else defaultFooter"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultHeader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Default Header &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultFooter&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Default Footer &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The alternative described here can be found in the &lt;code&gt;ng-content/render-slot&lt;/code&gt; folder in the example repository. When removing either the "Custom Header" or "Custom Footer" &lt;code&gt;div&lt;/code&gt; in the &lt;code&gt;AppComponent&lt;/code&gt; template for &lt;code&gt;app-render-slot&lt;/code&gt; the default fallback will be rendered.&lt;/p&gt;

&lt;h2&gt;
  
  
  with SlotRenderer
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Heads up: This solution does not work, so please skip ahead in case not of interest.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The approach described above has the disadvantage that each component with optional content projection does have to implement the mechanism to find/determine the rendered content.&lt;br&gt;&lt;br&gt;
My idea was to improve the solution by creating a "helper" component called &lt;code&gt;SlotRendererComponent&lt;/code&gt;, which would be responsible for rendering the content passed by the using component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-slot-renderer&lt;/span&gt; &lt;span class="na"&gt;[defaultSlotContent]=&lt;/span&gt;&lt;span class="s"&gt;"defaultHeader"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='header']"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-slot-renderer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;app-slot-renderer&lt;/span&gt; &lt;span class="na"&gt;[defaultSlotContent]=&lt;/span&gt;&lt;span class="s"&gt;"defaultFooter"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='footer']"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-slot-renderer&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultHeader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Default Header&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultFooter&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Default Footer&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The custom content gets provided using &lt;code&gt;ng-content&lt;/code&gt; and the &lt;code&gt;select&lt;/code&gt; attribute (the latter could be omitted in case there is only a single &lt;code&gt;ng-content&lt;/code&gt; to project). The default content is passed as &lt;code&gt;TemplateRef&lt;/code&gt; using an &lt;code&gt;Input&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SlotRendererComponent&lt;/code&gt; also uses &lt;code&gt;ng-content&lt;/code&gt; to render what has been projected from the using component which would be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isSlotSet$ | async; else defaultSlotContent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The custom content originally passed is therefore projected twice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First to the outer component (&lt;code&gt;RenderSlotSlotRendererComponent&lt;/code&gt; in the example)&lt;/li&gt;
&lt;li&gt;Second to the &lt;code&gt;SlotRendererComponent&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The flattened hierarchy looks something like this (not the real DOM structure):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- From SlotRendererComponent  --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isSlotSet$ | async; else defaultSlotContent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- From RenderSlotSlotRendererComponent  --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"[slot='header']"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Projected custom content   --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;appSlot&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Custom Header&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Same for the footer --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the same mechanism as in the first approach, the custom or default content will be rendered by &lt;code&gt;SlotRendererComponent&lt;/code&gt;.&lt;br&gt;
The reason why this solution is not working is due to &lt;code&gt;@ContentChildren&lt;/code&gt; not being able to query nested &lt;code&gt;ng-content&lt;/code&gt;s. Setting &lt;code&gt;{ descendants: true }&lt;/code&gt; also did not work for me. I found an &lt;a href="https://github.com/angulardart/angular/issues/195" rel="noopener noreferrer"&gt;issue&lt;/a&gt; describing the problem for the &lt;code&gt;AngularDart&lt;/code&gt; repository so maybe it is related (or I am doing something wrong here ;) ).&lt;/p&gt;
&lt;h1&gt;
  
  
  ng-template
&lt;/h1&gt;
&lt;h2&gt;
  
  
  with template properties
&lt;/h2&gt;

&lt;p&gt;One option for the &lt;code&gt;ng-template&lt;/code&gt; based solutions is to directly pass the custom contents in a property as &lt;code&gt;TemplateRef&lt;/code&gt;s.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-template-render-props&lt;/span&gt;
  &lt;span class="na"&gt;[templates]=&lt;/span&gt;&lt;span class="s"&gt;"{ 'header': header, 'footer': footer }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-template-render-props&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#header&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;div&amp;gt;&lt;/span&gt;Custom Header&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#footer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;div&amp;gt;&lt;/span&gt;Custom Footer&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The provided &lt;code&gt;TemplateRef&lt;/code&gt; for each slot is rendered using &lt;code&gt;*ngTemplateOutlet&lt;/code&gt;. Same as for the &lt;code&gt;ng-content&lt;/code&gt; approach the component falls back to a default content in case nothing has been defined (done by the &lt;code&gt;RenderTemplateComponent&lt;/code&gt; helper in the example).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-render-template&lt;/span&gt;
  &lt;span class="na"&gt;[template]=&lt;/span&gt;&lt;span class="s"&gt;"{ customTemplate: templates.header, defaultTemplate: defaultHeader }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-render-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;app-render-template&lt;/span&gt;
  &lt;span class="na"&gt;[template]=&lt;/span&gt;&lt;span class="s"&gt;"{ customTemplate: templates.footer, defaultTemplate: defaultHeader }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-render-template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultHeader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Default Header&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultFooter&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Default Footer&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  with directive
&lt;/h2&gt;

&lt;p&gt;Having to define a dedicated &lt;code&gt;ng-template&lt;/code&gt; wrapper for each custom content is inconvenient to use and clutters the template of the using component. This can be avoided by using a structural directive storing the &lt;code&gt;TemplateRef&lt;/code&gt; as well as the slot name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[appTemplateSlot]&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TemplateSlotDirective&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;appTemplateSlot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SlotName&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directive takes the slot name ("header" or "footer" in the example) as input property and stores the associated &lt;code&gt;TemplateRef&lt;/code&gt; in a public &lt;code&gt;template&lt;/code&gt; property (the &lt;code&gt;unknown&lt;/code&gt; type of &lt;code&gt;TemplateRef&lt;/code&gt; could be replaced by the associated context in case it is known/available).&lt;/p&gt;

&lt;p&gt;The rendering component can now query for the &lt;code&gt;TemplateSlotDirective&lt;/code&gt;s using &lt;code&gt;@ContentChildren&lt;/code&gt; and render the stored &lt;code&gt;template&lt;/code&gt; to the associated slot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-render-props-directive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RenderPropsDirectiveComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContentChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TemplateSlotDirective&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;templateSlots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;templateSlots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TemplateSlotDirective&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;templateDirectives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;templateSlots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateSlots&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;templateDirectives&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReplaySubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TemplateSlotDirective&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;templates$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Templates&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;templateDirectives&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;ReplaySubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;templates$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupTemplates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;templateDirectives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setupTemplates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;templateDirectives$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TemplateSlotDirective&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Templates&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;templateDirectives$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;templateDirectives&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;templateDirectives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;partialTemplateDirectives&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;templateDirective&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;templateDirective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appTemplateSlot&lt;/span&gt;
              &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;partialTemplateDirectives&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;templateDirective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appTemplateSlot&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="nx"&gt;templateDirective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;partialTemplateDirectives&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bufferSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;refCount&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;As usual the rendering component now either renders the custom or fallback content for each slot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-render-template&lt;/span&gt;
  &lt;span class="na"&gt;[template]=&lt;/span&gt;&lt;span class="s"&gt;"{ customTemplate: (templates$ | async)?.header, defaultTemplate: defaultHeader }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-render-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;app-render-template&lt;/span&gt;
  &lt;span class="na"&gt;[template]=&lt;/span&gt;&lt;span class="s"&gt;"{ customTemplate: (templates$ | async)?.footer, defaultTemplate: defaultHeader }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-render-template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultHeader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Default Header&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#defaultFooter&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Default Footer&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As shown below the &lt;code&gt;ng-template&lt;/code&gt; wrapper is now replaced by putting the &lt;code&gt;TemplateSlotDirective&lt;/code&gt; selector on the the custom content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-render-props-directive&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*appTemplateSlot=&lt;/span&gt;&lt;span class="s"&gt;"'header'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Custom Header&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;*appTemplateSlot=&lt;/span&gt;&lt;span class="s"&gt;"'footer'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Custom Footer&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/app-render-props-directive&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;With both the &lt;code&gt;ng-content&lt;/code&gt; as well as the &lt;code&gt;ng-template&lt;/code&gt; it was/is possible to fulfill the requirements to either display custom content or fall back to rendering a default.&lt;br&gt;
I prefer the &lt;code&gt;ng-template&lt;/code&gt; based solution as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When used with a structural directive provides the same ease of use as &lt;code&gt;ng-content&lt;/code&gt; for the using component (especially within the template).&lt;/li&gt;
&lt;li&gt;It allows for extracting all the repetitive rendering related implementations which can be reused for components requiring the same "feature". This is/was not possible for the &lt;code&gt;ng-content&lt;/code&gt; based solution due to the issue with querying nested &lt;code&gt;ng-content&lt;/code&gt;s using &lt;code&gt;@ContentChildren&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete code for the POC can be found &lt;a href="https://github.com/remshams/optional-content-projection" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Custom build configurations for testing and debugging in iOS/Xcode</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Wed, 28 Apr 2021 17:46:24 +0000</pubDate>
      <link>https://dev.to/remshams/custom-build-configurations-for-testing-and-debugging-in-ios-2dgj</link>
      <guid>https://dev.to/remshams/custom-build-configurations-for-testing-and-debugging-in-ios-2dgj</guid>
      <description>&lt;p&gt;When debugging one of my unit tests I coincidentally noticed that the complete start-up procedure/code was running before the unit tests get executed. With my web development background, this was somehow surprising to me as I expected only the class/method... referenced by the test suite being run. After taking some time to think about it this makes a lot of sense as the tests are run e.g. on a simulator where the application first needs to be installed and started before the tests run.&lt;br&gt;&lt;br&gt;
This means that any side effects at application start e.g. an HTTP call is also triggered when any unit test gets executed. Even though this did not lead to any unwanted side effects in my particular case I felt uneasy about the requests being performed. So I was looking for some means to exchange the "production" implementation with a version suitable for test runs or debugging.&lt;/p&gt;

&lt;p&gt;For the unit tests, I already relied on constructor-based dependency injection to pass stubs/mocks to avoid unwanted side effects and/or return test data. However, this only covered the dependencies for the subject under test, but not whatever is executed at application start.&lt;br&gt;
Having dependency injection already in place I just required some means to "determine" at compile and/or runtime if the problematic dependencies should be replaced by e.g. a test- or in-memory version.&lt;br&gt;&lt;br&gt;
The idea was to define a "mode" like &lt;code&gt;test&lt;/code&gt; or &lt;code&gt;production&lt;/code&gt; which could be derived and set at application start.&lt;/p&gt;
&lt;h1&gt;
  
  
  Build Configuration based dependency injection
&lt;/h1&gt;

&lt;p&gt;When creating a new project in XCode it also defines build configurations like &lt;code&gt;DEBUG&lt;/code&gt; and &lt;code&gt;RELEASE&lt;/code&gt; which can be used in combination with preprocessor macros to include different code sections depending on the configuration the build is executed with.&lt;br&gt;&lt;br&gt;
This seems to be often used e.g. to exclude SwiftUI previews from release builds or define a different &lt;code&gt;PersistenceController&lt;/code&gt; when working with &lt;code&gt;CoreData&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/20637435/xcode-what-is-a-target-and-scheme-in-plain-language" rel="noopener noreferrer"&gt;Schemes&lt;/a&gt; can then be used to set unique build configurations e.g. for &lt;code&gt;Run&lt;/code&gt; or &lt;code&gt;Test&lt;/code&gt;. This seemed to be sufficient to solve my test run dependency issues.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;DEBUG&lt;/code&gt; flag was one option but would also replace the release dependencies with the test/in-memory versions for debug runs on the simulator/real device (something I did not want). So a dedicated &lt;code&gt;Test&lt;/code&gt; configuration would allow for having different dependencies injected during debug- and test runs.&lt;br&gt;&lt;br&gt;
As it turned out creating and using such a custom configuration requires three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a custom build configuration and configuring the Active Compilation Conditions&lt;/li&gt;
&lt;li&gt;Injecting dependencies based on the configuration selected&lt;/li&gt;
&lt;li&gt;Creating/updating the Xcode &lt;code&gt;scheme&lt;/code&gt; for &lt;code&gt;Run&lt;/code&gt; and &lt;code&gt;Test&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Build configurations and Active Compilation Conditions
&lt;/h2&gt;

&lt;p&gt;First a new custom &lt;code&gt;Build Configuration&lt;/code&gt; is required, which can be created in the project settings &lt;code&gt;Info&lt;/code&gt; tab by duplicating from the e.g. &lt;code&gt;Debug&lt;/code&gt; configuration:&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%2Fb9baylgjm4yxpes21fw4.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%2Fb9baylgjm4yxpes21fw4.png" alt="Test Build Configuration" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next a new entry for &lt;code&gt;Active Compilations Conditions&lt;/code&gt; needs to be added for &lt;code&gt;Test&lt;/code&gt; which can be done in the &lt;code&gt;Build Settings&lt;/code&gt; Tab. It made sense to me to set &lt;code&gt;TEST&lt;/code&gt; as well as &lt;code&gt;DEBUG&lt;/code&gt; for the &lt;code&gt;Test&lt;/code&gt; build configuration to make sure everything applied to &lt;code&gt;Debug&lt;/code&gt; is also applied for &lt;code&gt;Test&lt;/code&gt; (in addition to what is defined for &lt;code&gt;Test&lt;/code&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%2F3zgdu0lmni4w8rds8vx3.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%2F3zgdu0lmni4w8rds8vx3.png" alt="Custom Active Compilations Conditions" width="800" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having it setup like this the &lt;code&gt;TEST&lt;/code&gt; flag is now available (in addition to &lt;code&gt;DEBUG&lt;/code&gt; and &lt;code&gt;RELEASE&lt;/code&gt;) for usage in preprocessor macros.&lt;/p&gt;
&lt;h2&gt;
  
  
  Build Configuration based injection
&lt;/h2&gt;

&lt;p&gt;Using macros alone, it is already possible to switch between different dependencies based on the active build configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeTodosRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TodosRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cp"&gt;#if TEST&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;InMemoryTodosRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="cp"&gt;#else&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;ProductionTodosRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://jsonplaceholder.typicode.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I did not want to use a macro wherever configuration specific code is required. So I next created a swift enum reflecting all application &lt;code&gt;mode&lt;/code&gt;s. The mode is determined at startup and made available as &lt;code&gt;shared&lt;/code&gt; global property (same as it is often done e.g. for the &lt;code&gt;PersistenceController&lt;/code&gt; and &lt;code&gt;CoreData&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;ApplicationMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="cp"&gt;#if TEST&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ApplicationMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="cp"&gt;#elseif DEBUG&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ApplicationMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;RunningMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To me, the approach has the advantage that Swift language features can be used when working with the configuration. It also decouples the application running mode from the build configurations (in case necessary for any reason).&lt;/p&gt;

&lt;p&gt;The global available application &lt;code&gt;mode&lt;/code&gt; property can next be combined with any dependency inject approach (e.g. like the &lt;a href="https://www.raywenderlich.com/books/advanced-ios-app-architecture/v3.0" rel="noopener noreferrer"&gt;Single-container approach&lt;/a&gt;), restricting the configuration dependant implementations to a few dedicated classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;TodosRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ListTodos&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;AppContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;todosRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TodosRepository&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;todosContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TodosContainer&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;todosRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AppContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeTodosRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;todosContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AppContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeTodosContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;listTodos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;todosRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Application running in mode: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;func&lt;/span&gt; &lt;span class="nf"&gt;makeTodosContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TodosContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;todosContainer&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeTodosRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TodosRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;InMemoryTodosRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;ProductionTodosRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://jsonplaceholder.typicode.com"&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="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeTodosContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;listTodos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ListTodos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TodosContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;TodosContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;listTodos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;listTodos&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="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;ProductionTodosRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TodosRepository&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;InMemoryTodosRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TodosRepository&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Schemes
&lt;/h2&gt;

&lt;p&gt;To make it all work for test runs the build configuration is set to &lt;code&gt;Test&lt;/code&gt; for the &lt;code&gt;Test&lt;/code&gt; step:&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%2Fdf9r0f44johooopwpv1t.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%2Fdf9r0f44johooopwpv1t.png" alt="Test step scheme" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything has been wired up correctly the application should now use the &lt;code&gt;Test&lt;/code&gt; dependencies on test startup (at least mine did ;) ).&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The short article described how to exchange dependencies based on tags by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defining a custom build configuration and &lt;code&gt;Active Compilation Conditions&lt;/code&gt; property&lt;/li&gt;
&lt;li&gt;Injecting dependencies based on the application running &lt;code&gt;mode&lt;/code&gt; derived from the active build configuration&lt;/li&gt;
&lt;li&gt;Creating/Updating a scheme to run the tests with the custom build configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This now allows for having different dependencies during test and debugging sessions. In case of interest, a small example application using the approach can be found on &lt;a href="https://github.com/remshams/xcode-custom-build-configurations" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Environment Variables
&lt;/h1&gt;

&lt;p&gt;As explained &lt;a href="https://stackoverflow.com/a/24344459" rel="noopener noreferrer"&gt;here&lt;/a&gt; exchanging dependencies only requires different behavior and not different compilation, so environment variables read at runtime could be a solution as well.&lt;br&gt;&lt;br&gt;
I opted against such an approach as the variables are set for all build configurations and therefore need to be manually switched on/off depending e.g. when running tests or debugging.&lt;br&gt;&lt;br&gt;
Besides the advantage of not having to recompile the application when changing the variable was not relevant for my use case/problem.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
    </item>
    <item>
      <title>Rolling (up) a multi module system (esm, cjs...) compatible npm library with TypeScript and Babel</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sun, 07 Feb 2021 16:16:18 +0000</pubDate>
      <link>https://dev.to/remshams/rolling-up-a-multi-module-system-esm-cjs-compatible-npm-library-with-typescript-and-babel-3gjg</link>
      <guid>https://dev.to/remshams/rolling-up-a-multi-module-system-esm-cjs-compatible-npm-library-with-typescript-and-babel-3gjg</guid>
      <description>&lt;p&gt;In this article we will delve into the build chain and build steps necessary to create the artifacts required to publish a library on npm. Our goal will be to provide our library consumers with a versatile package supporting (modern/legacy) JavaScript/TypeScript as well as the most common module systems.&lt;br&gt;
What has been written is based on my learnings and research when creating packages and is also meant to be documentation for myself. The process is still in flux, so every feedback (ideas for improvements, critics...) is, as always, very welcome.&lt;/p&gt;
&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;The first section lists and explains the requirements for the build process as well as the artifacts it produces. Related to this, we will also answer the question if a bundled version is required for each of the supported module systems.&lt;br&gt;&lt;br&gt;
With the requirements ready, the build chain and, most important, the steps for creating the necessary library artifacts will be laid out.&lt;/p&gt;

&lt;p&gt;As demonstration defeats discussion, we will look at the implementation of the sketched out build chain with help of an example "library". In the end there will be a deployment ready package, hopefully fulfilling all listed requirements.&lt;br&gt;&lt;br&gt;
As our focus lies on packing itself, the "features" of the example library are irrelevant and are therefore kept extremely simple.&lt;/p&gt;

&lt;p&gt;The explanations provided are based on my current understanding of the topics and may be opinionated or incomplete (hopefully not wrong). In addition, every package is unique and therefor its/your requirements and the resulting process can differ from what has been written here. However, I have tried to keep the information as overall applicable as possible. As mentioned in the beginning, feed back is very welcome.&lt;br&gt;&lt;br&gt;
That being said, let's start with the requirements for our build artifacts.&lt;/p&gt;
&lt;h1&gt;
  
  
  Requirements
&lt;/h1&gt;
&lt;h2&gt;
  
  
  JavaScript/TypeScript
&lt;/h2&gt;

&lt;p&gt;To me, one important goal was to make the modernly written, not transpilled library code available for further processing. This helps e.g. to decrease bundle sizes, as downstream consumers can base their build chain on the most current/common JavaScript version and only transpile the code to the language level required by their browser- or node version needs.&lt;/p&gt;

&lt;p&gt;However, for consumers not able to leverage modern JavaScript, an ES5 based version sacrificing the latest features must be provided.&lt;/p&gt;

&lt;p&gt;In case TypeScript is used, a transpilled JavaScript version should be supplied as well, so we do not enforce unnecessary restrictions to consumers by our language choice. "Types" will be provided as separate type definition files.&lt;/p&gt;
&lt;h2&gt;
  
  
  Module system
&lt;/h2&gt;

&lt;p&gt;Next to modern JavaScript, the library must support all current/common module systems. At the time of writing these are "ECMAScript Modul" (&lt;code&gt;esm&lt;/code&gt;), "CommonJs" (&lt;code&gt;cjs&lt;/code&gt;) and "Asynchronous Module Definition" (&lt;code&gt;AMD&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Especially supporting &lt;code&gt;esm&lt;/code&gt; is important to allow tree shaking support for consumers using bundlers like Rollup or webpack. So even when transpilled to legacy JavaScript, leveraging &lt;code&gt;esm&lt;/code&gt; is still beneficial (as described &lt;a href="https://web.dev/publish-modern-javascript/#modern-with-legacy-fallback-and-esm-bundler-optimizations" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;
  
  
  To bundle or not to bundle...
&lt;/h1&gt;

&lt;p&gt;Bundling is usually applied when writing JavaScript for the client (e.g. &lt;code&gt;Single Page Applications&lt;/code&gt;) as it avoids too many round trips to the server (especially before &lt;code&gt;HTTP/2&lt;/code&gt; arrived) by delivering everything in a single file. However, with multiplexing and server side push now being available in &lt;code&gt;HTTP/2&lt;/code&gt;, the questions is a bit more controversial today.&lt;/p&gt;

&lt;p&gt;If we take into account that downstream build systems further process and bundle the library code, the npm package should contain an unbundled artifact for all supported module systems with the most modern JavaScript version possible. This gives our consumers the flexibility to shape the library code based on their needs (e.g. supported browser versions) helping them to reduce the amount of shipped code by avoiding e.g. unnecessary transpilling.&lt;/p&gt;

&lt;p&gt;So if the library code is further processed by downstream consumers, one may ask the question if we need to create a bundled version at all? I sifted through different (popular and not so popular) npm packages and some of these are bundling, while others are not. Also reading blog posts and tutorials did not give a unambiguous answer, leaving me more confused then before.&lt;br&gt;&lt;br&gt;
Therefor I decided to look at each module system individually combined with whether it is used on the client or server. My hope was that I'd find some enlightenment when narrowing done the question...&lt;br&gt;
Next you find the reasoning I finally came up with.&lt;/p&gt;
&lt;h2&gt;
  
  
  ECMAScript Modules
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Browser
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;esm&lt;/code&gt; based library artifacts are consumed by e.g. &lt;code&gt;SPAs&lt;/code&gt; something like webpack or Rollup should be in place. Further processing, like tree-shaking, bundling, minifying..., is therefor better left to the downstream build process.&lt;/p&gt;

&lt;p&gt;So I originally decided not to include a bundled &lt;code&gt;esm&lt;/code&gt; version. But, when reading about the reasoning for providing a bundled &lt;code&gt;umd&lt;/code&gt; artifact (described in the section below) I thought about doing the same for &lt;code&gt;esm&lt;/code&gt;. It does sound counterintuitive at first, I mean what benefit do we get from a modern module system when everything is bundled to a single file. What we do get however, is all the modern JavaScript available for library code written in ES6+ syntax. This means modern browser can choose the bundled &lt;code&gt;esm&lt;/code&gt; version instead of &lt;code&gt;umd&lt;/code&gt; for direct import, avoiding all the additional code created to make our library code compatible with previous JavaScript versions. One could argue that in such a case the unbundled artifact could be imported. However, there still could be use cases for the bundled alternative e.g. in case &lt;code&gt;HTTP/2&lt;/code&gt; is not available and therefor loading a lots of files is not a performant option.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;

&lt;p&gt;In case the server application uses a current node version, same reasoning as for the browser applies.&lt;br&gt;&lt;br&gt;
However, the server can directly load the files from disk which should have almost no performance impact compared to the http request the browser has to perform. So I don't see any reason for using the bundled version here, even if no additional build process is in place.&lt;/p&gt;
&lt;h2&gt;
  
  
  CommonJs
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Browser
&lt;/h3&gt;

&lt;p&gt;Same arguments as for &lt;code&gt;esm&lt;/code&gt;: Bundling should not be required as the imported library is always further processed by downstream build systems.&lt;br&gt;
The only reason why client applications could/should use the &lt;code&gt;cjs&lt;/code&gt; instead of the &lt;code&gt;esm&lt;/code&gt; version is in case of an older bundler which does not understand the latter. In all other cases &lt;code&gt;esm&lt;/code&gt; is the preferred option as the tree shaking support is superior to &lt;code&gt;cjs&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;

&lt;p&gt;Again no difference to &lt;code&gt;esm&lt;/code&gt;. However, by including a &lt;code&gt;cjs&lt;/code&gt; version we ensure older node versions are also supported, so no additional/extra transpilling step is required for library consumers.&lt;/p&gt;
&lt;h2&gt;
  
  
  UMD
&lt;/h2&gt;

&lt;p&gt;We will discuss the bundling question for &lt;code&gt;umd&lt;/code&gt; instead of &lt;code&gt;amd&lt;/code&gt;, as the latter supports both &lt;code&gt;amd&lt;/code&gt; and &lt;code&gt;cjs&lt;/code&gt; in a single artifact.&lt;/p&gt;
&lt;h3&gt;
  
  
  Browser
&lt;/h3&gt;

&lt;p&gt;For me, the bundling question was a bit harder to answer for &lt;code&gt;umd&lt;/code&gt;, as I have most often worked in environments (usually &lt;code&gt;SPAs&lt;/code&gt;) where either &lt;code&gt;cjs&lt;/code&gt; and/or &lt;code&gt;esm&lt;/code&gt; has been used in combination with a dedicated bundler.&lt;br&gt;&lt;br&gt;
The reason for including a bundled &lt;code&gt;umd&lt;/code&gt; version is to support direct usage (with no further processing) in (older) browsers e.g. from something like &lt;a href="https://unpkg.com" rel="noopener noreferrer"&gt;unpkg&lt;/a&gt;. Modern browser, as described above, can use the bundled &lt;code&gt;esm&lt;/code&gt; version.&lt;br&gt;&lt;br&gt;
However, when a bundling step is performed downstream, it should always either use &lt;code&gt;esm&lt;/code&gt; or &lt;code&gt;cjs&lt;/code&gt; making an unbundled version superfluous.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;

&lt;p&gt;Node can always use either &lt;code&gt;esm&lt;/code&gt; or &lt;code&gt;cjs&lt;/code&gt;. So in case these are included in the npm package there seems to be no reason to provide a special, unbundled &lt;code&gt;umd&lt;/code&gt; version for node. It provides no benefit over the bundled variant already considered required in order to cover all use cases.&lt;/p&gt;

&lt;p&gt;My final impression regarding &lt;code&gt;umd&lt;/code&gt; and server applications is, that it makes sense if one wants to include only a single version of the library. However, since npm packages and bundlers (now) support including multiple versions and creating these is not much effort, there seems to be no reason for restricting library consumers to just &lt;code&gt;umd&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This brings us the conclusion that a bundled version is only required for &lt;code&gt;esm&lt;/code&gt; and &lt;code&gt;umd&lt;/code&gt;. For all other module system bundling is not a necessity, which finally leads to the following list of library artifacts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an unbundled &lt;code&gt;esm&lt;/code&gt; version&lt;/li&gt;
&lt;li&gt;an bundled &lt;code&gt;esm&lt;/code&gt; version&lt;/li&gt;
&lt;li&gt;an unbundled &lt;code&gt;cjs&lt;/code&gt; version&lt;/li&gt;
&lt;li&gt;a bundled &lt;code&gt;umd&lt;/code&gt; version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These four variants should cover most of our consumers use cases without restricting their build processes and, most importantly, not forcing them to ship unnecessary JavaScript code.&lt;/p&gt;

&lt;p&gt;Having the bundle/not bundle question out of the way, we will next define the build chain and its steps to create the listed artifacts.&lt;/p&gt;
&lt;h1&gt;
  
  
  Build chain
&lt;/h1&gt;

&lt;p&gt;The diagram below gives an overview of the steps required to go from our written source code (TypeScript for the example library) to the artifacts described in the previous section. The image also shows how the created results are referenced in the &lt;code&gt;package.json&lt;/code&gt;. This is important as it makes downstream bundlers "aware" of the available versions allowing them to choose the most appropriate one (e.g. &lt;code&gt;esm&lt;/code&gt; over &lt;code&gt;cjs&lt;/code&gt; for better tree shaking support).&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%2Fjchbvcglx3jt5rjj3txx.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%2Fjchbvcglx3jt5rjj3txx.jpeg" alt="Build chain overview" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Diagrams often read kind of abstract before knowing the details and this one is no exception. Therefor, when next going through the process and its artifacts, excerpts from the example library (e.g. configuration files) are referenced to provide additional details.&lt;br&gt;&lt;br&gt;
One note regarding the employed build tools mentioned in the diagram: I tried to use the most common ones for this/my build chain fulfilling the requirements listed earlier. These can of course be replaced by your own choice e.g. &lt;code&gt;tsc&lt;/code&gt; instead of &lt;code&gt;babel&lt;/code&gt; when compiling TypeScript.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the library artifacts
&lt;/h2&gt;

&lt;p&gt;The build steps next described need to get us from our source to the four target build artifacts defined in the previous section. For the example application this means going from TypeScript to &lt;code&gt;esm&lt;/code&gt; (bundled and unbundled), &lt;code&gt;cjs&lt;/code&gt; (unbundled) and &lt;code&gt;umd&lt;/code&gt; (bundled).&lt;br&gt;&lt;br&gt;
The two main steps required are transpilling and bundling. The latter is of course only needed when the final build artifact is a bundle.&lt;/p&gt;
&lt;h3&gt;
  
  
  Transpilling
&lt;/h3&gt;

&lt;p&gt;With the example application written in TypeScript, our first step is to go to the target JavaScript versions. Usually this can either be done by using &lt;code&gt;tsc&lt;/code&gt; or, as of late, &lt;code&gt;babel&lt;/code&gt; (with help of the &lt;code&gt;@babel/typescript&lt;/code&gt; plugin).&lt;br&gt;&lt;br&gt;
I opted for the latter as it, in my opinion, provides more flexibility compared to &lt;code&gt;tsc&lt;/code&gt; when configuring the transpilation/compilation step (e.g. &lt;code&gt;tsc&lt;/code&gt; requires a specific target JavaScript version where as in &lt;code&gt;babel&lt;/code&gt; it can be defined based on browsers market share, versions and the like). In addition, with the support of TypeScript in Babel, we can now use almost the same build chain for JavaScript or TypeScript projects helping to unify/simplify the process.&lt;/p&gt;

&lt;p&gt;The exact Babel configuration is somehow specific for each individual library/project and/or requirements. For the example library we only require two babel plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://babeljs.io/docs/en/babel-preset-typescript" rel="noopener noreferrer"&gt;@babel/typescript&lt;/a&gt;: To go from TypeScript to JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://babeljs.io/docs/en/babel-preset-env" rel="noopener noreferrer"&gt;@babel/env&lt;/a&gt;: To get down to the JavaScript version fulfilling the configuration we opted for (e.g. supported browsers and node versions)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A description of the two plugins and the available configurations is out of scope of the article. Therefor, I only quickly note why a property has been set like that and the reasoning behind it.&lt;br&gt;&lt;br&gt;
Especially the &lt;code&gt;@babel/env&lt;/code&gt; plugin provides a lot of flexibility, so in case you are interested in more details the two provided links should make for a good starting point.&lt;/p&gt;

&lt;p&gt;Having that said, the configuration for the example library looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sharedPresets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/typescript&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;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.spec.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;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sharedPresets&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="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;esmUnbundled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;esmBundled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt; 0.25%, not dead&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;sharedPresets&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;cjs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;commonjs&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;sharedPresets&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;We are using three Babel environments here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;esmUnbundled&lt;/code&gt;: The environment only goes from TypeScript to JavaScript and keeps the rest of the code in place. This is on purpose as it makes the most modern version of the library available to our consumers for further processing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;esmBundled&lt;/code&gt;: In addition to what is done in &lt;code&gt;unbundled&lt;/code&gt;, the &lt;code&gt;bundled&lt;/code&gt; environment transpiles to JavaScript supported by the majority of browsers/node versions. I opted against transpilling completely down to &lt;code&gt;ES2015&lt;/code&gt; as older browser can use the &lt;code&gt;umd&lt;/code&gt; alternative when directly importing the library.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cjs&lt;/code&gt;: Again, the environment is similar to &lt;code&gt;es-unbundled&lt;/code&gt;, with the only difference that &lt;code&gt;esm&lt;/code&gt; is replaced by &lt;code&gt;commonjs&lt;/code&gt; with the help of &lt;code&gt;@babel/env&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To execute the Babel transpilation, two &lt;code&gt;scripts&lt;/code&gt; have been defined in the &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build:esm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env BABEL_ENV=esmUnbundled babel src --extensions '.ts' --out-dir 'lib/esm' --source-maps"&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:cjs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env BABEL_ENV=cjs babel src --extensions '.ts' --out-dir 'lib/cjs' --source-maps"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&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;At the time of writing, source maps &lt;a href="https://github.com/babel/babel/issues/5261" rel="noopener noreferrer"&gt;seem not to be generated&lt;/a&gt; when configured in &lt;code&gt;.babelrc&lt;/code&gt; which is why &lt;code&gt;--source-maps&lt;/code&gt; has been added.&lt;br&gt;&lt;br&gt;
Running the scripts gives the following result:&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%2Fpg1swwaspdm9kno8bb2g.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%2Fpg1swwaspdm9kno8bb2g.png" alt="Dist folder with unbundled artifacts" width="165" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unsurprisingly, the &lt;code&gt;esm&lt;/code&gt; folder contains the unbundled &lt;code&gt;esm&lt;/code&gt; and &lt;code&gt;cjs&lt;/code&gt; the unbundled &lt;code&gt;cjs&lt;/code&gt; artifact.&lt;/p&gt;

&lt;p&gt;For the unbundled case we are almost done. What is missing is a reference to our &lt;code&gt;index.js&lt;/code&gt; entry files from to &lt;code&gt;package.json&lt;/code&gt; to make Bundlers aware of the available versions.&lt;br&gt;&lt;br&gt;
As described in detail &lt;a href="https://webpack.js.org/guides/package-exports/" rel="noopener noreferrer"&gt;here&lt;/a&gt; we need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the &lt;code&gt;main&lt;/code&gt; property to our &lt;code&gt;cjs&lt;/code&gt; &lt;code&gt;index.js&lt;/code&gt; and the &lt;code&gt;module&lt;/code&gt; property to the &lt;code&gt;esm&lt;/code&gt; &lt;code&gt;index.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set the appropriate properties in &lt;code&gt;exports&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;require&lt;/code&gt; again to the &lt;code&gt;cjs&lt;/code&gt; &lt;code&gt;index.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;import&lt;/code&gt; again to the &lt;code&gt;esm&lt;/code&gt; &lt;code&gt;index.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&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/cjs/index.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/esm/index.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;"exports"&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;"require"&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/cjs/index.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;"import"&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/esm/index.js"&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="err"&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;Having the &lt;code&gt;package.json&lt;/code&gt; setup like that, Bundlers can now choose whatever alternative is best supported. For example modern ones can take the &lt;code&gt;esm&lt;/code&gt; artifact whereas as older ones (not supporting the new &lt;code&gt;module&lt;/code&gt; and &lt;code&gt;exports&lt;/code&gt; property) fall back to what is referenced in &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To finalize our package we will next look how to generate the bundled artifacts for &lt;code&gt;esm&lt;/code&gt; and &lt;code&gt;umd&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bundling
&lt;/h3&gt;

&lt;p&gt;To bundle our library we need a ... Bundler. I chose Rollup for the job since it has good support for creating different versions for each module system from a single entry file. Of course it can again be replaced by whatever Bundler you prefer as long as it bundles to the required module systems and also comes with a plugin for the Transpiler, Terser... of your choice.&lt;/p&gt;

&lt;p&gt;As shown in the overview from the beginning of this section, there is not much difference between the build steps of the unbundled and bundled versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Bundler takes care of orchestrating the build process and build tools (like the Transpiler), so no need to call these "individually"&lt;/li&gt;
&lt;li&gt;an additional bundling step is added to the end of the build chain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the example library, the Rollup configuration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;babel&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;@rollup/plugin-babel&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="s1"&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;terser&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;rollup-plugin-terser&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;extensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.ts&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="s1"&gt;src/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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib/bundles/bundle.esm.js&lt;/span&gt;&lt;span class="dl"&gt;'&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="s1"&gt;esm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sourcemap&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib/bundles/bundle.esm.min.js&lt;/span&gt;&lt;span class="dl"&gt;'&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="s1"&gt;esm&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;terser&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
      &lt;span class="na"&gt;sourcemap&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib/bundles/bundle.umd.js&lt;/span&gt;&lt;span class="dl"&gt;'&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="s1"&gt;umd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myLibrary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sourcemap&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib/bundles/bundle.umd.min.js&lt;/span&gt;&lt;span class="dl"&gt;'&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="s1"&gt;umd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myLibrary&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;terser&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
      &lt;span class="na"&gt;sourcemap&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="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="nx"&gt;extensions&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;babelHelpers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./node_modules/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is nothing too fancy going on:&lt;br&gt;&lt;br&gt;
The &lt;code&gt;input&lt;/code&gt; property points to the entry &lt;code&gt;index.ts&lt;/code&gt; and &lt;code&gt;output&lt;/code&gt; defines the configurations for both &lt;code&gt;esm&lt;/code&gt; (normal/minified) and &lt;code&gt;umd&lt;/code&gt;(normal/minified). Additionally, the &lt;code&gt;sourcemap&lt;/code&gt; attribute has been added and set to &lt;code&gt;true&lt;/code&gt; to create external source map files. The &lt;code&gt;name&lt;/code&gt; property for the &lt;code&gt;umd&lt;/code&gt; version defines the namespace for the exported functions (e.g. &lt;code&gt;myLibrary.echo()&lt;/code&gt; for the example library).&lt;br&gt;&lt;br&gt;
For the build itself we require three plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@rollup/plugin-node-resolve&lt;/code&gt;: The plugin adds support to resolve imports to other node packages. This is not required for the example library (as no other dependency is used) but has been added since it is not unlikely to occur for more complex packages.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@rollup/plugin-babel&lt;/code&gt;: Triggers the transpile step through Babel (basically what we have done by means of the &lt;code&gt;babel-cli&lt;/code&gt; for the unbundled versions). As we are using babel only for the bundled artifacts &lt;code&gt;babelHelpers&lt;/code&gt; are set to &lt;code&gt;bundled&lt;/code&gt;, so in case any helpers are needed these are added to the bundle file (you can read more about the property in the &lt;a href="https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;). In &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;extensions&lt;/code&gt; the files and their extensions (&lt;code&gt;ts/js&lt;/code&gt; for the example library) to process are defined, whereas&lt;code&gt;excludes&lt;/code&gt; indicates folders/patterns which should be skipped (just the &lt;code&gt;node_modules&lt;/code&gt; folder for the example library).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rollup-plugin-terser&lt;/code&gt;: Used for minification and therefor only added for the minified outputs. This is optional and can be left out in case not wanted or required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Executing the Rollup process by using the added &lt;code&gt;package.json&lt;/code&gt; script &lt;code&gt;build:bundles&lt;/code&gt; produces the following result:&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%2Fc3nf17940un56457un7c.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%2Fc3nf17940un56457un7c.png" alt="Dist folder with bundled artifacts" width="206" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An new folder &lt;code&gt;bundles&lt;/code&gt; has been created containing the &lt;code&gt;esm&lt;/code&gt; and &lt;code&gt;umd&lt;/code&gt; artifacts. In contrast to the unbundled ones, there is no need/means to reference the former from the &lt;code&gt;package.json&lt;/code&gt; as these will be directly imported and are not meant for further processing.&lt;/p&gt;

&lt;p&gt;We now have all required "code" artifacts available for the package. The last thing missing is creating type definitions, so that clients using TypeScript can easily integrate the library.&lt;/p&gt;
&lt;h2&gt;
  
  
  Types
&lt;/h2&gt;

&lt;p&gt;Babel currently "only" transpiles our TypeScript code to JavaScript. Therefor, as shown in the overview diagram, a dedicated build step is required for creating the type definition files using &lt;code&gt;tsc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As we already have the transpiled JavaScript code, our &lt;code&gt;tsconfig.json&lt;/code&gt; can be kept pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="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;"emitDeclarationOnly"&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;"declarationMap"&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;"outDir"&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="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="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"./src/index.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="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;With the &lt;code&gt;declarations&lt;/code&gt; and &lt;code&gt;emitDeclarationOnly&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;tsc&lt;/code&gt; only creates declarations files and skips transpilling to JavaScript. The result is then put into the folder defined by &lt;code&gt;outDir&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
We also should not miss to create mappings between the &lt;code&gt;*.d.ts&lt;/code&gt; and &lt;code&gt;*.ts&lt;/code&gt; files, enabling IDEs like VSCode or IntelliJ to navigate directly to the source instead of the declarations files e.g. on &lt;code&gt;CMD + click&lt;/code&gt;/&lt;code&gt;Strg + click&lt;/code&gt; on a method or property name. This is simply done by adding the &lt;code&gt;declarationMap&lt;/code&gt; to the &lt;code&gt;tsconfig.json&lt;/code&gt; and setting it again to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The script &lt;code&gt;declarations&lt;/code&gt; has been added to the &lt;code&gt;package.json&lt;/code&gt; to trigger &lt;code&gt;tsc&lt;/code&gt;, which will create the declaration files in the &lt;code&gt;types&lt;/code&gt; folder (as defined by &lt;code&gt;outDir&lt;/code&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%2F3dmnpfwjs667oqw1vt3t.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%2F3dmnpfwjs667oqw1vt3t.png" alt="Dist folder with TypeScript types" width="164" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a final step we link the &lt;code&gt;index.d.ts&lt;/code&gt; file in the &lt;code&gt;package.json&lt;/code&gt; by means of the &lt;code&gt;types&lt;/code&gt; property, helping IDEs to discover the types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="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/index.d.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the unbundled-, bundled library versions and type declarations created, we now have a library ready for being published on npm. Since there are numerous posts out there explaining this final step (and the example application is pretty useless) we will not go further into this.&lt;br&gt;&lt;br&gt;
So time for wrapping up...&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The goal for this article was to create a versatile build chain to allow creating libraries that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provide raw, non transpilled artifacts based on modern JavaScript or TypeScript which can be further processed by downstream build chains&lt;/li&gt;
&lt;li&gt;provide an unbundled- (for consumers using Bundlers) and bundled (for direct usage/import) version&lt;/li&gt;
&lt;li&gt;support all modern and legacy module systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the listed requirements ready, we sketched the build steps and setup necessary to create our library artifacts.&lt;br&gt;&lt;br&gt;
To make the theoretical overview more tangible the process has been described based on a simple example library. This included a possible choice of tools required to realize the build chain and creating the artifacts necessary to fulfill our initial goals.&lt;/p&gt;

&lt;h1&gt;
  
  
  Appendix
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Testing locally
&lt;/h2&gt;

&lt;p&gt;To test the example library locally I have created a separate &lt;a href="https://github.com/remshams/node-module-esm-test" rel="noopener noreferrer"&gt;"testing repository"&lt;/a&gt;. The setup and link procedure is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/remshams/node-module-esm" rel="noopener noreferrer"&gt;Example Library&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://github.com/remshams/node-module-esm-test" rel="noopener noreferrer"&gt;Testing Repo&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;npm link&lt;/code&gt; to link to the locally available example library e.g. in case both projects are siblings in the folder structure the command is &lt;code&gt;npm link ../node-module-esm&lt;/code&gt; (a more detailed description can be found e.g. &lt;a href="https://medium.com/dailyjs/how-to-use-npm-link-7375b6219557" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm start&lt;/code&gt; (this starts a local http-server)&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;localhost:8080&lt;/code&gt; in the browser of your choice&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;src&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The then opened &lt;code&gt;index.html&lt;/code&gt; includes imports of &lt;code&gt;umd bundled&lt;/code&gt;, &lt;code&gt;esm bundled&lt;/code&gt; and &lt;code&gt;esm unbundled&lt;/code&gt; from the example library giving the following result:&lt;/li&gt;
&lt;/ul&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%2Fk6b8v0cousfvknp6xdkk.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%2Fk6b8v0cousfvknp6xdkk.png" alt="Screenshot testing index.html" width="265" height="311"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>npm</category>
      <category>babel</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>File replacements when building angular projects</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 16 Jan 2021 17:11:01 +0000</pubDate>
      <link>https://dev.to/remshams/replacing-configuration-files-in-angular-builds-based-on-build-targets-28jm</link>
      <guid>https://dev.to/remshams/replacing-configuration-files-in-angular-builds-based-on-build-targets-28jm</guid>
      <description>&lt;p&gt;This short article is about replacing files (e.g. configuration files) for different build configurations/targets (like &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;qa&lt;/code&gt; and &lt;code&gt;prod&lt;/code&gt;) in Angular. For our projects we used to leverage the Angular file replacements feature to provide different files based on the chosen build target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"production"&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;"fileReplacements"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.prod.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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/configuration.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/configuration.prod.json"&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;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fileReplacements"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.dev.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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/configuration.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/configuration.dev.json"&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;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"qa"&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;"fileReplacements"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.qa.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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/configuration.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/configuration.qa.json"&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;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;&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%2Flc5qys5eppnunnhemqat.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%2Flc5qys5eppnunnhemqat.png" alt="Folder structure for file replacement" width="185" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, file replacements outside of bundles were never officially supported by Angular and has ceased to work since the Angular 9 release as described &lt;a href="https://github.com/angular/angular-cli/issues/16779" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
We have migrated to the proposed workaround in the linked Github issue and it is working fine for us so far. In case someone has the same issue/question (and also to document the approach for myself ;) ), I have created a &lt;a href="https://github.com/remshams/angular-file-replacement" rel="noopener noreferrer"&gt;simple example repository&lt;/a&gt; showcasing the approach for a single &lt;code&gt;configuration.json&lt;/code&gt; file.&lt;br&gt;
The following section shows the required steps.&lt;/p&gt;
&lt;h1&gt;
  
  
  Configuration Folder
&lt;/h1&gt;

&lt;p&gt;In the example, a dedicated folder holding the different configurations has been created. This is not necessarily required but keeps the files organized. Next, each configuration target has an associated folder containing the &lt;code&gt;configuration.json&lt;/code&gt;. The additional folder is indeed required as otherwise it is not possible to select and copy the correct file (described in the next section).&lt;br&gt;
At the end it looks something like the following:&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%2Fdddf0e70oypws8rg9j4v.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%2Fdddf0e70oypws8rg9j4v.png" alt="Folder structure for file assets replacement" width="169" height="172"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Angular CLI configuration file (angular.json)
&lt;/h1&gt;

&lt;p&gt;As shown in the snippet below, for each of the deployment configurations the associated &lt;code&gt;configuration.json&lt;/code&gt; is copied as part of the &lt;code&gt;assets&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"production"&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;"assets"&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;"src/favicon.ico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"src/assets"&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;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configuration/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*.json"&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;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configuration/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&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;span class="nl"&gt;"fileReplacements"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.prod.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="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;"dev"&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;"assets"&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;"src/favicon.ico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"src/assets"&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;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configuration/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*.json"&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;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configuration/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&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;span class="nl"&gt;"fileReplacements"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.dev.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="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;"qa"&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;"assets"&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;"src/favicon.ico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"src/assets"&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;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations/qa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configuration/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*.json"&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;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/configurations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configuration/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&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;span class="nl"&gt;"fileReplacements"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"with"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/environments/environment.qa.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="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="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;By means of the created subfolders in the configuration folder, the correct &lt;code&gt;configuration.json&lt;/code&gt; file can be selected and copied. With help of the &lt;code&gt;output&lt;/code&gt; property the path within the &lt;code&gt;dist&lt;/code&gt; folder is defined. For the example, it is copied to a configuration folder in the root path. In addition a &lt;code&gt;README.md&lt;/code&gt; is put next to the &lt;code&gt;configuration.json&lt;/code&gt; to describe its properties and their effect on the application. Creating the dedicated folder helps to keep the two files next to each other.&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%2Fn5w4zjneay8u2abff07b.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%2Fn5w4zjneay8u2abff07b.png" alt="Angular dist folder with configuration files" width="184" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I don't like about the approach is, that we now have to duplicate the &lt;code&gt;assets&lt;/code&gt; properties for all build configurations as otherwise e.g. the &lt;code&gt;assets&lt;/code&gt; folder (images, fonts, translations and the like) does not get copied. Also, having to create a dedicated subfolder is also not as convenient as it was with the file replacement (although this is more a nuisance than a major drawback).&lt;/p&gt;

&lt;p&gt;In case you have a better idea (or a solution) for solving the duplication, I'd love to hear about it. Otherwise I hope it can be beneficial for someone.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>question</category>
    </item>
    <item>
      <title>Reactive Angular components with presenters - Part 2</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 09 Jan 2021 10:04:58 +0000</pubDate>
      <link>https://dev.to/remshams/reactive-angular-components-with-presenters-part-2-5g29</link>
      <guid>https://dev.to/remshams/reactive-angular-components-with-presenters-part-2-5g29</guid>
      <description>&lt;p&gt;In the first part of the article we looked at the issue of slow running (component) unit tests in one of our projects. After having discussed different approaches for improving the execution time, moving business logic out of the affected components has been chosen as the preferred solution. Based on the derived requirements for the (new) component structure, the main ideas of a Flutter BLoc and Mode-View-Presenter inspired component structure have been explained.&lt;/p&gt;

&lt;p&gt;In contrast to the more theoretical discussion in part one, part two focuses on showing the approach in practice by means of a simple example application. This will then enable us to assess the new found component structure in regard to the requirements formulated in part one.&lt;/p&gt;

&lt;h1&gt;
  
  
  Example application
&lt;/h1&gt;

&lt;p&gt;As it is often the case with these (simpler) applications it cannot showcase all elements and subtleties found in real projects without loosing focus on the main idea. However it should serve a good overview for how a presenter based component implementation can look like.&lt;/p&gt;

&lt;p&gt;The main feature of the example application is to show a list of user names. In case of interest, a running version can be seen &lt;a href="https://remshams.github.io/component-presenter" rel="noopener noreferrer"&gt;here&lt;/a&gt; The component has been implemented twice which allows for a direct comparison of two variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first variant contains all the "logic" in the component controller, reflecting our "old" approach&lt;/li&gt;
&lt;li&gt;For the second variant the logic is taken care of by a presenter, reflecting the "new" approach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, a quick overview and explanation of the relevant parts is given. In case you prefer reading code to text you can find it &lt;a href="https://github.com/remshams/component-presenter" rel="noopener noreferrer"&gt;here&lt;/a&gt; and directly jump to the results section.&lt;br&gt;&lt;br&gt;
The rest of us will start with the "Architecture" overview.&lt;/p&gt;
&lt;h2&gt;
  
  
  Architecture
&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%2Fgithub.com%2Fremshams%2Fcomponent-presenter%2Fblob%2Fassets%2Fimages%2Farchitecture.jpeg%3Fraw%3Dtrue" 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%2Fgithub.com%2Fremshams%2Fcomponent-presenter%2Fblob%2Fassets%2Fimages%2Farchitecture.jpeg%3Fraw%3Dtrue" alt="Example app components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;UsersRestAdapter&lt;/code&gt;: &lt;code&gt;Interface&lt;/code&gt; for requesting the user list from the server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProductionUserRestAdapter&lt;/code&gt;: &lt;code&gt;Service&lt;/code&gt; implementation of &lt;code&gt;UserRestAdapter&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Using an interface has been done on purpose as it allows for "mocking" the adapter for depending services/components like &lt;code&gt;UsersService&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UsersService&lt;/code&gt;: Manages/encapsulates the global user state as an Angular service.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;list&lt;/code&gt; all users&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refresh&lt;/code&gt; the list of users&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UsersComponent&lt;/code&gt;: Shows the list of usernames.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UsersPresenter&lt;/code&gt;: &lt;code&gt;Service&lt;/code&gt; managing the state of the &lt;code&gt;UsersWithPresenterComponent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UsersWithPresenterComponent&lt;/code&gt;: Shows the list of usernames using an presenter for component logic and state management.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UsersCounterComponent&lt;/code&gt;: Shows the number of users.

&lt;ul&gt;
&lt;li&gt;This has been put into a dedicated component on purpose as it shows how a presenter can be used for sharing overarching state and thus avoiding prop drilling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Other files not relevant for the discussion itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As described &lt;code&gt;UsersComponent&lt;/code&gt; and &lt;code&gt;UsersWithPresenterComponent&lt;/code&gt;, both implement the same user interface and features to enable a direct comparison.&lt;/p&gt;
&lt;h1&gt;
  
  
  Elements
&lt;/h1&gt;

&lt;p&gt;The section will give some implementation details for the elements relevant for the discussion in this article.&lt;br&gt;&lt;br&gt;
Classes/files not important for the approach are not covered.&lt;/p&gt;

&lt;p&gt;We will also define the required test categories for each discussed component/service, as testing, especially test performance, plays an important role in this article.&lt;br&gt;
As a quick reminder the two categories are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tests targeted at the ui (template required) --&amp;gt; slower&lt;/li&gt;
&lt;li&gt;Test targeted at business logic in the component (no template required) --&amp;gt; faster&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  UsersComponent
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;UsersComponent&lt;/code&gt; uses the &lt;code&gt;Angular Material UI&lt;/code&gt; library to display a simple list of users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userNames$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userCount$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userNames$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCount$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupUserCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setupUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extractUserNames&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setupUserCount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extractNumberOfUsers&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;As mentioned in &lt;code&gt;Architecture&lt;/code&gt; the main functionality of the component is to display a list of usernames.&lt;br&gt;&lt;br&gt;
The list is created by subscribing to the &lt;code&gt;users$&lt;/code&gt; Observable in the global &lt;code&gt;UsersService&lt;/code&gt;. As the component is only interested in the list of names, it creates a new Observable by &lt;code&gt;mapping&lt;/code&gt; over the global &lt;code&gt;users$&lt;/code&gt; list to extract the usernames from the &lt;code&gt;User&lt;/code&gt; objects (done by the &lt;code&gt;setupUsers&lt;/code&gt; method called in the constructor).&lt;br&gt;&lt;br&gt;
The &lt;code&gt;userCount$&lt;/code&gt; property uses the same approach for extracting the number of users.&lt;br&gt;
For the sake of simplicity, a refresh of the global users list is triggered once the component gets initialized. This ensures that users are available in the &lt;code&gt;UsersService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The associated component template subscribes to the list by employing the build-in &lt;code&gt;async&lt;/code&gt; pipe. Subsequently, it iterates over the usernames and displays each in a &lt;code&gt;material-list&lt;/code&gt;/&lt;code&gt;material-list-item&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The user count is displayed by simply subscribing to the &lt;code&gt;userCount$&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"userNames$ | async as userNames"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mat-list&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;mat-subheader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;List&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-list-item&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"userNames__element"&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let userName of userNames"&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{userName}}&lt;span class="nt"&gt;&amp;lt;/mat-list-item&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;mat-subheader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Count&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-list-item&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"userNames__count"&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Number of Users: {{userCount$ | async}}&lt;span class="nt"&gt;&amp;lt;/mat-list-item&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/mat-list&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;As ui and business logic concerns are mixed in the component, both test categories are represented. This is exactly the type of component which has been deemed problematic for our project as it performs template compilation for both test categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  UsersWithPresenterComponent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-users-presenter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UsersPresenter&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersWithPresenterComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersPresenter&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;The functionality is equivalent to the one in &lt;code&gt;UserComponent&lt;/code&gt;. The main difference is that all the implementation required for loading and converting the list of users has been moved to the &lt;code&gt;UsersPresenter&lt;/code&gt;. By adding the latter to the list of component &lt;code&gt;providers&lt;/code&gt; and making it part of the constructor, the template can directly subscribe to the public &lt;code&gt;userNames$&lt;/code&gt; property in the presenter.&lt;/p&gt;

&lt;p&gt;As mentioned in the beginning, a dedicated component &lt;code&gt;UserCount&lt;/code&gt; is leveraged to display the number of users. Although this would not necessarily be required in a "real" application (due to the low complexity), it shows how prop drilling can be avoided by injecting the presenter in deeper levels of the component tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"presenter.userNames$ | async as userNames"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mat-list&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;mat-subheader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;List&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-list-item&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"userNames__element"&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let userName of userNames"&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{userName}}&lt;span class="nt"&gt;&amp;lt;/mat-list-item&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;mat-subheader&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Count&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-list-item&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;app-user-counter&amp;gt;&amp;lt;/app-user-counter&amp;gt;&amp;lt;/mat-list-item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/mat-list&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;Having most of the logic now extracted to the &lt;code&gt;UsersPresenter&lt;/code&gt; leaves only template related functionalities in the component itself. As a consequence, all category two tests can be covered in the presenter tests and template compilation is only performed for ui tests (category one) where it is indeed required.&lt;br&gt;&lt;br&gt;
This is exactly what we wanted to achieve with the new structure in regard to testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  UsersPresenter
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersPresenter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userNames$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userCount$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userNames$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupUserNames&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCount$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupUserCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onInit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setupUserNames&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extractUserNames&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setupUserCount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extractNumberOfUsers&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;onInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshUsers&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;The &lt;code&gt;UsersPresenter&lt;/code&gt; encapsulates the implementation logic that has been extracted from &lt;code&gt;UsersWithPresenterComponent&lt;/code&gt;. It makes the list of users accessible to the component via the public &lt;code&gt;userNames$&lt;/code&gt; property (in the same way as &lt;code&gt;UsersComponent&lt;/code&gt; where it is located in the component controller itself).&lt;br&gt;&lt;br&gt;
The &lt;code&gt;UsersPresenter&lt;/code&gt; already gives an impression how global state (users list) can be declaratively processes/combined with local state when both use the same underlaying, reactive foundation (&lt;code&gt;RxJs&lt;/code&gt; in our case). With &lt;code&gt;NgRx&lt;/code&gt;, as another example, a selector would be used instead of directly accessing the &lt;code&gt;users$&lt;/code&gt; property in &lt;code&gt;UsersService&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;As the presenter is a service it only contains category two tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  UserCountComponent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCounterComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersPresenter&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;The &lt;code&gt;UserCountComponent&lt;/code&gt; can leverage the &lt;code&gt;UsersPresenter&lt;/code&gt; to display the number of users. This showcases how presenters, injected deeper in the component tree, can be an alternative to using &lt;code&gt;@Input&lt;/code&gt; properties for passing data.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;UserPresenter&lt;/code&gt; is available here, as &lt;code&gt;UserCounterComponent&lt;/code&gt; is a child node in the template of &lt;code&gt;UsersComponent&lt;/code&gt;. Worth mentioning may be, that it does not have to be a direct child.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;The component contains no business logic and therefor only category one tests are applicable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Results
&lt;/h1&gt;

&lt;p&gt;With the example application implemented it is now possible to see if component presenters can actually help to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decrease unit test time for components and component related business logic&lt;/li&gt;
&lt;li&gt;improve components and components structure&lt;/li&gt;
&lt;li&gt;share common logic/state in case appropriate&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unit test time
&lt;/h2&gt;

&lt;p&gt;All implementations that have been located in the component and factored out can now be tested in isolation. This reduces the number of tests performing template compilation leading to a reduced test time.&lt;br&gt;
At first glance it does look like a lot of effort for a few &lt;code&gt;ms&lt;/code&gt; e.g. for the &lt;code&gt;should emit list of user names&lt;/code&gt; test in the captured test run. However, these small improvements in run time do add up when the test suite size increases.&lt;br&gt;&lt;br&gt;
So the decreased test run time looks (even if only a few &lt;code&gt;ms&lt;/code&gt;) promising. It should be mentioned though, that the effect may be lower when the complexity of the test itself increases, reducing the "impact" of template compilation.&lt;br&gt;&lt;br&gt;
The complete html report of the test run can be found in the &lt;code&gt;test-reports&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;For our (real) project we could not make a direct before/after comparison as the migration is still ongoing. We are doing a kind of "on-touch" refactoring (instead of a big bang) to strike the balance between new features and code improvements. Nevertheless, we did make some measurements for our more complex components and saw improvements in test time.&lt;br&gt;
For the project (in contrast to the example application) the component tests have been removed all together, so only the ones for the presenters are left. After maintaining the former for some time we did not see any additional benefits as the template part is tested by e2e tests. This is/was just our experience so your mileage may vary here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lightweight, modularized and encapsulated components
&lt;/h2&gt;

&lt;p&gt;Even though the &lt;code&gt;UsersComponent&lt;/code&gt; and &lt;code&gt;UsersWithPresenterComponent&lt;/code&gt; are of low complexity, the simple example already shows the improvements of separating the "behind-the-scenes" implementation to a dedicated presenter. Not only does this lead to a component with almost no additional code (besides what is required for the Angular framework). It also separates the ui/template related implementations from the more involved state handling/orchestration concerns.&lt;/p&gt;

&lt;p&gt;Based on our experience so far, we formulated three structural elements for our projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementations e.g. global services, RxJs... for global state&lt;/li&gt;
&lt;li&gt;Presenters for component state and/or business logic (implemented as services provided by the component)&lt;/li&gt;
&lt;li&gt;Components concerned with the user interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three building blocks not only help us to make our components simpler (in case required multiple component presenters are used). We also made good experiences when introducing new team members as the three categories are a guideline where an implementation should be located.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing business logic and state
&lt;/h2&gt;

&lt;p&gt;Although somehow artificial (as hard to do otherwise in a simple example) the added &lt;code&gt;UsersCount&lt;/code&gt; component shows how a presenter provided at a higher level in the component tree can be shared/reused at a lower level. One can probably imagine how this can be applied to avoid e.g. prop drilling when the tree height increases.&lt;/p&gt;

&lt;p&gt;For our project, prop drilling and duplicated component state/business logic was/is not really an issue as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we heavily make us of generic components which take configurations as &lt;code&gt;@Input&lt;/code&gt; properties and therefor manage state independently&lt;/li&gt;
&lt;li&gt;shared business logic was and is factored into pure and shared plain old JavaScript functions&lt;/li&gt;
&lt;li&gt;global state and business logic is covered by &lt;code&gt;NgRx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bonus - Change Detection
&lt;/h2&gt;

&lt;p&gt;In the beginning of the article it has been mentioned, that presenters can be beneficial for change detection when completely based on Observables.&lt;br&gt;&lt;br&gt;
This is not necessarily required but opens up the possibility to enable the &lt;code&gt;onPush&lt;/code&gt; change detection strategy for additional performance benefits.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;h2&gt;
  
  
  ...for the pattern
&lt;/h2&gt;

&lt;p&gt;Time for a recap:&lt;/p&gt;

&lt;p&gt;We started the journey with the problem of slow running unit tests and looking for solutions potentially reducing the execution time. Moving non template related functionalities out of the component came out as our favorite option. It also opened up an opportunity to improve our component structure leading to additional requirements.&lt;/p&gt;

&lt;p&gt;After some theory about the patterns inspiring the new found approach, we looked at a simple example application implementing the same component feature (displaying a list of users) twice. This allowed a before/after comparison not possible in our real project for practical reasons.&lt;/p&gt;

&lt;p&gt;As a final result the newly employed pattern could be shown as beneficial for our requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lightweight, modularized and encapsulated components&lt;/li&gt;
&lt;li&gt;sharing of local state and business logic&lt;/li&gt;
&lt;li&gt;unit test time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end one could state that our initial problem (unit test times) was more solved as a side effect of the newly imposed presenter based structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  for the Project
&lt;/h2&gt;

&lt;p&gt;In our project we have (up to this point) made good experiences, both for new and refactored components.&lt;br&gt;&lt;br&gt;
We are using &lt;code&gt;NgRx&lt;/code&gt; for global state- and (now) presenters for local state management. As both &lt;code&gt;NgRx&lt;/code&gt; as well as our implementations of presenters are completely based on Observables, the global and local state can be combined or &lt;code&gt;piped&lt;/code&gt; pretty easily.&lt;/p&gt;

&lt;p&gt;What we really like about it is the clear structure it provides in combination with simplified components and testing. It does require some learning and "getting used to" due to being completely based on Observables.&lt;br&gt;&lt;br&gt;
However, we do not consider this a drawback. The Angular framework and libraries are already heavily relying on Observables (e.g. when looking at the &lt;code&gt;HttpClient&lt;/code&gt;, the &lt;code&gt;RoutingModule&lt;/code&gt; or libraries like &lt;code&gt;NgRx&lt;/code&gt;), so learning their usage is kind of a requirement. And almost every framework, library... needs some time and effort to become proficient in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  NgRx component
&lt;/h2&gt;

&lt;p&gt;Why has &lt;a href="https://ngrx.io/guide/component" rel="noopener noreferrer"&gt;@ngrx/component&lt;/a&gt; not been considered?.&lt;br&gt;&lt;br&gt;
The simple reason is, that it was not yet ready/available.&lt;br&gt;
Otherwise, as we are using &lt;code&gt;NgRx&lt;/code&gt;, it would have been a compelling alternative as it gives similar advantages in regard to testing and component/application structure with additional benefits like component based &lt;code&gt;selectors&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
We will definitely consider it for future projects where &lt;code&gt;NgRx&lt;/code&gt; is employed.&lt;/p&gt;

&lt;p&gt;The availability of &lt;code&gt;@ngrx/component&lt;/code&gt; does, in my opinion, not make the here described approach superfluous. Not all projects use &lt;code&gt;NgRx&lt;/code&gt; so in case an approach only based on Angular primitives (&lt;code&gt;Providers&lt;/code&gt;, &lt;code&gt;Services&lt;/code&gt; and &lt;code&gt;Observables&lt;/code&gt;) is needed, the MVP pattern and especially presenters can be an option with similar benefits (depending on how it is implemented).&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Reactive Angular components with presenters - Part 1</title>
      <dc:creator>Mathias Remshardt</dc:creator>
      <pubDate>Sat, 09 Jan 2021 10:04:53 +0000</pubDate>
      <link>https://dev.to/remshams/reactive-angular-components-with-presenters-part-1-4ki9</link>
      <guid>https://dev.to/remshams/reactive-angular-components-with-presenters-part-1-4ki9</guid>
      <description>&lt;p&gt;This two part article focuses on implementing lightweight, reactive Angular components with &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter" rel="noopener noreferrer"&gt;MVP&lt;/a&gt; like presenters.&lt;/p&gt;

&lt;p&gt;In the first part we will look how slow running unit tests has lead to new requirements for our component structure in one of our projects. We will next see how and why the solution, described in theory and practice, has been chosen.&lt;/p&gt;

&lt;p&gt;In the second part, a simple example application shows the new structure in action and helps to highlight the most relevant parts. This will then enable us to assess, if our solution could fulfill the requirements and expectations set at the outset.&lt;/p&gt;

&lt;p&gt;Before getting started, in case not already clear from the description/title, it should be mentioned that the article is more focused on the details of structuring/implementing a single Angular component. Therefor, it will probably not provide much benefit when looking for solutions on how to structure multiple components from a global/application point of view.&lt;/p&gt;

&lt;h1&gt;
  
  
  The pain - Slow running unit tests
&lt;/h1&gt;

&lt;p&gt;As one of our last project grew larger, we faced the issue of an increasingly slow running unit test suite. Further investigations revealed our Angular component unit tests as one of the major reasons for the increasing unit test time. These seemed to be slow due to the required &lt;code&gt;compile&lt;/code&gt; step triggered by &lt;code&gt;compileComponents&lt;/code&gt;&lt;br&gt;
This is fine for testing template related functionalities like the state a certain html element is in but not for e.g. state related tests.&lt;br&gt;
For a loading spinner, as an example, there are (at least) two categories that tests could be written for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A test validating that the spinner shows/hides when e.g. a &lt;code&gt;loading&lt;/code&gt; flag is set to &lt;code&gt;true/false&lt;/code&gt; (template/ui)&lt;/li&gt;
&lt;li&gt;A unit test validating that the &lt;code&gt;loading&lt;/code&gt; flag is in the right state e.g. when a backend call is pending or not (business logic)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first test category requires the compilation step. For the second test it only adds delay which, in case there are a lot of these tests, can lead to a slow down of the complete test suite.&lt;/p&gt;

&lt;p&gt;In our project we had a high ratio of component state related (category two) to template (category one) tests, even though core business logic has already been factored out to "helper" classes/services and the like. So for most test cases the template compilation was not required, making the problem even worse.&lt;/p&gt;

&lt;h1&gt;
  
  
  The ideas
&lt;/h1&gt;

&lt;p&gt;Based on the problem description from above we'd like to perform the compilation process only for tests requiring a template. This could be achieved by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;only writing &lt;strong&gt;Integration Tests&lt;/strong&gt; for these functionalities (e.g. using Cypress)&lt;/li&gt;
&lt;li&gt;having &lt;strong&gt;Dedicated Tests&lt;/strong&gt; skipping the compilation process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moving the functionality&lt;/strong&gt; (and therefore the tests) out of the component&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Integration Tests
&lt;/h2&gt;

&lt;p&gt;Completely relying on integration tests can work. However, there is a possibility for these tests to quickly grow large/complex in case the tested functionality is more involved than a loading spinner.&lt;/p&gt;

&lt;p&gt;In addition, multiple test scenarios could lead to the same result(s) e.g. the loading spinner being hidden. The test would need to perform additional checks like e.g. a side effect (could be a backend call) or another element being displayed (e.g. an error message). As we like to treat our integration tests as black box tests the latter was not really an option for us.&lt;/p&gt;

&lt;p&gt;With all this additional complexity and, especially effort, comes an inherent risk, that not all use cases/code branches will be covered (things happen when the going gets tough...)&lt;br&gt;&lt;br&gt;
More importantly all integration tests suffer from the same issue of not being as fast as unit tests (probably even slower than Angular component tests) rendering these invalid for solving our problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dedicated test suite/test file
&lt;/h2&gt;

&lt;p&gt;Why triggering compilation for tests not querying the template?&lt;/p&gt;

&lt;p&gt;An option would be to move the compilation step out of the &lt;code&gt;beforeEach&lt;/code&gt; block into a dedicated method which is only called when the template is required for testing.&lt;br&gt;
Another alternative could be to have these tests in a separate test file which does not compile the template and directly calls the component constructor (similar how &lt;code&gt;Services&lt;/code&gt; or &lt;code&gt;Pipes&lt;/code&gt; are tested).&lt;/p&gt;

&lt;p&gt;The proposed solution avoids the overhead created by the compilation process. In case needed the customized test file generation could be simplified by writing a schematic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving functionalities
&lt;/h2&gt;

&lt;p&gt;The approach is similar to moving the tests into a dedicated file. It takes the idea even further by „separating“ the complete functionality from the component itself and moving it to a dedicated &lt;code&gt;Service&lt;/code&gt; or JavaScript &lt;code&gt;Module&lt;/code&gt;.&lt;br&gt;
As this new service/module would not have any template, the issue of compilation would be gone.&lt;/p&gt;

&lt;p&gt;As an additional benefit, moving the implementation out of the component makes it more lightweight. In case free of core business logic by means of state management solutions (being it „simple“ &lt;code&gt;Services&lt;/code&gt;or a dedicated library like &lt;code&gt;NgRx&lt;/code&gt;) the component only contains view related properties (like the &lt;code&gt;isLoading&lt;/code&gt; flag for the described loading spinner example).&lt;/p&gt;

&lt;p&gt;For that additional benefit the option looked most appealing and was chosen for our project. We not only figured that it can solve our initial problem (slow running unit tests) but also be an opportunity to bring more structure to the components and application.&lt;/p&gt;

&lt;h1&gt;
  
  
  The new structure
&lt;/h1&gt;

&lt;p&gt;Components should already be lightweight/free of business logic in case a proper state management solution is in use. Nevertheless, we have experienced that, despite using &lt;code&gt;NgRx&lt;/code&gt; for dealing with global state, the orchestration as well as the required component related implementations can grow quite substantial for some components. Also, not every state (at least for us) is supposed to be global state and putting all that (transient) state into the component lead to our testing and structure issues in the first place.&lt;br&gt;&lt;br&gt;
For that reason we were looking for a solution filling the gap between managing global state and more complex local state/business logic (maybe even shared between multiple components).&lt;/p&gt;

&lt;p&gt;So we were looking for an approach that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reduces our unit test time for Angular components&lt;/li&gt;
&lt;li&gt;creates more lightweight components&lt;/li&gt;
&lt;li&gt;improves encapsulation and modularization for components&lt;/li&gt;
&lt;li&gt;enables sharing parts of the logic between component siblings and/or descendant if and only if it makes sense&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having settled on the idea of factoring out logic and state from our components (as described in the previous part) we iterated a few times until we reached our current structure. In hindsight, our final solution was inspired by a combination of the Flutter BLoc- and MVP pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flutter BLoc pattern
&lt;/h2&gt;

&lt;p&gt;At the time I had been investigating Flutter as an option/replacement for our non native mobile solutions (in case requested by clients). The BLoc pattern is one of the available (and popular) options for managing (global) state in Flutter. As it is not required for this article to deeply go into the implementation details here is my short summary (no claim to completeness):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B&lt;/strong&gt;usiness &lt;strong&gt;l&lt;/strong&gt;ogic &lt;strong&gt;c&lt;/strong&gt;omponents are a lightweight approach for managing state in a reactive/-event driven fashion. The reactivity within the bloc pattern is achieved by using &lt;code&gt;Streams&lt;/code&gt; or &lt;code&gt;Observables&lt;/code&gt;. Some implementations introduce the notion of &lt;code&gt;Events/Actions&lt;/code&gt; (similar to &lt;code&gt;Redux&lt;/code&gt;) triggering effects and/or state changes. (more details can be found e.g. &lt;a href="https://medium.com/codechai/architecting-your-flutter-project-bd04e144a8f1" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In my Flutter applications I used it for global state management. However, I had (some) of the same issues with Flutter widgets (widgets are similar to components) as discussed in the previous section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;testing widgets is more involved and slower (although faster then Angular component tests)&lt;/li&gt;
&lt;li&gt;widgets can grow complex in regard to state and business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the Flutter applications, I somehow solved it by using "BLocs" for local state as well. So each widget, with enough complexity justifying it, is associated with its own BLoc containing the state and business logic (provided either by prop passing or &lt;code&gt;InheritedWidgets&lt;/code&gt;).&lt;br&gt;&lt;br&gt;
I should mention however that I have always kept my BLocs simple instead of implementing these "by the book": So plain old classes which expose state as streams and updates are trigger by simple functions calls on these BLocs (so no notion of events and the like), keeping the overhead pretty low.&lt;/p&gt;

&lt;p&gt;It served me well in regard to solving the issues for my Flutter applications. What I particularly liked about the approach was the reactivity it provided for the presentational layer in regard to state updates, similar to what we get from &lt;code&gt;NgRx&lt;/code&gt; for global state in Angular.&lt;br&gt;&lt;br&gt;
So inspired by that we moved all the component related business logic into an associated service. As we are using &lt;code&gt;NgRx&lt;/code&gt;, core business logic was already been taken care of. In hindsight, what we came up with in the end is pretty close to presenters from the MVP pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MVP pattern
&lt;/h2&gt;

&lt;p&gt;Initially we named the new services classes &lt;code&gt;ComponentBlocs&lt;/code&gt;. However, I wasn't really satisfied with this term because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;our component "BLocs" never implemented the interface described by most BLoc related articles/libraries (e.g. we had no notion of &lt;code&gt;Events&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;we are not managing global state or core business logic in these classes&lt;/li&gt;
&lt;li&gt;it somehow "felt" wrong ;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Later, when (coincidentally) watching the &lt;a href="https://www.youtube.com/watch?v=D_ytOCPQrI0&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;introductory talk&lt;/a&gt; by Lars Gyrup Brink Nielsen about &lt;code&gt;Model-View-Presenter&lt;/code&gt; in Angular, I saw a similar structure and idea in there (at least I think so). It is not exactly the same to what we came up with e.g. we do not always have presentational components. However, it is close enough so that MVP and especially &lt;code&gt;Presenter&lt;/code&gt; seems to be a good fit for our component associated services.&lt;/p&gt;

&lt;p&gt;What is/was important to us (brought over by the BLoc pattern) is, that it should enable our components to react to state and state updates managed by the presenters. This is especially the case when used in combination with &lt;code&gt;NgRx&lt;/code&gt; as it then, due to both being based on reactive principles, allows for a seamless integration of global and local state.&lt;br&gt;&lt;br&gt;
Today I like to use the term &lt;code&gt;Reactive Presenter&lt;/code&gt; although this may not be exactly true since it is not only the presenter being reactive but also it's clients (usually Angular components).&lt;br&gt;&lt;br&gt;
As &lt;code&gt;reactive&lt;/code&gt; is a somehow loaded term and can mean different things for different people, I will stick with just &lt;code&gt;Presenter&lt;/code&gt; for the remainder of the article. The important point I want to pass here is, that our presenters should enable reactivity, both for itself and its clients.&lt;/p&gt;

&lt;p&gt;As we now figured that our new component structure closely leans on the ideas of presenters in MVP, we need to answer the questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a presenter&lt;/li&gt;
&lt;li&gt;How can it be made reactive in Angular&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;The are already lots of resources out there describing the MVP pattern in general e.g. the &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;, including presenters. However, it does not seem to be too popular in the Angular realm (at least this was/is my impression).&lt;br&gt;
As mentioned, the &lt;a href="https://www.youtube.com/watch?v=D_ytOCPQrI0&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;talk&lt;/a&gt; and &lt;a href="https://indepth.dev/posts/1070/model-view-presenter-with-angular" rel="noopener noreferrer"&gt;article&lt;/a&gt; by Lars Gyrup Brink Nielsen make for a good starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it is used
&lt;/h2&gt;

&lt;p&gt;Presenters are implemented as Angular services/injectables and associated with the component using component &lt;code&gt;providers&lt;/code&gt;. This keeps the services and their states scoped to the instance of the component instead of being globally available like &lt;code&gt;Services&lt;/code&gt; e.g. provided in &lt;code&gt;root&lt;/code&gt;. Limiting the scope of presenters also binds their lifecycles to the providing component, coming in handy when having to perform e.g. clean up logic &lt;code&gt;onDestroy&lt;/code&gt;. It also nicely separates the states (in case there is any), so that multiple instances of the same component cannot interfere with one another.&lt;/p&gt;

&lt;p&gt;A component can have multiple presenters allowing state and state related logic being separated into different presenters, enforcing encapsulation.&lt;br&gt;&lt;br&gt;
On the contrary, a single presenter can be injected into multiple components, either for reusing business logic or sharing state. The latter can avoid prop drilling by injecting the top level presenter into a "leaf" component (similar e.g. React &lt;code&gt;Context&lt;/code&gt; can be used).&lt;/p&gt;

&lt;p&gt;To add support for reactive state updates (not a requirement in general) our presenters are completely based on Observables. This not only allows for declarative state orchestration (global and/or local) but also a seamless integration with other reactive Angular features like the &lt;code&gt;RoutingModule&lt;/code&gt; or state management solutions like &lt;code&gt;NgRx&lt;/code&gt;. As an additional benefit, it can give us some advantage in regard to change detection, which we will discuss later.&lt;/p&gt;

&lt;p&gt;To make the described setup more tangible we will now look at an example implementation in the second part of the article.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
