<?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: Emeka Elo-Chukwuma</title>
    <description>The latest articles on DEV Community by Emeka Elo-Chukwuma (@brunoelo).</description>
    <link>https://dev.to/brunoelo</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%2F435334%2F8af3920a-a221-459a-9b20-32724b9c8e22.jpg</url>
      <title>DEV Community: Emeka Elo-Chukwuma</title>
      <link>https://dev.to/brunoelo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brunoelo"/>
    <language>en</language>
    <item>
      <title>How to create an Angular library or package and publish on npm</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Tue, 19 Jul 2022 08:28:07 +0000</pubDate>
      <link>https://dev.to/brunoelo/how-to-create-an-angular-library-or-package-4c15</link>
      <guid>https://dev.to/brunoelo/how-to-create-an-angular-library-or-package-4c15</guid>
      <description>&lt;h2&gt;
  
  
  What are libraries?
&lt;/h2&gt;

&lt;p&gt;Libraries which are also known as packages are reusable codes that speed up development processes or add functionalities to our applications. They save time, energy and resources for developers.&lt;/p&gt;

&lt;p&gt;When building an Angular application, you may find yourself rewriting functionalities you implemented across your app or projects. That can seem counter productive and a solution to that is to refactor that functionality or feature into a library which would make it more reusable, maintainable and accessible. This article shows how to create libraries or packages for the angular ecosystem. Let's begin!&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%2Fc.tenor.com%2FhHtKxHoD0JcAAAAC%2Fmadara-madara-uchiha.gif" 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%2Fc.tenor.com%2FhHtKxHoD0JcAAAAC%2Fmadara-madara-uchiha.gif" alt="Start"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Angular framework (version 14)&lt;/li&gt;
&lt;li&gt;Node version ^14.15.5 || ^16.10.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to use a different angular version, you can check this angular and node version compatibility table made by &lt;a class="mentioned-user" href="https://dev.to/layzee"&gt;@layzee&lt;/a&gt; &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Just keep in mind that libraries built with higher versions of angular are not compatible with applications built with angular versions lower than that of the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the library
&lt;/h2&gt;

&lt;p&gt;We will be using the Angular CLI to set up a workspace where we will build the library and an angular application where we can check out the functionalities we built for the library. Let's name the workspace &lt;code&gt;library-app&lt;/code&gt; and create it with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new library-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When it's done, you can serve your application to see it running.&lt;br&gt;&lt;br&gt;
Enter the root directory of your new workspace and generate the library with the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;library-app
ng generate library ngx-stuff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, the name of our library is &lt;code&gt;ngx-stuff&lt;/code&gt;. This is going to be a library that just does stuff 🤯.&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%2Fc.tenor.com%2FR86NN7Zz6ZIAAAAC%2Fnice-clap.gif" 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%2Fc.tenor.com%2FR86NN7Zz6ZIAAAAC%2Fnice-clap.gif" alt="unimpressed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;ngx&lt;/code&gt; prefix is a convention to denote that the library can be used with Angular.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the command, a &lt;code&gt;projects/ngx-stuff&lt;/code&gt; folder with the structure below is created in the root directory.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;projects
└── ngx-stuff
    ├── src
    │   ├── lib
    │   │   ├── ngx-stuff.component.spec.ts
    │   │   ├── ngx-stuff.component.ts
    │   │   ├── ngx-stuff.module.ts
    │   │   ├── ngx-stuff.service.spec.ts
    │   │   └── ngx-stuff.service.ts
    │   ├── public-api.ts
    │   └── test.ts
    ├── .browserslistrc
    ├── tsconfig.json
    ├── karma.conf.js
    ├── ng-package.json
    ├── package.json
    ├── README.md
    ├── tsconfig.lib.json
    ├── tsconfig.lib.prod.json
    └── tsconfig.spec.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;lib&lt;/code&gt; folder contains the files where the library features are built.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;public-api.ts&lt;/code&gt; exposes the functions and utilities to be imported by other applications.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;package.json&lt;/code&gt; records important metadata about the library and is required before publishing to NPM. It also defines functional attributes of the library that npm uses to install dependencies and identify the entry point to our package.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;ng-packagr&lt;/code&gt; library is installed in the workspace and can be seen in the &lt;code&gt;package.json&lt;/code&gt; of our application.&lt;br&gt;&lt;br&gt;
The build output path for the library is added to the &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;angular.json&lt;/code&gt; file is modified by adding configuration for the generated library which basically maps the file paths in the library folder to properties in the json file.&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;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./node_modules/@angular/cli/lib/config/schema.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;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newProjectRoot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"projects"&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;"library-app"&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;"projectType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application"&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;span class="nl"&gt;"ngx-stuff"&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;"projectType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"library"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"root"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceRoot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff/src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"prefix"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"architect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"builder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@angular-devkit/build-angular:ng-packagr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"options"&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;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff/ng-package.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="nl"&gt;"configurations"&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;"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;"tsConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff/tsconfig.lib.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="nl"&gt;"development"&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;"tsConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff/tsconfig.lib.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;"defaultConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&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;"test"&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;"builder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@angular-devkit/build-angular:karma"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"options"&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;"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;"projects/ngx-stuff/src/test.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;"tsConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff/tsconfig.spec.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;"karmaConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects/ngx-stuff/karma.conf.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="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;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;blockquote&gt;
&lt;p&gt;Notice the different &lt;code&gt;projectType&lt;/code&gt; for the &lt;code&gt;ngx-stuff&lt;/code&gt; library and the &lt;code&gt;library-app&lt;/code&gt; application&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Building features in the library
&lt;/h2&gt;

&lt;p&gt;The type of functionality we want to build into a library is determined by the kind of library it is. There are component or ui libraries as well as utility libraries. Your library can also be both if you want.&lt;/p&gt;
&lt;h3&gt;
  
  
  Utility feature
&lt;/h3&gt;

&lt;p&gt;To build utility functions for our library, we create reusable functions in the &lt;code&gt;ngx-stuff.service.ts&lt;/code&gt; file.&lt;br&gt;
Let's create two functions called &lt;code&gt;doStuff&lt;/code&gt; that returns the string &lt;code&gt;stuff library&lt;/code&gt; and &lt;code&gt;doStuffWithInput&lt;/code&gt; that returns the string we pass to the function as an argument.&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="c1"&gt;// ngx-stuff.service.ts&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;Injectable&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="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="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NgxStuffService&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="nf"&gt;doStuff&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stuff library&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;doStuffWithInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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="kr"&gt;string&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;input&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;Now, we can instantly use these functions from the library in our application by injecting the library service as a dependency using the Angular 14 &lt;code&gt;inject()&lt;/code&gt; method&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="c1"&gt;// app.component.ts&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&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;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;NgxStuffService&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;projects/ngx-stuff/src/public-api&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;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-root&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;./app.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;./app.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&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="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;library-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;stuff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NgxStuffService&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stuff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stuff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doStuffWithInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stuff library with input&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;When we run our application, we can see the values we logged out in the browser console.&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1657537749576%2Ft407r2JbA.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1657537749576%2Ft407r2JbA.jpg" alt="ngxstufflibraryoutput.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Component feature
&lt;/h3&gt;

&lt;p&gt;To add a component feature to the library, we build the user-interface in the &lt;code&gt;ngx-stuff.component.ts&lt;br&gt;
&lt;/code&gt; file. We will create a reusable button that can be customized.&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="c1"&gt;// ngx-stuff.component.ts&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;,&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;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="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;ngx-stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;button class="custom" [ngClass]="customClass" [ngStyle]="customStyle"&amp;gt;
      {{ name }}
    &amp;lt;/button&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&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;button {color: blue;} .custom{background-color: yellow}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NgxStuffComponent&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="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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button stuff&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;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;customClass&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;=&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;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;customStyle&lt;/span&gt; &lt;span class="o"&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="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The field properties in the component class are bound to the attributes in the button. These properties have the &lt;code&gt;Input()&lt;/code&gt; decorator which allows the library to receive values from parent components(components where the library is imported).&lt;/p&gt;

&lt;p&gt;To use the &lt;code&gt;ngClass&lt;/code&gt; and &lt;code&gt;ngStyle&lt;/code&gt; attributes, the &lt;code&gt;commonModule&lt;/code&gt; package needs to be imported in the library's module.&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="c1"&gt;// ngx-stuff.module.ts&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;CommonModule&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/common&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;NgModule&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;NgxStuffComponent&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;./ngx-stuff.component&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;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;NgxStuffComponent&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;CommonModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;NgxStuffComponent&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;NgxStuffModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For this library component to be used in our application, we need to import the library's module in the application's NgModule.&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="c1"&gt;// app.module.ts&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;NgModule&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;BrowserModule&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/platform-browser&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;NgxStuffModule&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;projects/ngx-stuff/src/public-api&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;AppComponent&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;./app.component&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;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;NgxStuffModule&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="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;p&gt;Then we use it in our template with the &lt;code&gt;ngx-stuff&lt;/code&gt; selector&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;!-- app.component.html --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ngx-stuff&amp;gt;&amp;lt;/ngx-stuff&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ngx-stuff&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"new button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ngx-stuff&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ngx-stuff&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"custom class"&lt;/span&gt; &lt;span class="na"&gt;customClass=&lt;/span&gt;&lt;span class="s"&gt;"custom-class"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ngx-stuff&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ngx-stuff&lt;/span&gt; &lt;span class="na"&gt;customClass=&lt;/span&gt;&lt;span class="s"&gt;"new-class more-class"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ngx-stuff&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ngx-stuff&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"custom style"&lt;/span&gt; &lt;span class="na"&gt;[customStyle]=&lt;/span&gt;&lt;span class="s"&gt;"{backgroundColor:'white'}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ngx-stuff&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;style.css&lt;/code&gt; file contains styles for the custom button&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/** style.css **/&lt;/span&gt;
&lt;span class="nc"&gt;.custom-class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.more-class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;palevioletred&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;Results&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1657560334635%2Fh1piOoB1i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1657560334635%2Fh1piOoB1i.jpg" alt="librarybuttons.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the library
&lt;/h2&gt;

