<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Fábio Borges</title>
    <description>The latest articles on Forem by Fábio Borges (@fborges42).</description>
    <link>https://forem.com/fborges42</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%2F300090%2F0984a146-a141-43cf-acfe-e54772e6366f.PNG</url>
      <title>Forem: Fábio Borges</title>
      <link>https://forem.com/fborges42</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fborges42"/>
    <language>en</language>
    <item>
      <title>Using Matomo on Angular</title>
      <dc:creator>Fábio Borges</dc:creator>
      <pubDate>Tue, 03 May 2022 10:41:49 +0000</pubDate>
      <link>https://forem.com/fborges42/using-matomo-on-angular-l3d</link>
      <guid>https://forem.com/fborges42/using-matomo-on-angular-l3d</guid>
      <description>&lt;p&gt;If you haven’t heard about &lt;a href="https://matomo.org/" rel="noopener noreferrer"&gt;Matomo&lt;/a&gt;, yet, then you should check this out.&lt;/p&gt;

&lt;p&gt;Matomo is a &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Google Analytics alternative that protects your data and your customers' privacy” and that “gives you 100% data ownership”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is great news for those of you who are GDPR aware and unfortunately (for some) aren’t able to use cloud services like Google Analytics.&lt;/p&gt;

&lt;h2&gt;
  
  
  OK, so where can we start?
&lt;/h2&gt;

&lt;p&gt;On this guide, I’ll help you configure an “on-premise” installation of Matomo using Docker with nginx, and running it on Angular.&lt;/p&gt;

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

&lt;p&gt;All the info I’m sharing can be found at &lt;a href="https://github.com/matomo-org/docker" rel="noopener noreferrer"&gt;matomo-org/docker&lt;/a&gt; and &lt;a href="https://github.com/EmmanuelRoux/ngx-matomo" rel="noopener noreferrer"&gt;EmmanuelRoux/ngx-matomo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some tweaks can be found in my git &lt;a href="https://github.com/fborges42/matomo-angular-docker" rel="noopener noreferrer"&gt;matomo-angular-docker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m also assuming you already installed docker on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up your docker
&lt;/h2&gt;

&lt;p&gt;This setup is for Matomo version 3 and includes a database with MySQL image (you could use MariaDB as well), the Matomo app and the web using nginx. &lt;/p&gt;

&lt;p&gt;First thing is first, let’s get the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file. &lt;/p&gt;

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

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--max-allowed-packet=64MB&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db:/var/lib/mysql&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=matomo&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db.env&lt;/span&gt;

  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;matomo:fpm-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;links&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;matomo:/var/www/html&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MATOMO_DATABASE_HOST=db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PHP_MEMORY_LIMIT=2048M&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db.env&lt;/span&gt;

  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;matomo:/var/www/html:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./matomo.conf:/etc/nginx/conf.d/default.conf:ro&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:80&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matomo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Nothing fancy here, Matomo will be running on port 8080, and you can of course change the values like &lt;code&gt;MYSQL_ROOT_PASSWORD&lt;/code&gt; or the restart option (which if you don’t know, keeps restarting the container in case of failure).&lt;/p&gt;

&lt;p&gt;In case you didn’t notice, we’re referencing two other files in this compose.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;db.env&lt;/code&gt; where we will set some variables for MySQL image&lt;/p&gt;

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

&lt;span class="s"&gt;MYSQL_PASSWORD=matomo&lt;/span&gt;
&lt;span class="s"&gt;MYSQL_DATABASE=matomo&lt;/span&gt;
&lt;span class="s"&gt;MYSQL_USER=matomo&lt;/span&gt;
&lt;span class="s"&gt;MATOMO_DATABASE_ADAPTER=mysql&lt;/span&gt;
&lt;span class="s"&gt;MATOMO_DATABASE_TABLES_PREFIX=matomo_&lt;/span&gt;
&lt;span class="s"&gt;MATOMO_DATABASE_USERNAME=matomo&lt;/span&gt;
&lt;span class="s"&gt;MATOMO_DATABASE_PASSWORD=matomo&lt;/span&gt;
&lt;span class="s"&gt;MATOMO_DATABASE_DBNAME=matomo&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And &lt;code&gt;matomo.conf&lt;/code&gt; file where we’re defining some behaviour for Matomo nginx.&lt;/p&gt;

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