&lt;p&gt;Notice that the import path for the library looks a bit different, that's because we are importing the library locally relative to where we want to use it in our application. However, in our &lt;code&gt;tsconfig.json&lt;/code&gt;, the path has already been configured for the build path to map to a shorter string which is easier to understand.&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tsconfig.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="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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paths"&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;"ngx-stuff"&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;"dist/ngx-stuff"&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="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;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;So we'll build our library with the following command;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng build ngx-stuff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we change the import path in our application to &lt;code&gt;ngx-stuff&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="c1"&gt;// app.component.ts&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;NgxStuffService&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;ngx-stuff&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 typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.module.ts&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;NgModule&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;BrowserModule&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/platform-browser&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;NgxStuffModule&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;ngx-stuff&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;p&gt;So now, when we make any change to the library, we need to build it first before checking it out.&lt;/p&gt;
&lt;h2&gt;
  
  
  Publishing to NPM
&lt;/h2&gt;

&lt;p&gt;To publish a library or package to npm, a user account on npm platform is needed. You can &lt;a href="https://www.npmjs.com/signup" rel="noopener noreferrer"&gt;sign up here&lt;/a&gt; if you do not have an account.&lt;/p&gt;

&lt;p&gt;Now we need to log in to our npm account via the terminal on vscode using the following command;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm adduser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Answer the prompts for your username, password and email. You will also get another prompt to fill a one time password sent to your email. Once it's done, the terminal will show &lt;code&gt;Logged in as &amp;lt;username&amp;gt; on https://registry.npmjs.org/.&lt;/code&gt;&lt;br&gt;
You can also use the &lt;code&gt;npm whoami&lt;/code&gt; command which will return your username in the terminal to verify you are logged in.&lt;/p&gt;

&lt;p&gt;Build the library using the &lt;code&gt;ng build&lt;/code&gt; command then&lt;br&gt;
navigate to the build output folder using the command below&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;dist/ngx-stuff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Run the command below to publish the package to npm&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Yay! 🥳 you just published your library.&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%2Fc.tenor.com%2FgfcR46X_rm8AAAAC%2Fmadara-uchiha-ninja.gif" 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%2Fc.tenor.com%2FgfcR46X_rm8AAAAC%2Fmadara-uchiha-ninja.gif" alt="Enjoy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The published library built in this article can be found &lt;a href="https://www.npmjs.com/package/ngx-stuff" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
You can checkout the repository for the entire project.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/emekaelo" rel="noopener noreferrer"&gt;
        emekaelo
      &lt;/a&gt; / &lt;a href="https://github.com/emekaelo/library-app" rel="noopener noreferrer"&gt;
        library-app
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An angular application with a library project published to npm
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;LibraryApp&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;This project was generated with &lt;a href="https://github.com/angular/angular-cli" rel="noopener noreferrer"&gt;Angular CLI&lt;/a&gt; version 14.0.5.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Development server&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;ng serve&lt;/code&gt; for a dev server. Navigate to &lt;code&gt;http://localhost:4200/&lt;/code&gt;. The application will automatically reload if you change any of the source files.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Code scaffolding&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;ng generate component component-name&lt;/code&gt; to generate a new component. You can also use &lt;code&gt;ng generate directive|pipe|service|class|guard|interface|enum|module&lt;/code&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Build&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;ng build&lt;/code&gt; to build the project. The build artifacts will be stored in the &lt;code&gt;dist/&lt;/code&gt; directory.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running unit tests&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;ng test&lt;/code&gt; to execute the unit tests via &lt;a href="https://karma-runner.github.io" rel="nofollow noopener noreferrer"&gt;Karma&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running end-to-end tests&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;ng e2e&lt;/code&gt; to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Further help&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To get more help on the Angular CLI use &lt;code&gt;ng help&lt;/code&gt; or go check out the &lt;a href="https://angular.io/cli" rel="nofollow noopener noreferrer"&gt;Angular CLI Overview and Command Reference&lt;/a&gt; page.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/emekaelo/library-app" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


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

&lt;p&gt;Libraries are essential to the software development process and I hope this article has helped you understand how to build libraries or packages in Angular. Let me know if you have any comments or suggestions in the comment section and lastly, feel free to share the article so that others can learn. Happy publishing!&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;If you would like to connect with me, I'm available on;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord: &lt;code&gt;brunoelo#8120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="'https://twitter.com/brunoelo'"&gt;BrunoElo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>JavaScript concepts to remember</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Mon, 18 Jul 2022 07:22:26 +0000</pubDate>
      <link>https://dev.to/brunoelo/javascript-concepts-to-remember-52eh</link>
      <guid>https://dev.to/brunoelo/javascript-concepts-to-remember-52eh</guid>
      <description>&lt;p&gt;This article is just a piece of my notepad that outlines some JavaScript concepts I don't necessarily forget but still have to check on just to be sure 😅. One reason for this post is because I am more likely to reach out for my device (and check the internet) than a physical notepad or even a note app and another reason is the ease of sharing with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Memory Heap
&lt;/h3&gt;

&lt;p&gt;An unstructured region of memory where global variables and objects are stored.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Event loop
&lt;/h3&gt;

&lt;p&gt;This pulls functions out of the event or callback queue and places it in the call stack when it becomes empty.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Call Stack
&lt;/h3&gt;

&lt;p&gt;This represents the single thread provided for JavaScript code execution and keeps track of the operations to be executed. Whenever a function is finished, it is popped from the stack. The stack operates in a LIFO queue where the last function call in a function gets executed first.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Event queue
&lt;/h3&gt;

&lt;p&gt;This holds mostly async functions processed by the web APIs so that when they are ready to run, the event loop can pull from it and add to the callstack.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Closures
&lt;/h3&gt;

&lt;p&gt;This occurs when a function is being declared and returned in another function and this is done so that the inner function can have access to the scope of the outer function even after the outer function has been executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Hoisting
&lt;/h3&gt;

&lt;p&gt;This is the process where the JavaScript interpreter moves declaration of functions, variables or classes to the top o their scope prior to code execution&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Lexical Scope
&lt;/h3&gt;

&lt;p&gt;This is the region in which a block of code has access to the variables defined in that scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Promise
&lt;/h3&gt;

&lt;p&gt;A promise is an object representing the eventual completion or failure of an asynchronous operation. It is a special JavaScript object that initially has a &lt;strong&gt;pending state&lt;/strong&gt; with an &lt;em&gt;undefined&lt;/em&gt; value which when resolved, becomes a &lt;strong&gt;fulfilled state&lt;/strong&gt; with a &lt;em&gt;value&lt;/em&gt; as the result or becomes a &lt;strong&gt;rejected state&lt;/strong&gt; with an &lt;em&gt;error&lt;/em&gt; as the result.&lt;br&gt;
The promise object has methods like &lt;code&gt;then&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;finally&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Async/Await
&lt;/h3&gt;

&lt;p&gt;These keywords make handling asynchronous code more readable. The &lt;code&gt;async&lt;/code&gt; keyword makes a function return a promise while the &lt;code&gt;await&lt;/code&gt; keyword suspends further JavaScript code execution until the promise resolves.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>browser</category>
    </item>
    <item>
      <title>How browser parses webpage and constructs it</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Sun, 17 Jul 2022 08:14:01 +0000</pubDate>
      <link>https://dev.to/brunoelo/how-browser-rendering-works-concise-summary-300g</link>
      <guid>https://dev.to/brunoelo/how-browser-rendering-works-concise-summary-300g</guid>
      <description>&lt;p&gt;If you are curious about how browsers work or want to quickly prepare for your frontend interview 👀 then you have come to the right place. This article is basically from my notepad where I summarized the process of browser rendering while I was studying it myself. I felt it will be better to make it an article where I can easily find it for reference and also share with you. Alright, let's get straight to business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DNS Lookup
&lt;/h3&gt;

&lt;p&gt;This happens the first time a client navigates to a certain domain. The browser requests a DNS lookup and the server responds with an IP address which will likely be cached for a certain duration so that subsequent requests will be faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  TCP Handshake
&lt;/h3&gt;

&lt;p&gt;Once the IP address is known, the browser sets up a connection via a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/TCP_handshake"&gt;TCP-three way handshake&lt;/a&gt; and this technique is often referred to as "SYN, SYN-ACK, ACK"(SYNchronize, SYNchronize-ACKnowledgement, and ACKnowledge). This is done so that computers that want to communicate can negotiate the parameters of connection before transmitting data such as HTTP browser requests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The host, generally the browser, sends a TCP SYNchronize packet to the server. The server receives the SYN and sends back a SYNchronize-ACKnowledgement. The host receives the server's SYN-ACK and sends an ACKnowledge. The server receives ACK and the TCP socket connection is established.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  TLS Negotiation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/TLS"&gt;TLS&lt;/a&gt; negotiation is another handshake for establishing secure connection. This determines which cipher will be used to encrypt the communication, verifies the server and establishes that a secure connection is in place before beginning the actual data transfer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Response
&lt;/h2&gt;

&lt;p&gt;Once secure connection has been established, the browser makes a HTTP GET Requests and the response for this initial requests contains the first byte of data received.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TIME TO FIRST BYTE (TTFB)&lt;/strong&gt; - This is the time between when the user made the request and the receipt of the first packet of HTML which is usually 14kb of data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parse
&lt;/h2&gt;

&lt;p&gt;The browser turns the data it receives over the network into DOM and CSSOM which is used by renderer to paint a page on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the DOM tree
&lt;/h3&gt;

&lt;p&gt;The browser parses the HTML mark up by tokenization and builds the DOM tree. The tokens include opening and closing tags, attribute names and values. The browser keeps parsing the HTML even when it sees non-blocking resources like an image or CSS file but pauses parsing when it sees script tags without an async or defer attribute.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preload Scanner
&lt;/h3&gt;

&lt;p&gt;This is an optimization feature that reduces blockages by retrieving resources in the background so that by the time the HTML parser reaches the requested assets, it may have already been in flight or downloaded&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the CSSOM
&lt;/h3&gt;

&lt;p&gt;The browser converts the CSS rules into a map of styles by going through each rule set in the CSS, creating a &lt;em&gt;tree of nodes&lt;/em&gt; with parent, child and sibling relationship based on the CSS selectors. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Accessibility Object Model(AOM): the browser also builds an accessibility tree that assistive devices use to parse and interpret content. AOM is like a semantic version of the DOM.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Render
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Style
&lt;/h3&gt;

&lt;p&gt;The DOM tree and CSSOM tree are combined into a render tree then used to compute the layout of visible elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout
&lt;/h3&gt;

&lt;p&gt;This is the process by which the width, height and location of the nodes in the render tree are determined, as well as the size and position of objects on the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Paint
&lt;/h3&gt;

&lt;p&gt;The browser converts each box calculated in the layout phase to pixels on the screen drawing visual parts of an element like text colors, borders, shadows etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MDN Docs - &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/How_browsers_work"&gt;Populating the page: how browsers work&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;If you would like to connect with me, I'm available on;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord: &lt;code&gt;brunoelo#8120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/brunoelo"&gt;BrunoElo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Building password validation with strength meter in React with hooks</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Sat, 16 Jul 2022 14:49:13 +0000</pubDate>
      <link>https://dev.to/brunoelo/building-password-validation-with-strength-meter-in-react-with-hooks-2mi6</link>
      <guid>https://dev.to/brunoelo/building-password-validation-with-strength-meter-in-react-with-hooks-2mi6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When building applications, you cannot avoid handling authentication and one of the ways to handle authentication is by receiving user data via a sign up or registration form and such forms contain passwords. You don't just want your users to use strong passwords that meet certain criteria but also visually inform them of how strong their passwords are during account creation.&lt;br&gt;&lt;br&gt;
In as much as password validation is done on the backend, the frontend validation helps guide the user in sending what the backend expects which ensures that your users as well as your systems are more secure. This article will show how to implement password validation from scratch(no library) as well as show the strength of the current password as the user types.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is a stackblitz demo of what we will be building.&lt;br&gt;
&lt;iframe src="https://stackblitz.com/edit/react-ts-oa8gu4?embed=1&amp;amp;file=App.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Password validation criteria
&lt;/h2&gt;

&lt;p&gt;For users to fulfill our "&lt;em&gt;mysterious&lt;/em&gt;"🪄 validation criteria, their passwords must contain;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One uppercase character&lt;/li&gt;
&lt;li&gt;One lowercase character&lt;/li&gt;
&lt;li&gt;One numeric character&lt;/li&gt;
&lt;li&gt;One special character&lt;/li&gt;
&lt;li&gt;Eight or more characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or else,&lt;br&gt;
&lt;a href="https://i.giphy.com/media/njYrp176NQsHS/giphy-downsized-large.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/njYrp176NQsHS/giphy-downsized-large.gif" alt="You shall not pass" width="480" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will be using these regex patterns in the code snippet below to handle the validation:&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;atLeastOneUppercase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// capital letters from A to Z&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;atLeastOneLowercase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// small letters from a to z&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;atLeastOneNumeric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// numbers from 0 to 9&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;atLeastOneSpecialChar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;#?!@$%^&amp;amp;*-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// any of the special characters within the square brackets&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eightCharsOrMore&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/.&lt;/span&gt;&lt;span class="se"&gt;{8,}&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// eight characters or more&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling component state
&lt;/h2&gt;

&lt;p&gt;State handling is inevitable and gladly a lot more easier with React hooks. Let's outline the states to track.&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;meter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMeter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;meter&lt;/code&gt;: This handles the visibility of the password strength meter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;password&lt;/code&gt;: This takes care of the actual password the user types into the password field.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;passwordTracker&lt;/code&gt;: Just a local variable that stores all the characters that pass a validation criteria as well as each criteria that they pass. It does so by storing the return value of the &lt;code&gt;match()&lt;/code&gt; method(which is an array of the passing character(s)) to the property in the &lt;code&gt;passwordTracker&lt;/code&gt; object  that corresponds with the validation criteria.&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;passwordTracker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;atLeastOneUppercase&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;lowercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;atLeastOneLowercase&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;atLeastOneNumeric&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;specialChar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;atLeastOneSpecialChar&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;eightCharsOrGreater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eightCharsOrMore&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Password input field and strength meter
&lt;/h2&gt;

&lt;p&gt;This is a simple input field with functions to execute based on browser events. When a user focuses on the field, an anonymous function sets the &lt;code&gt;meter&lt;/code&gt; state to &lt;code&gt;true&lt;/code&gt; thereby displaying the password strength meter and validation criteria. The &lt;code&gt;onChange&lt;/code&gt; event updates the state of the actual password as the user types.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
          &lt;span class="nx"&gt;onFocus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setMeter&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="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&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;setPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
          &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter password...pwetty please&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;meter&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password-strength-meter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;passwordStrength&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Must contain &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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;passwordTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uppercase&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uppercase, &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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;passwordTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lowercase&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lowercase, &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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;passwordTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specialChar&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;special character, &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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;passwordTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number, &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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;passwordTracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eightCharsOrGreater&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eight characters or more&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the validation criteria section, the negated value of a property is used to determine whether a criteria should be rendered or not. For example, if a password passes the &lt;code&gt;atLeastOneUppercase&lt;/code&gt; regex, the value of the &lt;code&gt;uppercase&lt;/code&gt; property is updated to a truthy value so that when negated(&lt;code&gt;!&lt;/code&gt;), becomes &lt;code&gt;false&lt;/code&gt; and does not render the &lt;code&gt;'uppercase, '&lt;/code&gt; part any more. When falsy(&lt;code&gt;null&lt;/code&gt;) it negates the value and becomes truthy which renders the &lt;code&gt;'uppercase, '&lt;/code&gt; part letting users know that they still have to fulfill that criterion.&lt;br&gt;&lt;br&gt;