&lt;span class="s"&gt;upstream php-handler {&lt;/span&gt;
    &lt;span class="s"&gt;server app:9000;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="s"&gt;server {&lt;/span&gt;
    &lt;span class="s"&gt;listen 80;&lt;/span&gt;

    &lt;span class="s"&gt;add_header Referrer-Policy origin;&lt;/span&gt; &lt;span class="c1"&gt;# make sure outgoing links don't show the URL to the Matomo instance&lt;/span&gt;
    &lt;span class="s"&gt;root /var/www/html;&lt;/span&gt; &lt;span class="c1"&gt;# replace with path to your matomo instance&lt;/span&gt;
    &lt;span class="s"&gt;index index.php;&lt;/span&gt;
    &lt;span class="s"&gt;try_files $uri $uri/ =404;&lt;/span&gt;

    &lt;span class="s"&gt;## only allow accessing the following php files&lt;/span&gt;
    &lt;span class="s"&gt;location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs).php {&lt;/span&gt;
        &lt;span class="s"&gt;# regex to split $uri to $fastcgi_script_name and $fastcgi_path&lt;/span&gt;
        &lt;span class="s"&gt;fastcgi_split_path_info ^(.+\.php)(/.+)$;&lt;/span&gt;

        &lt;span class="s"&gt;# Check that the PHP script exists before passing it&lt;/span&gt;
        &lt;span class="s"&gt;try_files $fastcgi_script_name =404;&lt;/span&gt;

        &lt;span class="s"&gt;include fastcgi_params;&lt;/span&gt;
        &lt;span class="s"&gt;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;&lt;/span&gt;
        &lt;span class="s"&gt;fastcgi_param PATH_INFO $fastcgi_path_info;&lt;/span&gt;
        &lt;span class="s"&gt;fastcgi_param HTTP_PROXY "";&lt;/span&gt; &lt;span class="c1"&gt;# prohibit httpoxy: https://httpoxy.org/&lt;/span&gt;
        &lt;span class="s"&gt;fastcgi_pass php-handler;&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;

    &lt;span class="s"&gt;## deny access to all other .php files&lt;/span&gt;
    &lt;span class="s"&gt;location ~* ^.+\.php$ {&lt;/span&gt;
        &lt;span class="s"&gt;deny all;&lt;/span&gt;
        &lt;span class="s"&gt;return 403;&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;

    &lt;span class="s"&gt;## disable all access to the following directories&lt;/span&gt;
    &lt;span class="s"&gt;location ~ /(config|tmp|core|lang) {&lt;/span&gt;
        &lt;span class="s"&gt;deny all;&lt;/span&gt;
        &lt;span class="s"&gt;return 403;&lt;/span&gt; &lt;span class="c1"&gt;# replace with 404 to not show these directories exist&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
    &lt;span class="s"&gt;location ~ /\.ht {&lt;/span&gt;
        &lt;span class="s"&gt;deny all;&lt;/span&gt;
        &lt;span class="s"&gt;return 403;&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;

    &lt;span class="s"&gt;location ~ js/container_.*_preview\.js$ {&lt;/span&gt;
        &lt;span class="s"&gt;expires off;&lt;/span&gt;
        &lt;span class="s"&gt;add_header Cache-Control 'private, no-cache, no-store';&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;

    &lt;span class="s"&gt;location ~ \.(gif|ico|jpg|png|svg|js|css|htm|html|mp3|mp4|wav|ogg|avi|ttf|eot|woff|woff2|json)$ {&lt;/span&gt;
        &lt;span class="s"&gt;allow all;&lt;/span&gt;
        &lt;span class="s"&gt;## Cache images,CSS,JS and webfonts for an hour&lt;/span&gt;
        &lt;span class="s"&gt;## Increasing the duration may improve the load-time, but may cause old files to show after an Matomo upgrade&lt;/span&gt;
        &lt;span class="s"&gt;expires 1h;&lt;/span&gt;
        &lt;span class="s"&gt;add_header Pragma public;&lt;/span&gt;
        &lt;span class="s"&gt;add_header Cache-Control "public";&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;

    &lt;span class="s"&gt;location ~ /(libs|vendor|plugins|misc/user) {&lt;/span&gt;
        &lt;span class="s"&gt;deny all;&lt;/span&gt;
        &lt;span class="s"&gt;return 403;&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;

    &lt;span class="s"&gt;## properly display textfiles in root directory&lt;/span&gt;
    &lt;span class="s"&gt;location ~/(.*\.md|LEGALNOTICE|LICENSE) {&lt;/span&gt;
        &lt;span class="s"&gt;default_type text/plain;&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# vim: filetype=nginx&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Up up we go!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5sqgc9k9xu5mc5oez20.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%2Fq5sqgc9k9xu5mc5oez20.png" alt="Hot air balloon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to run the docker-compose file. For this, just open your favourite terminal (I like ZSH!) on the root of the folder where you have the file in and execute the command &lt;code&gt;docker-compose up&lt;/code&gt;. This will create the needed volumes and images for the new docker containers.&lt;/p&gt;

&lt;p&gt;If you now head to your &lt;a href="http://localhost:8080/" rel="noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt;, and you did exactly as I said, you’ll see that Matomo is ready to be configured.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Matomo
&lt;/h2&gt;

&lt;p&gt;On the Database Setup, make sure you enter the inputs for the values defined on the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;Superuser&lt;/code&gt; step just set up your credentials as you want them and then on &lt;code&gt;Set up a Website&lt;/code&gt; make sure to define your target, in this example it will be &lt;a href="https://localhost:4200/" rel="noopener noreferrer"&gt;https://localhost:4200&lt;/a&gt; which is where we will be running our angular application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problems ahead?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj71gm0u4aihcehny0zi.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%2Fsj71gm0u4aihcehny0zi.png" alt="developer thinking"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On ending the setup, you might be faced with a warning stating that Matomo has not been configured to run on your &lt;a href="http://localhost" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; 8080 port.&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%2Fnitpr5codez5csxrb07m.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%2Fnitpr5codez5csxrb07m.png" alt="matomo error"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem is not the problem, savvy?
&lt;/h2&gt;

&lt;p&gt;To get around this, we need to change Matomo &lt;code&gt;config.ini.php&lt;/code&gt; file inside the app container that was created by our compose file.&lt;/p&gt;

&lt;p&gt;The deal is that we basically need to tell Matomo that the port we’re using is a trusted host.&lt;/p&gt;

&lt;p&gt;To do this, run the following command from same folder where docker-compose.yaml is: &lt;code&gt;docker exec -u 0 -it matomo_app /bin/sh&lt;/code&gt; take in consideration that &lt;code&gt;matomo_app&lt;/code&gt; is your container name (in some scenarios you might end up with and suffix like matomo_app_1, just check the name using &lt;code&gt;docker ps&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;If the command ran successfully, then we should be inside the container.&lt;/p&gt;

&lt;p&gt;Now we'll use &lt;code&gt;vi&lt;/code&gt; to edit the Matomo configuration file by running the command &lt;code&gt;vi config/config.ini.php&lt;/code&gt; (make sure your path is &lt;code&gt;/var/www/html&lt;/code&gt;).&lt;br&gt;
Press the key &lt;code&gt;I&lt;/code&gt; to insert data, navigate to the &lt;code&gt;[General]&lt;/code&gt; section and then append the following: &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;General&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;trusted_hosts&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;cors_domains&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Once finished the editing, press the &lt;code&gt;ESC&lt;/code&gt; key, write &lt;code&gt;:wq&lt;/code&gt; and press enter. This will write and quite the editing of the file.&lt;/p&gt;

&lt;p&gt;Trusted hosts will allow you to run Matomo in your defined port (in this scenario it’s 8080) and the CORS will allow your local project to call Matomo on the same port (look at me, doing magic and stuff)&lt;/p&gt;

&lt;h2&gt;
  
  
  Are we there yet?
&lt;/h2&gt;

&lt;p&gt;Almost there, kids. So we got everything up and running, and the only missing link is adding the Matomo package to your angular project and set it up.&lt;/p&gt;

&lt;p&gt;On the angular project, install the package &lt;code&gt;npm install --save @ngx-matomo/tracker&lt;/code&gt; followed by &lt;code&gt;npm install --save @ngx-matomo/router&lt;/code&gt; and then import the modules &lt;code&gt;NgxMatomoTrackerModule&lt;/code&gt; and &lt;code&gt;NgxMatomoRouterModule&lt;/code&gt; into your app.module, so it looks like this&lt;/p&gt;


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

&lt;p&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;br&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgxMatomoTrackerModule&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-matomo/tracker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgxMatomoRouterModule&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-matomo/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&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;br&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;br&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;NgxMatomoTrackerModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;siteId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_MATOMO_SITE_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// your Matomo's site ID (find it in your Matomo's settings)&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;trackerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&lt;a href="http://localhost:8080/" rel="noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// your matomo server root url&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;NgxMatomoRouterModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;&lt;br&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;})&lt;/span&gt;&lt;br&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;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Are we done yet?&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvbjwi6jookre7033cfr.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%2Fbvbjwi6jookre7033cfr.png" alt="Matomo real time dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh, yes, we are! The configuration above is the bare minimum, so you'll have a report for every routing navigation you do. Try navigating back and forward on your angular app and then check the Matomo dashboard, you should see some data appearing.&lt;/p&gt;

&lt;p&gt;This was a very fun and educational exercise for me, and I hope I’ve helped you set up your machine as well.&lt;br&gt;
As always, please feel free to advise, share ideas and, comment! See you soon!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yafy58ns9hgv2zc3rgd.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%2F8yafy58ns9hgv2zc3rgd.png" alt="people bump fist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://unsplash.com/@ashkfor121" rel="noopener noreferrer"&gt;Ashkan Forouzani&lt;/a&gt;, &lt;a href="https://unsplash.com/@punttim" rel="noopener noreferrer"&gt;Tim Gouw&lt;/a&gt; and &lt;a href="https://unsplash.com/@rcrazy" rel="noopener noreferrer"&gt;Ricardo Rocha&lt;/a&gt; for the photos.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why you should stop z-index:9999</title>
      <dc:creator>Fábio Borges</dc:creator>
      <pubDate>Wed, 14 Apr 2021 14:41:50 +0000</pubDate>
      <link>https://forem.com/fborges42/why-you-should-stop-z-index-9999-56mj</link>
      <guid>https://forem.com/fborges42/why-you-should-stop-z-index-9999-56mj</guid>
      <description>&lt;p&gt;Sometimes you just need to handle your custom modal depth, or maybe you had to deal with sticky positioning. We've all been there and there are better ways of achieving this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3omvlqlc6coydg3mqksi.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%2F3omvlqlc6coydg3mqksi.png" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3omvlqlc6coydg3mqksi.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;So I guess you went too far with it, and now you don't actually know what's the difference between &lt;code&gt;z-index:549&lt;/code&gt; and &lt;code&gt;z-index:329&lt;/code&gt;. And why the heck is this table button &lt;code&gt;z-index:9999&lt;/code&gt;? &lt;em&gt;It's ruining my modal!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I won't get too much on the problem side, I guess if you're here you probably know what's happening, and you just need a better approach so let me try and show you different ways of fixing this.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solutions
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4swppfp215qfmuwtc1y4.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%2F4swppfp215qfmuwtc1y4.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say, for the sake of simplicity, that we have 3 levels of depth: &lt;strong&gt;base&lt;/strong&gt;, &lt;strong&gt;footer&lt;/strong&gt;, and &lt;strong&gt;modal&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CSS var approach (&lt;a href="https://en.wikipedia.org/wiki/KISS_principle" rel="noopener noreferrer"&gt;KISS&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;Here we just store those 3 index, so we can use them later.&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;:root&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--footer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&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 then we can just fetch anywhere in the project like so.&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;.table&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;var(--base);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.modal&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;var(--modal)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might need to use CSS vars to be able to manipulate them in JavaScript but in this scenario it's not clear what's inside those variables, and they will be easily lost between many others you might have, maybe a preprocessor could help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;More on the 100 range gaps next.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a preprocessor (&lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;SASS&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;Same idea here but maybe a bit more organized. The idea here is to store those default values inside the &lt;code&gt;$zindex&lt;/code&gt; variable that we can access and manage it better.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nv"&gt;$zindex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fetch the values we can use &lt;a href="https://sass-lang.com/documentation/values/maps" rel="noopener noreferrer"&gt;maps&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nc"&gt;.modal&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$zindex&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.footer&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$zindex&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But why the heck are we gapping 100 values?
&lt;/h2&gt;

&lt;p&gt;Sometimes you might even see it in 1000 range gaps, but the main reason for this is just in case you need to add something in between and since &lt;code&gt;z-index&lt;/code&gt; can't handle decimal numbers you're safer doing it this way.&lt;br&gt;
&lt;em&gt;Even if you don't add 99 extra items between depth.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting funky with it
&lt;/h2&gt;

&lt;p&gt;Unless you're doing a tiny project you'll probably need to deal with a lot of deeper depth levels, but that's not a problem.&lt;/p&gt;

&lt;p&gt;Since we have default values for all the depths lets think in a scenario where you might have the need to have way more management over a modal. Here's what we can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nv"&gt;$zindex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;210&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;220&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;230&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;.modal&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$zindex&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

  &lt;span class="nc"&gt;.modal__btn--close&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map-get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$zindex&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;...&lt;/span&gt; 
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;There's a lot more ways of handling &lt;code&gt;z-index&lt;/code&gt; you just need to get creative and keep things organized. It's pretty clear we can all do a better job with it. &lt;/p&gt;

&lt;p&gt;Do you have a different or easier way of doing it? Let others know on the comments!&lt;/p&gt;

&lt;p&gt;I hope this could help someone out. Cheers, see you soon!&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://unsplash.com/@didsss" rel="noopener noreferrer"&gt;https://unsplash.com/@didsss&lt;/a&gt; for the header image :)&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to automate a Javascript project versioning</title>
      <dc:creator>Fábio Borges</dc:creator>
      <pubDate>Wed, 30 Dec 2020 17:53:52 +0000</pubDate>
      <link>https://forem.com/fborges42/how-to-automate-a-javascript-project-versioning-43bd</link>
      <guid>https://forem.com/fborges42/how-to-automate-a-javascript-project-versioning-43bd</guid>
      <description>&lt;p&gt;Sooner or later all developers need to handle some sort of versioning their software. If you've been there you know that &lt;strong&gt;manual updating&lt;/strong&gt; versions, &lt;strong&gt;changelogs&lt;/strong&gt;, and &lt;strong&gt;tags&lt;/strong&gt; are &lt;strong&gt;prone to error and emotional decisions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll try to show an easy and automated way of managing your versions following the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;conventional commiting&lt;/a&gt; structure and with the help of &lt;a href="https://github.com/conventional-changelog/standard-version"&gt;standard-version&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install standard-version
&lt;/h1&gt;

&lt;p&gt;Let us start with installing our package&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i standard-version -D&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, for the purpose of easiness add the following script to your &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "scripts": {
    "release": "standard-version"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  How it works
&lt;/h1&gt;

&lt;p&gt;Our package needs us to follow the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;Conventional Commits Rules&lt;/a&gt; in the repository. This means that we must use the correct syntax. &lt;/p&gt;

&lt;p&gt;Here is an overview of how it's done:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;fix&lt;/strong&gt; for a &lt;strong&gt;&lt;code&gt;PATCH&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;feat&lt;/strong&gt; for a &lt;strong&gt;&lt;code&gt;MINOR&lt;/code&gt;&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;!&lt;/strong&gt; scope suffix for a &lt;strong&gt;&lt;code&gt;MAJOR&lt;/code&gt;&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the commits must follow the pattern &lt;code&gt;scope!: message&lt;/code&gt; the &lt;strong&gt;!&lt;/strong&gt; is optional for a &lt;strong&gt;&lt;code&gt;MAJOR&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: new reset password button` -&amp;gt; 0.1.0
feat!: new reset password button` -&amp;gt; 1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Workflow
&lt;/h1&gt;

&lt;p&gt;Now that all is configured and we've understood the ground rules for automated versioning, let's have a look at a simplistic view of how a workflow should be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developing a feature on a feature branch&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit -m "feat: created a reset password"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Merging to the master branch&lt;/strong&gt; - &lt;em&gt;this is where the magic happens&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git merge origin/feature-branch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run standard-version&lt;/code&gt; &lt;em&gt;- the package is looking into the commit history and automatically increasing your API version to X.Y.Z&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git push —follow-tags origin master&lt;/code&gt; - &lt;em&gt;this is pushing your bumped with the changelog file and tags generated&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;And that's all!&lt;/strong&gt; You should be able to see on your &lt;code&gt;master&lt;/code&gt; branch the corresponding bumped version with the changelog file and all linked to a tag.&lt;/p&gt;

&lt;h1&gt;
  
  
  Common mistake
&lt;/h1&gt;

&lt;p&gt;According the &lt;a href="https://semver.org/"&gt;semver&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means that until you intentionally run &lt;code&gt;npm run release -- --release-as major&lt;/code&gt; you won't see your major version bumping from &lt;strong&gt;0.y.z&lt;/strong&gt; to &lt;strong&gt;1.y.z&lt;/strong&gt;. From this moment on, the package will do its job and bump major versions as well.&lt;/p&gt;

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

&lt;p&gt;Bumping versions based on &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;conventional commiting&lt;/a&gt; convention of rules is seen as a good practice in order to have an explicit commit history. &lt;br&gt;
With the help of &lt;a href="https://github.com/conventional-changelog/standard-version"&gt;standard-version&lt;/a&gt; we've seen above we are able to automatically bump versions and track changes each time an artifact is released into production.&lt;/p&gt;

&lt;h5&gt;
  
  
  Special thanks to &lt;a href="https://unsplash.com/@csoref"&gt;https://unsplash.com/@csoref&lt;/a&gt; for the header image :)
&lt;/h5&gt;

</description>
      <category>javascript</category>
      <category>codequality</category>
      <category>programming</category>
    </item>
    <item>
      <title>VSCode tips for productivity</title>
      <dc:creator>Fábio Borges</dc:creator>
      <pubDate>Tue, 18 Feb 2020 19:56:58 +0000</pubDate>
      <link>https://forem.com/fborges42/vscode-tips-for-productivity-3j24</link>
      <guid>https://forem.com/fborges42/vscode-tips-for-productivity-3j24</guid>
      <description>&lt;p&gt;Hello all, here are some productivity tips for everyday use.&lt;/p&gt;

&lt;h1&gt;
  
  
  Keybindings
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nb-XkIb9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/72c3brmm555gigb8ff1a.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nb-XkIb9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/72c3brmm555gigb8ff1a.jpeg" alt="F47A0653-6DA0-42E7-8590-2A6D864566D6_4_5005_c" width="524" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reload window
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bvN5lOwH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9am5fd5y2wpzvr94pj3d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bvN5lOwH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9am5fd5y2wpzvr94pj3d.png" alt="Screenshot 2020-12-30 at 10.14.51" width="880" height="96"&gt;&lt;/a&gt; &lt;br&gt;
For some reason, something that, from time to time, happens is that I get syntax error highlights although nothing is wrong in the code.&lt;br&gt;
For these situations or any of the likes, I've created a key combination to reload the window which acts the same way a reload on an online page would act.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uppercase and Lowercase
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3QAdP2DG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/35vvzplamh1gdblf10nv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3QAdP2DG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/35vvzplamh1gdblf10nv.png" alt="Screenshot 2020-12-30 at 10.05.40" width="880" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another one I use a lot, especially when I'm getting classes from &lt;em&gt;Pascal Case&lt;/em&gt; into &lt;em&gt;camel case&lt;/em&gt;, is to &lt;strong&gt;UPPERCASE&lt;/strong&gt; or &lt;strong&gt;lowercase&lt;/strong&gt; an entire string of text. &lt;br&gt;
I know there's a combination on VS Code for this, however, I like to have my combo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Zen mode
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bfIDz7ZR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/69z6zbq0fvoyr5ozf5e8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bfIDz7ZR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/69z6zbq0fvoyr5ozf5e8.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
Love it or hate it. I'm not very keen on this one but I do know a couple of people who like it and use it a lot. This feature allows the user to enter the 'flow state' and focus only on the code - it's really good if you know your way around shortcuts. &lt;br&gt;
You can access the zen mode through the command palette doing &lt;strong&gt;cmd + shift + p&lt;/strong&gt; and write &lt;strong&gt;zen mode&lt;/strong&gt;. To exit just repeat the steps.&lt;/p&gt;

&lt;h1&gt;
  
  
  Incredible long files
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KStNE0h_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gzlvd6e3goe8oj4e58jr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KStNE0h_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gzlvd6e3goe8oj4e58jr.png" alt="Alt Text" width="616" height="313"&gt;&lt;/a&gt;&lt;br&gt;
Fortunately, VSCode allows us to search inside our files in a friendlier way than just scrolling through 1000 lines of code.&lt;br&gt;
By doing &lt;strong&gt;cmd + p&lt;/strong&gt; and typing &lt;strong&gt;@&lt;/strong&gt;, we get a list of the current file organized methods and properties that we can select and navigate directly into. If you want an in-depth list, you can use the &lt;strong&gt;@:&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Go to line
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ft0nCbfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k0q34ajq51cjou9tjsbo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ft0nCbfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k0q34ajq51cjou9tjsbo.png" alt="Alt Text" width="616" height="101"&gt;&lt;/a&gt;&lt;br&gt;
We can also use the go-to command by doing &lt;strong&gt;cmd + p&lt;/strong&gt; and typing &lt;strong&gt;:&lt;/strong&gt;&lt;br&gt;
This one is pretty easy and we do have a keybinding for it but I find this way faster and easier on the brain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Too much info?
&lt;/h3&gt;

&lt;p&gt;If you find it hard to memorize these commands just "ask for help" by doing &lt;strong&gt;cmd + p&lt;/strong&gt; and typing &lt;strong&gt;?&lt;/strong&gt;. You'll get a full list of the available commands.&lt;/p&gt;

&lt;p&gt;That's all folks, I hope you find my tips helpful.&lt;br&gt;
Do you have any productivity tips to share? Leave it on the comments, I'll be glad to check them out!&lt;/p&gt;

&lt;p&gt;Cover photo by Hello I'm Nik 🍌 on Unsplash - Thanks!&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>development</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>My 2019 in a nutshell.</title>
      <dc:creator>Fábio Borges</dc:creator>
      <pubDate>Thu, 26 Dec 2019 16:12:58 +0000</pubDate>
      <link>https://forem.com/fborges42/my-2019-in-a-nutshell-3md5</link>
      <guid>https://forem.com/fborges42/my-2019-in-a-nutshell-3md5</guid>
      <description>&lt;p&gt;Last year, around the same day, I created the classical new years' resolution list, but this time it was different. I went and try to do everything on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read 10 to 12 books this year&lt;/strong&gt;&lt;br&gt;
I've never been much of a reader and never liked books either. But one lovely day I got curious about what do great minds in my field have in common. &lt;br&gt;
People like Bill Gates, Elon Musk, Steve Jobs, Jeff Bezos, and many others have an interest in reading, side by side with things like waking up early, have a quiet and alone time, pre organize the day and so on.&lt;br&gt;
So I started reading books about personal finance, which is something I'm interested in, and I highly recommend you start with something you will like aswell - I'm not into fiction/romance but that's ok ( I think ). &lt;br&gt;
I then moved slowly to more technical books and the last one I bought was &lt;em&gt;Steal Like an Artist - by Austin Kleon&lt;/em&gt; which is a small book with some insights on how to be creative that I found useful for the next topic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start freelancing&lt;/strong&gt;&lt;br&gt;
I always had a crush on front end development but never went after something outside my 9 to 6 job as a full-stack. This year I changed it by doing some freelancing. &lt;br&gt;
The extra money is great, but have you ever done something different for yourself? I've not only improved my skills as a developer but also as a communicator and web designer. Being a freelance made me aware of the importance of organizing my CSS, have a good and simple deploy pipeline, and I started using Figma for the first time. I've also become more aware of my value as a professional which is something everyone should be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invest in my work&lt;/strong&gt;&lt;br&gt;
I bought a couple of online courses to help me improve some specific skillset like angular, react and CSS.&lt;br&gt;
I also had an old beaten laptop which would from time to time get stuck during boot and couldn't really handle my unorganized universe of 1000 tabs on chrome and so I bought myself a brand new MacBook Pro 15''. As a first time using macOS it was a bit of a struggle but everything is fine now, and NPM runs smoother as well. So win-win plus I can now sit on Starbucks working - just kidding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimalism&lt;/strong&gt;&lt;br&gt;
Oh boy... Let me tell you... Everything I owned I had probably two or three of it. This was turning my home office into an unorganized hell aswell as my life. But not only that, I was trying to do so much at once that I was procrastinating everything around me. So, new year new me, I started cleansing my mindset. I've donated a lot of clothes, shoes, throw away unnecessary stuff like broken chargers and headphones, old parts of laptops, old demo CDs and the biggest thing of all, I scanned all my receipts and invoices and threw every paper on the trash.&lt;br&gt;
There's still a long way to go but I've found myself a bit more productive, more organized and the air is a bit more breathable now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Financial Education&lt;/strong&gt;&lt;br&gt;
So after getting some cleansing on my mind, I decided it was time for me to take a short leech on my money spending. I fixed a budget for monthly spend on leisure, house expenses, and investments. Since I started to question myself "what's the value this item can bring to my life" I started buying less and thus spending less, so my monthly budget decreased and I've been able to apply the remaining money to lower some credits I have. Less is more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health &amp;amp; Mindfulness&lt;/strong&gt;&lt;br&gt;
I'm a remote worker so I find myself locked "in the basement" for days in a row. This has led me to a decrease in my immune system and thus my calm and zen posture ended up revealing that I have some sort of fake nervous personality and so I started getting some problems with health. This was the year I started to make this a priority in my life and thus trying to chill a bit more, definitely leaving the house more often and just enjoy life - I must say my new minimalist lifestyle is helping here as well.&lt;/p&gt;

&lt;p&gt;So this is it! I didn't plan it, however, I'm finishing this year by writing my first (of many, so I hope) posts on dev.to. &lt;br&gt;
I'll try to keep it going next year but maybe focusing more on web development. &lt;br&gt;
I hope you guys liked this and don't forget it's never too late to start something. You are your only concurrence and enemy, beat your self and become better than yesterday.&lt;/p&gt;

</description>
      <category>retrospective</category>
      <category>goals</category>
      <category>motivation</category>
    </item>
  </channel>
</rss>