Lastly, we have the &lt;code&gt;passwordStrength&lt;/code&gt; variable whose value is gotten from the number of &lt;em&gt;truthy&lt;/em&gt; values in &lt;code&gt;passwordTracker&lt;/code&gt; object.&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;passwordStrength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;passwordTracker&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is if 3 validation criteria are passed, the corresponding properties will have truthy values while the rest have falsy values (&lt;code&gt;null&lt;/code&gt;). To know the number of criteria passed, we use the &lt;code&gt;Object.values()&lt;/code&gt; method on the &lt;code&gt;passwordTracker&lt;/code&gt; which returns an array of &lt;em&gt;values&lt;/em&gt;. Then we filter for the truthy values and then obtain the length of the array with a &lt;code&gt;.length&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;code&gt;passwordStrength&lt;/code&gt; is mainly use to determine the color and width of the password strength meter and also show or hide the &lt;code&gt;'Must contain '&lt;/code&gt; part based on if all criteria are passed or not.&lt;br&gt;&lt;br&gt;
With CSS-in-JS, we are able to execute javaScript in our CSS styles using &lt;a href="https://en.wikipedia.org/wiki/Short-circuit_evaluation"&gt;short circuit evaluation&lt;/a&gt; which assigns various colors to the &lt;code&gt;background-color&lt;/code&gt; property. The width of the meter is given in percentage by multiplying the ratio of the number of passed criteria(which could be 1,2,3,4 or 5) to the total number of criteria(5) by 100&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.password-strength-meter&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;${&lt;/span&gt;
              &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;'orange'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;'#03a2cc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;'#03a2cc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;'#0ce052'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
              &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;passwordStrength&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;''&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nt"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%;&lt;/span&gt;
            &lt;span class="nt"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;(passwordStrength&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt; &lt;span class="err"&gt;5)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;%;&lt;/span&gt;
            &lt;span class="nt"&gt;display&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;block&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nt"&gt;border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nt"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;width&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;s&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
          &lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It is more aesthetically pleasing and a better user experience to pinpoint the requirements a user needs to fulfill in order to navigate your app smoothly.&lt;br&gt;&lt;br&gt;
I really hope you've gained some insight on this article on how to implement password validation with password strength meter. I would love to know if there are any improvements that can be made on this implementation and also if you would prefer using a library over self implementation.  &lt;/p&gt;

&lt;p&gt;Feel free to share other implementations you have come across, suggestions, comments or questions.&lt;br&gt;
Thanks for reading and happy coding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;If you would like to connect with me, I'm available on;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord: &lt;code&gt;brunoelo#8120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/brunoelo"&gt;BrunoElo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Module scoped styling in Angular 13</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Fri, 15 Jul 2022 11:24:44 +0000</pubDate>
      <link>https://dev.to/brunoelo/module-scoped-styling-in-angular-13-i09</link>
      <guid>https://dev.to/brunoelo/module-scoped-styling-in-angular-13-i09</guid>
      <description>&lt;p&gt;Angular convention provides us with the concept of modules typically used for grouping features in our applications. I heavily rely on this and as such, get into the dilemma of styling those modules when I want each module to have global styles that only affect all components in that particular module.&lt;br&gt;&lt;br&gt;
This article shows various ways of achieving module scoped styling in Angular.&lt;br&gt;&lt;br&gt;
You can &lt;a href="module-scoped-styling-in-angular-13-i09#demo"&gt;jump to the stackblitz demo&lt;/a&gt; to check it out.&lt;/p&gt;
&lt;h2&gt;
  
  
  Application architecture
&lt;/h2&gt;

&lt;p&gt;Firstly, let me describe the application architecture for these use cases.&lt;br&gt;
We have an angular 13 application in a stackblitz which has the &lt;code&gt;app module&lt;/code&gt; and 3 lazy-loaded modules with 2 components in each module.&lt;br&gt;
The &lt;code&gt;styles.scss&lt;/code&gt; global stylesheet has the style below which is applied across the entire application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="no"&gt;red&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will be using the colors of the paragraphs to show how you can leverage module scoped styling and what it entails.&lt;br&gt;&lt;br&gt;
Currently, this is what the color of the paragraphs in all components look like&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UEoevZ_j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176501201/sikx3y_wY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UEoevZ_j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176501201/sikx3y_wY.png" alt="module-one-first.png" width="865" height="231"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y-cgmVDV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176589975/2lk46Nfet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y-cgmVDV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176589975/2lk46Nfet.png" alt="module-one-second.png" width="862" height="234"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9K14JZ6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176600585/vT37LB-d1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9K14JZ6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176600585/vT37LB-d1.png" alt="module-two-first.png" width="865" height="235"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m-teah8V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176649523/Mss7tv3rX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m-teah8V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176649523/Mss7tv3rX.png" alt="module-two-second.png" width="878" height="236"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5lzGClHv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176671634/iTMiVUvUu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5lzGClHv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176671634/iTMiVUvUu.png" alt="module-three-first.png" width="867" height="242"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TTuS4nas--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176679168/N2bDwm_FG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TTuS4nas--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651176679168/N2bDwm_FG.png" alt="module-three-second.png" width="850" height="236"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution 1: Using the &lt;code&gt;:host&lt;/code&gt; selector in the stylesheet of the module component
&lt;/h2&gt;

&lt;p&gt;With this method, the &lt;code&gt;:host&lt;/code&gt; selector is used to style the host element(&lt;code&gt;app-module-one&lt;/code&gt;) and then the children(components) of the parent host element inherit the css property. The &lt;code&gt;:host&lt;/code&gt; selector can also be combined with other selectors if you want to style the descendants of the host element.&lt;br&gt;&lt;br&gt;
We add this in &lt;code&gt;module-one.component.scss&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;And now, every component in module one gets the styles&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f-0Rfbd9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651177059171/DTJPS98Jz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f-0Rfbd9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651177059171/DTJPS98Jz.png" alt="module-one-first-after.png" width="866" height="235"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BNiGqLzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651177069883/Wyt350W-J.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BNiGqLzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651177069883/Wyt350W-J.png" alt="module-one-second-after.png" width="851" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can add more properties relating to font, background color e.t.c... that you want applied to all components of the module. Ideally inheritable css properties.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution 2: Creating a separate stylesheet for modules and importing it in components you need it in
&lt;/h2&gt;

&lt;p&gt;It may be preferred to use an entirely separate stylesheet which is added in the &lt;code&gt;styleUrls&lt;/code&gt; array of the components the styles should be applied to.&lt;br&gt;&lt;br&gt;
We'll create a stylesheet called &lt;code&gt;module-two-styles.scss&lt;/code&gt; in the &lt;code&gt;module-two&lt;/code&gt; directory (so it's easy to find) and add the style below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* module-two-styles.scss */&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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're simply styling the &lt;code&gt;p&lt;/code&gt; tag by giving the color property a value of &lt;code&gt;green&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Then import the &lt;code&gt;module-two-styles.scss&lt;/code&gt; in the &lt;code&gt;first.component.ts&lt;/code&gt;, &lt;code&gt;second.component.ts&lt;/code&gt; and &lt;code&gt;module-two.component.ts&lt;/code&gt; files in &lt;code&gt;module-two&lt;/code&gt; folder.&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="cm"&gt;/* module-two/first/first.component.ts */&lt;/span&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-first&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;./first.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;./first.component.scss&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;../module-two-style.scss&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 javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* module-two/second/second.component.ts */&lt;/span&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-second&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;./second.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;./second.component.scss&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;../module-two-style.scss&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 javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* module-two/module-two.component.ts */&lt;/span&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-module-two&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;./module-two.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;./module-two.component.scss&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;module-two-style.scss&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;p&gt;Now this will only apply the style to the components you imported the stylesheet into. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S_lvaur8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651178105909/b6Il_YH6K.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S_lvaur8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651178105909/b6Il_YH6K.png" alt="module-two-first-after.png" width="851" height="212"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CCl589lD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651178112205/zeloQU74G.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CCl589lD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651178112205/zeloQU74G.png" alt="module-two-second-after.png" width="874" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some reasons for doing this is sometimes, you may be working in a codebase that has the potential to be largely refactored while you're working on something or maybe you want to create some sort of easily manageable distinction between your styles and the ones that were already in the existing project and cannot afford to tamper with the global stylesheet as you consider the time constraints involved.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Tip for using &lt;code&gt;styleUrls&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The position of the stylesheet paths in the &lt;code&gt;styleUrls&lt;/code&gt; array matters. Stylesheets get overridden by other stylesheets that come after them in the array.&lt;/em&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  Demo&lt;a id="demo-link"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here is a stackblitz that contains a demo for the article. You can quickly explore and experiment more style properties.&lt;br&gt;
&lt;iframe src="https://stackblitz.com/edit/angular-ivy-987gd3?embed=1&amp;amp;file=src/app/app.component.html" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thank you for reading &lt;/p&gt;

&lt;p&gt;Feel free to leave suggestions or questions in the comment especially if you have challenges with styling your application a certain way. Also share the article if you gained something or feel it was helpful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;If you would like to connect with me, I'm available on;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord: &lt;code&gt;brunoelo#8120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/brunoelo"&gt;BrunoElo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>styling</category>
    </item>
    <item>
      <title>Adding Forestry CMS to an Angular Scully blog site</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Thu, 14 Jul 2022 09:05:36 +0000</pubDate>
      <link>https://dev.to/brunoelo/adding-forestry-cms-to-an-angular-scully-blog-site-32op</link>
      <guid>https://dev.to/brunoelo/adding-forestry-cms-to-an-angular-scully-blog-site-32op</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article aims to guide you through the configuration of Forestry CMS in your angular project that is built with Scully static site generator and deployed on Netlify.&lt;br&gt;
We will be using the Angular scully blog project we built in &lt;a href="https://www.brunoelo.com/blog/creating-an-angular-blog-with-scully-and-deploying-on-netlify"&gt;a previous article&lt;/a&gt;. Kindly check it out if you haven't so you can be up to speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forestry CMS
&lt;/h2&gt;

&lt;p&gt;Forestry CMS is a git based headless CMS that can be used to manage content on sites stored in a repository. It makes commits and pushes to your selected repository when you save content on the CMS as well as fetching latest commits to update content on the CMS. It allows you embrace the jamstack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing our site
&lt;/h2&gt;

&lt;p&gt;Since we already have a site with its repository on github, let's head over to &lt;a href="https://forestry.io"&gt;Forestry&lt;/a&gt; and import our site by signing up.&lt;br&gt;
You will be taken to a page that shows a few questions. When asked &lt;strong&gt;What kinds of sites do you plan to build with Forestry?&lt;/strong&gt;, choose &lt;strong&gt;Other&lt;/strong&gt; then click complete registration.&lt;br&gt;&lt;br&gt;
After that step, you will be taken to the page where you can add your site. Select &lt;code&gt;Add site&lt;/code&gt; at the top right corner and choose &lt;code&gt;Other&lt;/code&gt; option as your static site generator then click next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wbeLJAXN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750726958/Kzl-VvGYh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wbeLJAXN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750726958/Kzl-VvGYh.jpg" alt="forestrycmsstep1.jpg" width="735" height="487"&gt;&lt;/a&gt;&lt;br&gt;
Select your git provider for where your site's repository is stored&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CWLe_eKC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750747642/_pla7ap7k.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CWLe_eKC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750747642/_pla7ap7k.jpg" alt="forestrycmsstep2.jpg" width="487" height="342"&gt;&lt;/a&gt;&lt;br&gt;
Complete github authentication so that forestry can access your repositories. Then select the repository and branch your site is deployed from.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OC_qgCre--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750765420/lwVVd9deF.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OC_qgCre--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750765420/lwVVd9deF.jpg" alt="forestrycmsstep3.jpg" width="828" height="464"&gt;&lt;/a&gt;&lt;br&gt;
Once it's done, you'll be taken to the forestry CMS.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2owzWIOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750787962/zVMMMXxJJ.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2owzWIOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651750787962/zVMMMXxJJ.jpg" alt="forestrycmsstep4.jpg" width="880" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding blog section on our CMS
&lt;/h2&gt;

&lt;p&gt;Next, we need to configure our side bar so that the CMS can read contents from our repository. Click the &lt;code&gt;Configure side bar&lt;/code&gt; button and select &lt;code&gt;add section&lt;/code&gt; for our blog. Choose the &lt;code&gt;Directory&lt;/code&gt; section type.&lt;br&gt;&lt;br&gt;
Fill the label and content directory fields accordingly and click done then save.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gvPEG50j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651751272990/Fg4VElVj7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gvPEG50j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651751272990/Fg4VElVj7.jpg" alt="forestrycmsstep5.jpg" width="880" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you save, the new section appears at the left side bar and fetches the available markdown files form your repository in the directory you specified. Click on the blog section to see your content and checkout your posts.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mBJ9XKGX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651751559378/Xqmtk6wvC.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mBJ9XKGX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651751559378/Xqmtk6wvC.jpg" alt="forestrycmsstep6.jpg" width="880" height="283"&gt;&lt;/a&gt;&lt;br&gt;
Click on the &lt;code&gt;create new&lt;/code&gt; button and select &lt;code&gt;Blog&lt;/code&gt; from the dropdown to add a new post. You'll be prompted to create a &lt;em&gt;frontmatter&lt;/em&gt; template if you do not have such so let's do that.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fl-QlIVI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651752038619/rX9H26F9W.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fl-QlIVI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651752038619/rX9H26F9W.jpg" alt="forestrycmsstep7.jpg" width="880" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a frontmatter template
&lt;/h2&gt;

&lt;p&gt;Select the &lt;em&gt;Create a new template&lt;/em&gt; option, name the template and choose any template style you like.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BVhMUoOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651752331784/cq7wafrir.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BVhMUoOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651752331784/cq7wafrir.jpg" alt="forestrycmsstep8.jpg" width="796" height="518"&gt;&lt;/a&gt;&lt;br&gt;
Once you click the &lt;code&gt;create template&lt;/code&gt; button, you can begin adding fields for your frontmatter.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a field
&lt;/h3&gt;

&lt;p&gt;Click the &lt;code&gt;Add field&lt;/code&gt; button and select from a variety of field types. You can even build on your other frontmatter templates.&lt;br&gt;
I've added a text field type&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5Xbvpw6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651752840163/3v7iTgbdD.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5Xbvpw6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651752840163/3v7iTgbdD.jpg" alt="forestrycmsstep10.jpg" width="498" height="461"&gt;&lt;/a&gt;&lt;br&gt;
After adding all the fields for your frontmatter template, you can save it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a frontmatter template
&lt;/h2&gt;

&lt;p&gt;If you do not want to create templates from the beginning, you can generate one from one of your posts so it can be reused.&lt;br&gt;
Select the &lt;em&gt;Create based on existing template&lt;/em&gt; option, name the template and choose a post with the frontmatter you would like to replicate. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k0lDUJB7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651753590224/ywGJJadE_.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k0lDUJB7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651753590224/ywGJJadE_.jpg" alt="forestrycmsstep11.jpg" width="836" height="460"&gt;&lt;/a&gt;&lt;br&gt;
Once you click the &lt;code&gt;create template&lt;/code&gt; button, it shows all the automatically created fields form the frontmatter of the post you selected. It's pretty awesome plus you can also add more fields to that template.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hDY4TsH7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651753769730/CQXrL0Yu2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hDY4TsH7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651753769730/CQXrL0Yu2.jpg" alt="forestrycmsstep12.jpg" width="880" height="472"&gt;&lt;/a&gt;&lt;br&gt;
Now when we create a blog and select the frontmatter template, all of the fields get rendered in the editor section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Media configuration
&lt;/h2&gt;

&lt;p&gt;We need to tell forestry CMS where we store our media files so it knows where to save new ones we add and where it should read media files from so we can see the correct media file when updating a post.&lt;br&gt;
Select &lt;code&gt;media&lt;/code&gt; from the left side bar and click &lt;code&gt;change upload folder&lt;/code&gt;.&lt;br&gt;
Edit the upload directory to &lt;code&gt;src/assets/images&lt;/code&gt; and public path to &lt;code&gt;/assets/images&lt;/code&gt; then save media settings.&lt;br&gt;
Select &lt;code&gt;media&lt;/code&gt; from the left side bar again and you'll be able to view your media files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a blog post
&lt;/h2&gt;

&lt;p&gt;Let's make a new blog post with the generated frontmatter template. Don't forget to toggle the published button for it to appear on your blog. When you save, Forestry CMS makes a commit to your repository and creates a blog post which is saved as new markdown file.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T7TVJXwP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651755888970/3MTIL5s2G.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T7TVJXwP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1651755888970/3MTIL5s2G.jpg" alt="forestrycmsstep13a.jpg" width="880" height="372"&gt;&lt;/a&gt;&lt;br&gt;
Here is the &lt;a href="https://angular-scully-site.netlify.app/blog/forestry-cms-post"&gt;link to the new blog post&lt;/a&gt; that was created with forestry CMS.&lt;/p&gt;

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

&lt;p&gt;Forestry CMS is packed with various functionalities that makes it easier to manage content on your site. &lt;/p&gt;

&lt;p&gt;I hope you find this article helpful and feel free to share with others or reach out if you have any questions, suggestions or comments.&lt;br&gt;
Thanks for reading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;If you would like to connect with me, I'm available on;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord: &lt;code&gt;brunoelo#8120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/brunoelo"&gt;BrunoElo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cms</category>
      <category>forestry</category>
      <category>angular</category>
      <category>scully</category>
    </item>
    <item>
      <title>Adding Netlify CMS to an Angular Scully blog site</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Wed, 13 Jul 2022 08:31:38 +0000</pubDate>
      <link>https://dev.to/brunoelo/adding-netlify-cms-to-an-angular-scully-blog-site-285k</link>
      <guid>https://dev.to/brunoelo/adding-netlify-cms-to-an-angular-scully-blog-site-285k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article aims to guide you through the configuration of netlify CMS in your angular project that is built with Scully static site generator and deployed on Netlify.&lt;br&gt;
We will be using the Angular scully blog project we built in &lt;a href="https://www.brunoelo.com/blog/creating-an-angular-blog-with-scully-and-deploying-on-netlify"&gt;a previous article&lt;/a&gt;. Kindly check it out if you haven't so you can be up to speed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is the final result of what we will be building&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;a href="https://angular-scully-site.netlify.app/admin"&gt;CMS demo&lt;/a&gt; for &lt;a href="https://angular-scully-site.netlify.app"&gt;Angular-Scully blog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrunoElo/angular-scully-blog"&gt;Github repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Netlify CMS
&lt;/h3&gt;

&lt;p&gt;This is a git-based CMS that allows us manage the content of our applications that are stored in repositories on any of the version control platforms such as Github, Bitbucket or Gitlab. It supports a variety of file formats like markdown, JSON, YAML and TOML.&lt;br&gt;&lt;br&gt;
Now that we have some background with the tools we are using, let's begin&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lg6teIGj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://tenor.com/view/benedict-cumberbatch-dr-strange-doctor-dtrange-protect-power-gif-16748773.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lg6teIGj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://tenor.com/view/benedict-cumberbatch-dr-strange-doctor-dtrange-protect-power-gif-16748773.gif" alt="doctor strange ready" width="498" height="359"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding Netlify CMS to your Angular-Scully app
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; folder in your app, create a folder named &lt;code&gt;admin&lt;/code&gt; which will contain two files namely; &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;config.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;src
 └ admin
     ├ index.html
     └ config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src/admin/index.html&lt;/code&gt; is the file which loads/fetches the admin panel that handles access to the netlify CMS app for your your site while the &lt;code&gt;src/admin/config.yml&lt;/code&gt; handles Netlify CMS configuration.&lt;br&gt;&lt;br&gt;
Add the code snippet below to the &lt;code&gt;src/admin/index.html&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="c"&gt;&amp;lt;!-- src/admin/index.html --&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Content Manager&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Include the script that builds the page and powers Netlify CMS --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above is just basic html page that loads the actual admin page from a CDN.&lt;/p&gt;

&lt;p&gt;Here is a sample configuration for the &lt;code&gt;config.yml&lt;/code&gt;. It is also important to go through the &lt;a href="https://www.netlifycms.org/docs/add-to-your-site/#configuration"&gt;configuration docs&lt;/a&gt; for more insight on what these settings do. Add this snippet below or customise to fit your use case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# src/admin/config.yml&lt;/span&gt;

&lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git-gateway&lt;/span&gt;
  &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt; &lt;span class="c1"&gt;# Branch to update (optional; defaults to master)&lt;/span&gt;

&lt;span class="na"&gt;media_folder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/assets/images"&lt;/span&gt; &lt;span class="c1"&gt;# Media files will be stored in the repo under assets/images&lt;/span&gt;
&lt;span class="na"&gt;public_folder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/assets/images"&lt;/span&gt; &lt;span class="c1"&gt;# The src attribute for uploaded media will begin with /assets/images&lt;/span&gt;

&lt;span class="na"&gt;collections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blog"&lt;/span&gt; &lt;span class="c1"&gt;# Used in routes, e.g., /admin/collections/blog&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Blog"&lt;/span&gt; &lt;span class="c1"&gt;# Used in the UI&lt;/span&gt;
    &lt;span class="na"&gt;folder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blog"&lt;/span&gt; &lt;span class="c1"&gt;# The path to the folder where the documents are stored&lt;/span&gt;
    &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Allow users to create new documents in this collection&lt;/span&gt;
    &lt;span class="c1"&gt;#slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# The fields for each document, usually in front matter&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Layout"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;layout"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hidden"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blog"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Description"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;#- {label: "Slug", name: "slug", widget: "string"}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Published"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;boolean"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Publish&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Date"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;datetime"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Image"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rating&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(scale&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1-5)"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Body"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;markdown"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include the &lt;code&gt;src/admin&lt;/code&gt; directory of the Netlify CMS in your &lt;code&gt;angular.json&lt;/code&gt; file so that the files can be included in the build directories of your static site.&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="nl"&gt;"projects"&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;"angular-blog"&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"architect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="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;"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="s2"&gt;"src/admin"&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;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;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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run the command &lt;code&gt;npm run build&lt;/code&gt; you should see the &lt;code&gt;admin&lt;/code&gt; directory in the &lt;code&gt;dist&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dist
├ angular-blog
|    └ admin
|        ├ index.html
|        └ config.yml
└ static
     └ admin
          ├ index.html
          └ config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Netlify CMS authentication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication on Netlify web app (the backend)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Steps to enable Identity and Git Gateway
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Log into your netlify web app platform&lt;/li&gt;
&lt;li&gt;Once you get to your dashboard, click on &lt;strong&gt;sites&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Select the site you want to enable netlify identity for&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;site settings&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Identity&lt;/strong&gt; on the left side tab&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Enable Identity&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Registration Preferences&lt;/strong&gt;, click &lt;strong&gt;Edit settings&lt;/strong&gt; and choose &lt;strong&gt;Invite only&lt;/strong&gt; option. (For the sake of the demo, I have left mine as open)&lt;/li&gt;
&lt;li&gt;If you would like to enable third-party login, add a provider in the &lt;strong&gt;External providers&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Scroll down to &lt;strong&gt;Git Gateway&lt;/strong&gt; in the &lt;strong&gt;Services&lt;/strong&gt; section and click the &lt;strong&gt;Enable Git Gateway&lt;/strong&gt; button.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authentication in your app (the frontend)
&lt;/h3&gt;

&lt;p&gt;We need to add the Netlify Identity Widget which basically handles the interface needed to connect to the backend we configured in the previous step. To include the widget, add the &lt;code&gt;script&lt;/code&gt; tag below in the &lt;code&gt;head&lt;/code&gt; of your CMS index file at &lt;code&gt;src/admin/index.html&lt;/code&gt; and also in the &lt;code&gt;head&lt;/code&gt; of your main index file &lt;code&gt;src/index.html&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="c"&gt;&amp;lt;!-- src/admin/index.html --&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Content Manager&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://identity.netlify.com/v1/netlify-identity-widget.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Include the script that builds the page and powers Netlify CMS --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&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 html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/index.html --&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;AngularBlog&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/x-icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://identity.netlify.com/v1/netlify-identity-widget.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;app-root&amp;gt;&amp;lt;/app-root&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;When a user logs in with the Netlify Identity widget, an access token directs to the site homepage. In order to complete the login and get back to the CMS, redirect the user back to the &lt;code&gt;/admin/&lt;/code&gt; path. To do this, add the following script before the closing body tag of your site's main index page:&lt;/p&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;netlifyIdentity&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="nx"&gt;netlifyIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&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="nx"&gt;netlifyIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin/&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;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Push your code to your github repo which will trigger a build process on netlify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing the CMS in your browser
&lt;/h2&gt;

&lt;p&gt;You can access your site's CMS at &lt;code&gt;yoursite.com/admin/&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Checkout the &lt;a href="https://angular-scully-site.netlify.app/admin"&gt;CMS demo&lt;/a&gt; for &lt;a href="https://angular-scully-site.netlify.app"&gt;Angular-Scully blog&lt;/a&gt;. Click login with Netlify Identity and choose Sign up so you can create an account to access the CMS.&lt;br&gt;&lt;br&gt;
Please be good and have fun posting. Thank you for reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.netlifycms.org/docs/add-to-your-site/"&gt;Netlify documentation for adding Netlify CMS to your site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;If you would like to connect with me, I'm available on;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord: &lt;code&gt;brunoelo#8120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/brunoelo"&gt;BrunoElo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>netlify</category>
      <category>cms</category>
      <category>scully</category>
    </item>
    <item>
      <title>Creating an Angular blog with Scully and deploying on Netlify</title>
      <dc:creator>Emeka Elo-Chukwuma</dc:creator>
      <pubDate>Tue, 03 May 2022 19:32:16 +0000</pubDate>
      <link>https://dev.to/brunoelo/creating-an-angular-blog-with-scully-and-deploying-on-netlify-30kk</link>
      <guid>https://dev.to/brunoelo/creating-an-angular-blog-with-scully-and-deploying-on-netlify-30kk</guid>
      <description>&lt;p&gt;We'll be building a blog site with the Angular framework, Scully for static site generation(SSG) and then deploying the project on Netlify so that it can be accessible to the public.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this article covers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Using Angular to build the blog architecture&lt;/li&gt;
&lt;li&gt;Installing Scully library to handle static site Generation&lt;/li&gt;
&lt;li&gt;Netlify deployment&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular-scully-site.netlify.app/" rel="noopener noreferrer"&gt;Demo of this project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrunoElo/angular-scully-blog" rel="noopener noreferrer"&gt;Repository for the demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup requirements
&lt;/h2&gt;

&lt;p&gt;We'll be using the following tools for this project&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular v13&lt;/li&gt;
&lt;li&gt;Tailwind&lt;/li&gt;
&lt;li&gt;Scully&lt;/li&gt;
&lt;li&gt;Node v14.15 (or higher)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; is an application design framework and development platform for creating efficient and sophisticated single-page apps. It's an opensource frontend framework built by Google.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://scully.io/docs/learn/overview/" rel="noopener noreferrer"&gt;Scully&lt;/a&gt; is a library used for generating static sites built with Angular and ushers you into the jamstack. SSGs generate static pages when you build your project so that what you publish/deploy is the already built pages which can be indexed by google(for some of that SEO good good) and served quickly to clients. Without scully, our angular project will go through client side rendering where each page of the application that is visited is rendered by the browser at runtime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind&lt;/a&gt; is a CSS utility library that is used to speed up the styling of applications by offering flexibility and conciseness.&lt;/p&gt;

&lt;p&gt;Now that we have some background on the project, we can start building&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%2Ftenor.com%2Fview%2Fdenki-raiton-tsubaki-boruto-naruto-gif-23947946.gif" 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%2Ftenor.com%2Fview%2Fdenki-raiton-tsubaki-boruto-naruto-gif-23947946.gif" alt="Hajime"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the Angular project
&lt;/h2&gt;

&lt;p&gt;Use the command below to generate a new angular project. You can name your project what you like. I have chosen &lt;code&gt;angular-blog&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new angular-blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You'll see the following questions. We want routing and SCSS stylesheet format.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After the project has been generated, serve the application using the ng serve command&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You'll be greeted with the standard angular welcome template.&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%2F099yjy37pvsfw5hkzbc3.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%2F099yjy37pvsfw5hkzbc3.png" alt="Angular welcome page"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;code&gt;app.component.html&lt;/code&gt; and delete the entire content (we don't want that welcome page showing up) and then place &lt;code&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/code&gt; tags since this is where all our modules and components will be displayed based on the route configuration in &lt;code&gt;app.routing-module.ts&lt;/code&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  Installing Scully
&lt;/h2&gt;

&lt;p&gt;Run the command below to install scully and automatically make all the necessary configurations to the project&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @scullyio/init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;During the installation, you'll get the question below. As at the time of this writing, &lt;code&gt;pupeteer&lt;/code&gt; is the most stable renderer so we'll choose that.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;? Which route renderer would you like to use?
  Scully platform server
&amp;gt; Puppeteer
  Playwright (beta)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here is what the terminal looks like after the installation process&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%2Fpi7xkctvf1nwvcwdpv8s.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%2Fpi7xkctvf1nwvcwdpv8s.png" alt="scully installation terminal"&gt;&lt;/a&gt;&lt;br&gt;
The &lt;code&gt;init&lt;/code&gt; schematic of the scully installation made a couple of changes which include;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;installing the pupeteer plugin&lt;/li&gt;
&lt;li&gt;updating the &lt;code&gt;app.module.ts&lt;/code&gt; by importing the &lt;code&gt;ScullyLibModule&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;updating the package.json file with scully commands for building and serving the generated pages
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "scully": "npx scully --",
    "scully:serve": "npx scully serve --"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;created a &lt;code&gt;scully.angular-blog.config.ts&lt;/code&gt; file which is the scully configuration file.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Adding blog support to our project
&lt;/h3&gt;

&lt;p&gt;Scully has a schematic for creating the blog section for our project&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate @scullyio/init:blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This adds a lazy-loaded blog module's routes to the Angular application(&lt;code&gt;app.routing-module.ts&lt;/code&gt;) and creates a &lt;code&gt;./blog&lt;/code&gt; folder for the blog's markdown files(where our blog posts will live).&lt;br&gt;
Below is the current route configuration in &lt;code&gt;app.routing-module.ts&lt;/code&gt; updated by scully.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes: Routes = [{ path: 'blog', loadChildren: () =&amp;gt; import('./blog/blog.module').then(m =&amp;gt; m.BlogModule) }];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It also updates the &lt;code&gt;scully.angular-blog.config.ts&lt;/code&gt; with the blog routes to prerender.&lt;/p&gt;
&lt;h4&gt;
  
  
  A few other configurations to do
&lt;/h4&gt;

&lt;p&gt;Now we have a module for our blog feature. The next things we need to create are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a component for the list of blog posts using the command below
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component blog/blog-list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;a component that will show the actual blog post content using the command below
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component blog/blog-post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We also need to go to the &lt;code&gt;blog.routing.module.ts&lt;/code&gt; and fix up our route configuration as below&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes: Routes = [
  {
    path: '',
    component: BlogComponent,
    children: [
      {path: ':slug', component: BlogPostComponent},
      {path: '', component: BlogListComponent}
      ]
  }
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lastly, we add the &lt;code&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/code&gt; in the &lt;code&gt;blog.component.html&lt;/code&gt; to handle routing in the module.This page will display the blog list and blog posts based on the route configuration in &lt;code&gt;blog-routing.module.ts&lt;/code&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  Configuring the route entry point for scully
&lt;/h2&gt;

&lt;p&gt;After sorting out the module for our blog feature, we need to create an entry point for scully (typically the home page of our app).  &lt;/p&gt;

&lt;p&gt;It is suitable to leverage the Angular lazy-loaded module feature for our app home page because this part of our app is separate from the blog part. &lt;br&gt;
Create a &lt;code&gt;home module&lt;/code&gt; with the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module home --route=home --module=app-routing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This updates the route configuration in &lt;code&gt;app-routing.module.ts&lt;/code&gt; with the path for the &lt;code&gt;home module&lt;/code&gt;. Set its path to an empty string.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes: Routes = [{
        path: 'blog',
        loadChildren: () =&amp;gt; import('./blog/blog.module').then(m =&amp;gt; m.BlogModule)
    },
    {
        path: '',
        loadChildren: () =&amp;gt; import('./home/home.module').then(m =&amp;gt; m.HomeModule)
    },
    {path: '**', redirectTo: 'blog', pathMatch: 'full'},
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can always add a redirect below the route configuration for the blog module if you don't want the home page to be accessed yet.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{path:'',redirectTo:'blog',pathMatch:'full'},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Building the Angular-Scully app
&lt;/h2&gt;

&lt;p&gt;After all those configurations, we need to build our project with Angular, build with Scully then serve the built project on the Scully server but first, let's restart the Angular server.&lt;br&gt;&lt;br&gt;
Build the project by running&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we build with scully using&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx scully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can also modify the &lt;code&gt;build&lt;/code&gt; command in our &lt;code&gt;package.json&lt;/code&gt; so that it will run the two previous commands.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"build": ng build &amp;amp;&amp;amp; npm run scully -- --scanRoutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we can use &lt;code&gt;npm run build&lt;/code&gt; to achieve the same thing.&lt;br&gt;
After those two commands, a &lt;code&gt;dist&lt;/code&gt; folder is created in the root directory of our project. This folder contains the two built versions of our site, The folder named &lt;code&gt;angular-blog&lt;/code&gt; is the one built by Angular while the one named &lt;code&gt;static&lt;/code&gt; contains the static pages generated by scully.&lt;br&gt;
Now, we can start the scully server using the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx scully serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After the server starts successfully, navigate to &lt;a href="http://localhost:4200/blog" rel="noopener noreferrer"&gt;http://localhost:4200/blog&lt;/a&gt; to see the angular app running, then in a separate tab, open this link &lt;a href="http://localhost:1668/blog" rel="noopener noreferrer"&gt;http://localhost:1668/blog&lt;/a&gt; to see the static site. You browser should show a white page with the text &lt;code&gt;blog-list works!&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
To check our actual blog post (created by the &lt;code&gt;init:blog&lt;/code&gt; schematic) go to the markdown file in the &lt;code&gt;blog&lt;/code&gt; folder and copy the value of the &lt;code&gt;slugs&lt;/code&gt; property in the frontmatter.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: "2022-04-29-blog"
description: 'blog description'
published: false
slugs:
    - ___UNPUBLISHED___l2kp8pyl_z4RfUZ7hSOMdOfldi8yqeZcOKuebIId2
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That is the current path(generated by scully) to the blog post when &lt;code&gt;published: false&lt;/code&gt;. It's a private route to your blog post when it's still in draft version so you can share with anyone to get an article review before publishing. When you are ready to publish the post, you can set &lt;code&gt;published: true&lt;/code&gt; and remove the &lt;code&gt;slugs&lt;/code&gt; property which will allow scully use the file name(without the extension) as its path when it generates the static pages.  &lt;/p&gt;

&lt;p&gt;Go to address bar of the tab serving the static site and paste the slug after &lt;a href="http://localhost:1668/blog/" rel="noopener noreferrer"&gt;http://localhost:1668/blog/&lt;/a&gt; then press enter. You should see the content of the blog post.&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%2Frf3wfuygpj88j1am5q7j.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%2Frf3wfuygpj88j1am5q7j.png" alt="static site blog post"&gt;&lt;/a&gt;&lt;br&gt;
Now, we have confirmed that our blog feature is fully functional so next up is to add more blog posts.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating blog posts
&lt;/h2&gt;

&lt;p&gt;We can create a blog post with the command below. The &lt;code&gt;name&lt;/code&gt; option takes the name of your post.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate @scullyio/init:post --name="Post 1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This creates a markdown file in the &lt;code&gt;blog&lt;/code&gt; folder.&lt;br&gt;
When we open the newly created markdown file, we see this&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: Post 1
description: blog description
published: false
---

# Post 1

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

&lt;/div&gt;


&lt;p&gt;As you now know, the content between the three dashes is the frontmatter and below the frontmatter is the blog content.&lt;br&gt;&lt;br&gt;
The frontmatter is where we can add information about the post such as metadata, SEO e.t.c.&lt;br&gt;
Let's update this markdown file to look like this&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: Post 1
description: blog description
published: true
image: /assets/images/enigma.jpg
seo: {
metaDescription: First post for my angular scully blog,
metaTitle: First post
},
---

# Post 1

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

&lt;/div&gt;


&lt;p&gt;I have added an image in the corresponding directory which I'll render in post.&lt;br&gt;
When we're satisfied with our markdown file, we can build with the &lt;code&gt;npx scully&lt;/code&gt; command.&lt;/p&gt;
&lt;h3&gt;
  
  
  A tip on knowing which to build with
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ng build&lt;/code&gt; is only needed when you modified something in your angular app. The scully config file, plugins, and eventual markdown files are not part of your Angular app. Although this may seem evident, if this is your first time using Scully it is easy to rebuild Angular even if it is not needed. When writing Scully plugins OR modifying your blog's markdown files, you DO NOT need to ng build the app each time you re-run Scully. Again, ng build Angular only if the Angular app changes &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Showing all blog posts
&lt;/h2&gt;

&lt;p&gt;Let's head over to &lt;code&gt;blog-list.component.ts&lt;/code&gt; to work out the logic that handles data for the component.&lt;br&gt;
In this component, we will inject the &lt;code&gt;ScullyRoutesService&lt;/code&gt; as a dependency which will give us access to the blog posts routes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, OnInit } from '@angular/core';
import {ScullyRoute, ScullyRoutesService} from "@scullyio/ng-lib";
import {Observable} from "rxjs";

@Component({
  selector: 'app-blog-list',
  templateUrl: './blog-list.component.html',
  styleUrls: ['./blog-list.component.scss']
})
export class BlogListComponent implements OnInit {
  links$: Observable&amp;lt;ScullyRoute[]&amp;gt; = this.scully.available$;

  constructor(private scully: ScullyRoutesService) { }

  ngOnInit(): void {
    this.getPublishedPosts();
  }

  getPublishedPosts() {
    this.links$ = this.links$.pipe(tap(val) =&amp;gt; console.log(val))
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What we want to render are the published posts, that's why we get the published routes from the &lt;code&gt;available$&lt;/code&gt; property on the &lt;code&gt;ScullyRoutesService&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
In the &lt;code&gt;blog-list.component.html&lt;/code&gt; we can build the template that shows all blog posts. We'll work with the code below for now.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li *ngFor="let post of links$ | async"&amp;gt;
    &amp;lt;a [href]="post.route"&amp;gt;{{post.title}}&amp;lt;/a&amp;gt;
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After you save, you should see an array of two routes in the console. We can't see any blog posts route yet because we haven't built with scully after changing the &lt;code&gt;published&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Let's ensure that the &lt;code&gt;published&lt;/code&gt; property in our markdown files are set to &lt;code&gt;true&lt;/code&gt; then build with scully to update our published routes.&lt;br&gt;
Now when we reload, we should see an array of 4 routes in the console. However, since we only want blog posts routes, we'll need to transform our data with some rxjs.&lt;br&gt;
Let's update the &lt;code&gt;getPublishedPosts&lt;/code&gt; function&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getPublishedPosts() {
    this.links$ = this.links$.pipe(map((links) =&amp;gt; links.filter((link) =&amp;gt;
      link.route.startsWith('/blog/'))),tap((val) =&amp;gt; console.log(val)));
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To ensure the scully version of our site is updated, let's run the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we should have our page like this.&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%2F0dwoi9jkr9o4kbo7212o.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%2F0dwoi9jkr9o4kbo7212o.png" alt="blog posts"&gt;&lt;/a&gt;&lt;br&gt;
You can click on the links to see that they show the corresponding posts.&lt;/p&gt;
&lt;h2&gt;
  
  
  Accessing the data in the blog post page
&lt;/h2&gt;

&lt;p&gt;We can get the route data of a particular page we navigate to with the help of the &lt;code&gt;ScullyRoutesService&lt;/code&gt; by subscribing to the observable returned by the &lt;code&gt;getCurrent()&lt;/code&gt; method.&lt;br&gt;
Add the code below to the &lt;code&gt;blog-post.component.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {Component, OnDestroy, OnInit} from '@angular/core';
import {ScullyRoute, ScullyRoutesService} from "@scullyio/ng-lib";
import {Subject, takeUntil} from "rxjs";
import {tap} from "rxjs/operators";

@Component({
  selector: 'app-blog-post',
  templateUrl: './blog-post.component.html',
  styleUrls: ['./blog-post.component.scss']
})
export class BlogPostComponent implements OnInit, OnDestroy {
  currentRoute: ScullyRoute = {} as ScullyRoute;
  onDestroy$ = new Subject&amp;lt;void&amp;gt;();

  constructor(private scully: ScullyRoutesService) {
  }

  ngOnInit(): void {
    this.getCurrentPost()
  }

  getCurrentPost() {
    this.scully.getCurrent()
      .pipe(takeUntil(this.onDestroy$))
      .subscribe((routeData: ScullyRoute) =&amp;gt; {
        this.currentRoute = routeData;
      });
  }

  ngOnDestroy() {
    this.onDestroy$.next();
    this.onDestroy$.complete();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Details of our current route is assigned to &lt;code&gt;this.currentRoute&lt;/code&gt; property and this allows us use the route data for that particular post the way we want.&lt;/p&gt;
&lt;h2&gt;
  
  
  Styling our blog
&lt;/h2&gt;

&lt;p&gt;Firstly, we need to create another component which will be our reusable component for the blog cards. Use the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component blog/blog-list/blog-card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open the &lt;code&gt;blog-card.component.html&lt;/code&gt; and place the code below inside it&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;li *ngFor="let post of links$ | async"&amp;gt;
    &amp;lt;a [href]="post.route"&amp;gt;{{post.title}}&amp;lt;/a&amp;gt;
&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we make use of this component in our &lt;code&gt;blog-list.component.html&lt;/code&gt; via the &lt;code&gt;app-blog-card&lt;/code&gt; selector in this way&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;app-blog-card [post]="post" *ngFor="let post of links$ | async"&amp;gt;&amp;lt;/app-blog-card&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We are also passing each route object in the array as &lt;code&gt;post&lt;/code&gt; through the &lt;code&gt;app-blog-card&lt;/code&gt; component therefore, we will need to receive this data from the parent component(&lt;code&gt;blog list&lt;/code&gt;) in our child component (&lt;code&gt;blog card&lt;/code&gt;) using the &lt;code&gt;Input()&lt;/code&gt; decorator.&lt;br&gt;
Let's do that by putting the code below in the &lt;code&gt;blog-card.component.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {Component, Input, OnInit} from '@angular/core';
import {ScullyRoute} from "@scullyio/ng-lib";

@Component({
  selector: 'app-blog-card',
  templateUrl: './blog-card.component.html',
  styleUrls: ['./blog-card.component.scss']
})
export class BlogCardComponent implements OnInit {
  @Input() post: Partial&amp;lt;ScullyRoute&amp;gt; = {};

  constructor() { }

  ngOnInit(): void {
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Finally, some styling
&lt;/h3&gt;

&lt;p&gt;You can use any styling format you want. I'll be using tailwind.&lt;br&gt;
Let's use the straightforward &lt;a href="https://tailwindcss.com/docs/guides/angular" rel="noopener noreferrer"&gt;tailwind documentation&lt;/a&gt; to configure it in our project.&lt;br&gt;
After the configuration is done, we'll need to restart the angular server.&lt;br&gt;
Update the &lt;code&gt;blog-card.component.html&lt;/code&gt; with the new template below&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;li class="h-full"&amp;gt;
  &amp;lt;a [href]="post.route" class="h-full w-full lg:max-w-full lg:flex hover:bg-gray-100"&amp;gt;
    &amp;lt;div
      class="h-48 lg:h-auto lg:w-48 flex-none bg-cover rounded-t lg:rounded-t-none lg:rounded-l text-center overflow-hidden"
      [style.background-image]="'url(' + (post['image'] || 'https://images.unsplash.com/photo-1496494118863-9cf5d1e70cd6?ixlib=rb-1.2.1&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=870&amp;amp;q=80') + ')'"
      title="Mountain"&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div
      class="w-full border-r border-b border-l border-gray-400 lg:border-l-0 lg:border-t lg:border-gray-400  rounded-b lg:rounded-b-none lg:rounded-r p-4 flex flex-col justify-between leading-normal"&amp;gt;
      &amp;lt;div class="mb-8"&amp;gt;
        &amp;lt;div class="text-gray-900 font-bold text-xl mb-2"&amp;gt;{{post.title}}&amp;lt;/div&amp;gt;
        &amp;lt;p class="text-gray-700 text-base"&amp;gt;{{post['seo']?.metaDescription || post['description']}}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/a&amp;gt;
&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Also update the &lt;code&gt;blog-list.component.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;ul class="p-10 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-1 lg:grid-cols-1 xl:grid-cols-3 gap-5"&amp;gt;
    &amp;lt;app-blog-card [post]="post" *ngFor="let post of links$ | async"&amp;gt;&amp;lt;/app-blog-card&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The code below adds a header to our site. Add it in &lt;code&gt;app.component.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;nav class="flex flex-wrap items-center justify-between bg-gray-800 p-6 w-full"&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;a class="text-white no-underline hover:text-white hover:no-underline" routerLink="/"&amp;gt;
      &amp;lt;span class="text-2xl"&amp;gt;Angular scully blog&amp;lt;/span&amp;gt;
    &amp;lt;/a&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;ul class="list-reset flex justify-end flex-1 items-center"&amp;gt;
    &amp;lt;li class="mr-3"&amp;gt;
      &amp;lt;a class="inline-block text-white no-underline hover:text-gray-200 hover:text-underline py-2 px-4"
         routerLinkActive="" routerLink="/blog"&amp;gt;blog&amp;lt;/a&amp;gt;
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/nav&amp;gt;
&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we have a nice user interface that shows all blog post&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%2Fyy6x0oplntelflicrwez.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%2Fyy6x0oplntelflicrwez.png" alt="blog list ui"&gt;&lt;/a&gt;&lt;br&gt;
Let's add the code below for the blog post user interface(&lt;code&gt;blog-post.component.html&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;main class="mx-auto max-w-screen-sm max-w-screen-lg"&amp;gt;
  &amp;lt;img [src]="currentRoute['image'] || 'https://cdn.mos.cms.futurecdn.net/4uiRZ5nNAgpHSifSjaKwcC-970-80.jpg.webp'"
       alt="nft"/&amp;gt;
  &amp;lt;h3&amp;gt;ScullyIo content&amp;lt;/h3&amp;gt;
  &amp;lt;hr&amp;gt;

  &amp;lt;!-- This is where Scully will inject the static HTML --&amp;gt;
  &amp;lt;scully-content&amp;gt;&amp;lt;/scully-content&amp;gt;
  &amp;lt;hr&amp;gt;
  &amp;lt;h4&amp;gt;End of content&amp;lt;/h4&amp;gt;
&amp;lt;/main&amp;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%2Fs44w8lma0mmbj0ha76im.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%2Fs44w8lma0mmbj0ha76im.png" alt="blog post ui"&gt;&lt;/a&gt;&lt;br&gt;
Finally, use the &lt;code&gt;npm run build&lt;/code&gt; command to build the project and checkout the scully static version in your browser.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pushing to Github
&lt;/h2&gt;

&lt;p&gt;Create a repository on &lt;a href="//github.com"&gt;Github&lt;/a&gt; and then copy the remote url (&lt;code&gt;https://github.com/&amp;lt;github-username&amp;gt;/&amp;lt;repository-name&amp;gt;.git&lt;/code&gt;) so that we can add it for our project using the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin https://github.com/&amp;lt;github-username&amp;gt;/&amp;lt;repository-name&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Rename the branch to &lt;code&gt;main&lt;/code&gt; with the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch -M main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Push to github with the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here's a link to the &lt;a href="https://github.com/BrunoElo/angular-scully-blog" rel="noopener noreferrer"&gt;repository for this article demo&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/emekaelo" rel="noopener noreferrer"&gt;
        emekaelo
      &lt;/a&gt; / &lt;a href="https://github.com/emekaelo/angular-scully-blog" rel="noopener noreferrer"&gt;
        angular-scully-blog
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A demo application for the angular scully blog article. Can be used as a starter template
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;AngularBlog&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;This is the repository for the Angular blog demo with Netlify CMS and Forestry CMS integration deployed on Netlify.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech stack&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;The tools used to build the project include;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular version 13.3&lt;/li&gt;
&lt;li&gt;Scully&lt;/li&gt;
&lt;li&gt;Tailwind&lt;/li&gt;
&lt;li&gt;Netlify CMS&lt;/li&gt;
&lt;li&gt;Forestry CMS&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;After cloning the project, run the command:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Use the command below to run the angular and scully build commands:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Serve the angular app:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;ng serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Serve the scully version which is the static site:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npx scully serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Navigate to &lt;a href="http://localhost:4200/" rel="nofollow noopener noreferrer"&gt;http://localhost:4200/&lt;/a&gt; to see the Angular app and &lt;a href="http://localhost:1668/" rel="nofollow noopener noreferrer"&gt;http://localhost:1668/&lt;/a&gt; to see the scully static site&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Further help&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To get more help on the Angular CLI use &lt;code&gt;ng help&lt;/code&gt; or go check out the &lt;a href="https://angular.io/cli" rel="nofollow noopener noreferrer"&gt;Angular CLI Overview and Command Reference&lt;/a&gt; page.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/emekaelo/angular-scully-blog" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Deploying to Netlify
&lt;/h2&gt;

&lt;p&gt;After pushing our Angular Scully blog to github, we are ready to deploy on Netlify. If you do not have an account yet, you can &lt;a href="https://app.netlify.com/signup" rel="noopener noreferrer"&gt;signup here&lt;/a&gt; or go ahead and log in to your account if you have one.&lt;br&gt;&lt;br&gt;
Choose import from git&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%2Fmi2uk2v6ay84fkotmtiq.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%2Fmi2uk2v6ay84fkotmtiq.png" alt="import from git"&gt;&lt;/a&gt; &lt;br&gt;
Select Github&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%2Fvttrs4mfnsvk5cwbrwli.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%2Fvttrs4mfnsvk5cwbrwli.png" alt="create site on netlify"&gt;&lt;/a&gt;&lt;br&gt;
Connect the repository you want to deploy. You may need to configure netlify for your github account if it has not been setup. This is needed for netlify to have access to the repository&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%2F6162j679b1im5b05rn1a.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%2F6162j679b1im5b05rn1a.png" alt="connect repo"&gt;&lt;/a&gt;&lt;br&gt;
Provide the path to the folder where the scully generated static pages are as well as the build command&lt;br&gt;&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%2Ffopcljobmo13vwgtaie3.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%2Ffopcljobmo13vwgtaie3.png" alt="deploy site"&gt;&lt;/a&gt;&lt;br&gt;
Click the &lt;code&gt;Deploy site&lt;/code&gt; button and watch as netlify builds your project.&lt;br&gt;
Congratulations on making it to the end and have fun personalising your site as you like.&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%2Ftenor.com%2Fview%2Fnaruto-kakashi-dance-dancing-happy-gif-4899160.gif" 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%2Ftenor.com%2Fview%2Fnaruto-kakashi-dance-dancing-happy-gif-4899160.gif" alt="Yay"&gt;&lt;/a&gt;&lt;br&gt;
Here's a link to the &lt;a href="https://angular-scully-site.netlify.app/" rel="noopener noreferrer"&gt;deployed site&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I do hope this article has been helpful in guiding you through creating your blog site with Angular and scully from scratch.&lt;br&gt;
You can leave questions or suggestions in the comments or reach out to me on twitter &lt;a href="https://twitter.com/BrunoElo" rel="noopener noreferrer"&gt;BrunoElo&lt;/a&gt; if you like. Thanks for reading!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>jamstack</category>
      <category>netlify</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
