<?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: Kayode</title>
    <description>The latest articles on DEV Community by Kayode (@zt4ff_1).</description>
    <link>https://dev.to/zt4ff_1</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%2F521316%2Fb93a621d-6b76-43bb-b8e9-3e6f0ee90134.jpg</url>
      <title>DEV Community: Kayode</title>
      <link>https://dev.to/zt4ff_1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zt4ff_1"/>
    <language>en</language>
    <item>
      <title>Effective Neovim Setup. A Beginner’s Guide</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sat, 09 Mar 2024 14:53:03 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/effective-neovim-setup-a-beginners-guide-1i81</link>
      <guid>https://dev.to/zt4ff_1/effective-neovim-setup-a-beginners-guide-1i81</guid>
      <description>&lt;p&gt;Vim is a text editor that comes preinstalled with most major Linux distributions. It’s a highly customizable editor and it can be a productivity improvement for developers when utilized well.&lt;/p&gt;

&lt;p&gt;Vim encourages the use of keyboards with several keybindings that can operate differently in different modes thereby minimizing the need for a mouse. &lt;/p&gt;

&lt;p&gt;Simply put, Vim is an editor that can match the speed at which you think.&lt;/p&gt;

&lt;p&gt;Neovim is an extension of Vim. It’s built for users who want the good parts of Vim, and more.&lt;/p&gt;

&lt;p&gt;You can read more about the vision of Neovim &lt;a href="https://neovim.io/charter/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note: For the article, we are using &lt;a href="http://www.lazyvim.org/" rel="noopener noreferrer"&gt;LazyVim&lt;/a&gt; to configure our Neovim setup. LazyVim makes it easy to customize and extend Neovim’s configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Neovim
&lt;/h2&gt;

&lt;p&gt;There are several ways to install Neovim. This &lt;a href="https://github.com/neovim/neovim/blob/master/INSTALL.md" rel="noopener noreferrer"&gt;wiki&lt;/a&gt; provides several guidelines on how to install Neovim. &lt;/p&gt;

&lt;p&gt;I use an Arch Linux machine so it was easy to install Neovim by running the command:&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;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On a Windows machine, you can use &lt;a href="https://chocolatey.org/" rel="noopener noreferrer"&gt;Chocolatey&lt;/a&gt; by running the command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On a macOS machine, you can use &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;homebrew&lt;/a&gt; by running the command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once Neovim is installed, we can confirm that it exists by running the command.&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;The output should look similar to the image below.&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%2Fhchx3xng3ju60ds4tlt4.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%2Fhchx3xng3ju60ds4tlt4.png" alt="basic neovim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up LazyGit
&lt;/h2&gt;

&lt;p&gt;There are some requirements needed to set up LazyVim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Neovim (we have this installed already)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git" rel="noopener noreferrer"&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://www.nerdfonts.com/" rel="noopener noreferrer"&gt;Nerd Font&lt;/a&gt; (optional but needed to display icons)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we will clone the LazyVim starter repository into our  Neovim runtime path.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/.config/nvim&lt;/code&gt; is the Neovim’s runtime path for macOS and Linux machines while &lt;code&gt;~/AppData/local/nvim&lt;/code&gt; is for Windows machines. &lt;/p&gt;

&lt;p&gt;Since I am not an Arch Linux machine, I’d run the command below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LazyVim/starter ~/.config/nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run the command &lt;code&gt;nvim&lt;/code&gt; again to confirm that it is set up.&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%2Fwrxnkixmcj8n2gi1hotq.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%2Fwrxnkixmcj8n2gi1hotq.png" alt="lazyvim-basic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Plugins Installation
&lt;/h2&gt;

&lt;p&gt;LazyVim comes with a wealth of plugins pre-configured and ready to use. This section of the article will introduce two more plugins that can greatly improve your Neovim experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;nvim-telescope&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is a highly extendable fuzzy finder over lists. To install this plugin, you can create a new file in the &lt;code&gt;plugins&lt;/code&gt; directory of your Neovim config path named &lt;code&gt;telescope.lua&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.config/nvim/lua/plugins/&lt;span class="p"&gt;;&lt;/span&gt; nvim telescope.lua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then paste the code below into the &lt;code&gt;telescope.lua&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;--telescope.lua&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"nvim-telescope/telescope.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.1.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"nvim-lua/plenary.nvim"&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;Then in &lt;code&gt;~/.config/nvim/lua/config/lazy.lua&lt;/code&gt; you can add this below the last line.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'telescope.builtin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;C-p&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;live_grep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fb'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;help_tags&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 code above set up keymaps to execute some of the functions provided by nvim-telescope.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;C-p&amp;gt;&lt;/code&gt; keymap is a &lt;code&gt;Ctrl + p&lt;/code&gt; keybinding that opens a fuzzy finder for files in a modal.&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%2Fg0fnolox6p83qla98snw.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%2Fg0fnolox6p83qla98snw.png" alt="treesitter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;nvim-treesitter&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is a plugin that provides a simple way to use the &lt;a href="https://github.com/tree-sitter/tree-sitter" rel="noopener noreferrer"&gt;tree-sitter&lt;/a&gt; in Neovim and also provides functionalities like highlighting, etc.&lt;/p&gt;

&lt;p&gt;Just like we did for the nvim-telescope plugin, we will create a new file in the &lt;code&gt;plugins&lt;/code&gt; directory of Neovim’s configuration called &lt;code&gt;treesitter.lua&lt;/code&gt; and then paste the code below into it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- treesitter.lua&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lazy"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&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;"nvim-treesitter/nvim-treesitter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;":TSUpdate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; 
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;configs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"nvim-treesitter.configs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="n"&gt;ensure_installed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"lua"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"vim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"vimdoc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"elixir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"heex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"javascript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"html"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="n"&gt;sync_install&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="n"&gt;indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;  
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;ensure-installed&lt;/code&gt; is a tuple that includes various languages you want to include the parser support for. &lt;/p&gt;

&lt;p&gt;You can see a list of supported languages &lt;a href="https://github.com/nvim-treesitter/nvim-treesitter?tab=readme-ov-file#supported-languages" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This is a very basic introduction to getting Neovim set up quickly.&lt;/p&gt;

&lt;p&gt;Using Neovim can be very uncomfortable for the first time especially when you have habits that is different from from what Vim preaches. It will be a slow painful start but in no time, you will pick it up. &lt;/p&gt;

&lt;p&gt;And do not be overwhelmed with trying to learn everything about Vim for a start. Pick up the barest minimum you need to get started and grow with that.&lt;/p&gt;

</description>
      <category>vim</category>
      <category>beginners</category>
      <category>neovim</category>
    </item>
    <item>
      <title>Optimizing Older PCs to Learn How to Code</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Mon, 11 Dec 2023 23:32:42 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/optimizing-older-pcs-to-learn-how-to-code-1a04</link>
      <guid>https://dev.to/zt4ff_1/optimizing-older-pcs-to-learn-how-to-code-1a04</guid>
      <description>&lt;p&gt;Do you have an old clunky laptop and you want to learn programming, this is a simple guide to help you utilize the little resources available to you.&lt;/p&gt;

&lt;p&gt;When I started learning how to code, I had a Dell Inspiron with 2GB RAM and an old processor that I don’t even remember again. Following the guides listed below helped me use my Inspiron to get my first-ever paid job until I was able to afford a better laptop. &lt;/p&gt;

&lt;p&gt;N.B: This might not be the best experience but it’s always greater than no experience.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Discard Windows and install Linux&lt;/strong&gt;: &lt;br&gt;
Lighter variations of Linux are known to operate functionally on old PCs. Giving up Windows and your favourite software might be hard but we are running on limited resources and we need the best output as much as we can. &lt;/p&gt;

&lt;p&gt;Moreover, many Linux distros are beginner-friendly and can play your favourite media type. &lt;br&gt;
Select a user-friendly and lightweight Linux distribution for beginners. Consider options like Ubuntu-based distributions (Lubuntu, Xubuntu) or Linux Mint with the XFCE desktop environment for a familiar and efficient experience.&lt;/p&gt;

&lt;p&gt;Here’s an installation guide on some recommended options&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lubuntu’s &lt;a href="https://manual.lubuntu.me/stable/1/1.3/installation.html"&gt;installation guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Xubuntu’s &lt;a href="https://xubuntu.org/download/"&gt;installation guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Linux Mint’s &lt;a href="https://linuxmint-installation-guide.readthedocs.io/en/latest/"&gt;installation guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Linux Lite’s &lt;a href="https://www.linuxliteos.com/manual/install.html"&gt;installation guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Turn off desktop effects and animation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use lightweight software alternatives&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manage Startup Application&lt;/strong&gt;: &lt;br&gt;
Manage your startup applications by removing unused applications to improve speed time and save resources&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser Optimization&lt;/strong&gt;: &lt;br&gt;
Web browsers can be resource-hungry. Removing or disabling unnecessary browser extensions can be one way to improve your browser extensions. &lt;br&gt;
You can switch to light browsers like Midori or research ways to optimize settings in popular browsers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;I hope you find this helpful and that it points you in the right direction. You don’t have you wait for a better PC, you can start now with what you’ve got. &lt;/p&gt;

&lt;p&gt;I am available to help, you can always reach me via:&lt;/p&gt;

&lt;p&gt;X (Twitter): &lt;a href="https://twitter.com/zt4ff"&gt;https://twitter.com/zt4ff&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/oluwasegun-kayode-07879b1aa/"&gt;https://www.linkedin.com/in/oluwasegun-kayode-07879b1aa/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>linux</category>
    </item>
    <item>
      <title>So The Journey Begins - My Startup Story</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sat, 03 Jun 2023 04:34:40 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/so-the-journey-begins-my-startup-story-4ga7</link>
      <guid>https://dev.to/zt4ff_1/so-the-journey-begins-my-startup-story-4ga7</guid>
      <description>&lt;p&gt;Hi friends 👋🏽. It's been a while since I heard from you. I hope you are doing well and are doing great.&lt;/p&gt;

&lt;p&gt;Since the last time I wrote here, there have been a lot of interesting things happening to me, both good and otherwise. I wish to write about them here, but that would defeat the purpose of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Startups?
&lt;/h2&gt;

&lt;p&gt;The reason I want to create startups is that owning a business has proven to have certain benefits such as financial gain and potential for growth. Moreover, some people exceed their peak capacity or creativity where there is no predictable path to follow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Little disclaimer here: I am more focused on product development right now rather than other aspects that make up a business. I am going solo right now, but I hope to make some friends (with you) along the way to build awesome and useful products.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Which Startups?
&lt;/h2&gt;

&lt;p&gt;Or rather, which products? Currently, I am interested in dev tools and utilities. Being a developer for over 4 years, I have created helpful tools or scripts to help me do my job faster, and I have occasionally contributed to such tools. I aim to build on this foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Plans?
&lt;/h2&gt;

&lt;p&gt;I am new to this. My approach to this is to learn as it unfolds. Many of the products I will build may never be used by anybody, but I will make sure to learn, have fun, and document my experience.&lt;/p&gt;

&lt;p&gt;Since I primarily write TypeScript, I found a tool called &lt;a href="https://redwoodjs.com/"&gt;Redwood.js&lt;/a&gt; that helps you bootstrap your project so you can develop faster. I was part of their showcase event recently, and I love many of the products that are being built with it. Moreover, Redwood.js has a community of founders who are usually helpful, especially when you are just starting this journey or going solo.&lt;/p&gt;

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

&lt;p&gt;I started working on a project a month ago, and I look forward to shipping it and sharing it with you. It’s a tool that is guaranteed to help firms and individuals automate their content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Will You Join Me?
&lt;/h2&gt;

&lt;p&gt;I created a newsletter dedicated to documenting my experience, the experience of others, courses, opportunities, job openings, investment opportunities, and many more, and this journey continues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://zt4ff.substack.com/?r=8n8jt&amp;amp;utm_campaign=pub-share-checklist"&gt;Join me here!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;I would love to hear about your experience building a business on the internet. What works and what didn’t?&lt;/p&gt;

&lt;p&gt;What advice will you give a newbie like me?&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>startup</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Playwright Tutorial for Beginners 2 - Code Generator</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:43:16 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-2-code-generator-feb</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-2-code-generator-feb</guid>
      <description>&lt;h2&gt;
  
  
  Using Playwright test generator (codegen)
&lt;/h2&gt;

&lt;p&gt;Playwright has a feature that allows us to generate tests scripts by interacting with web apps directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating a test script
&lt;/h3&gt;

&lt;p&gt;We will run the below command in our terminal to open a &lt;a href="https://todomvc.com/examples/vanillajs" rel="noopener noreferrer"&gt;todo app&lt;/a&gt;, then we can perform some basic functions of the website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx playwright codegen https://todomvc.com/examples/vanillajs

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;At the time of writing this journal, there is a bug where the Inspect tool window is opened outside of your laptop view, only if you have an external monitor (Playwright somehow assume you have an external monitor, even when you do not).&lt;/p&gt;

&lt;p&gt;More on the issue on GitHub at &lt;a href="https://github.com/microsoft/playwright/issues/5696" rel="noopener noreferrer"&gt;https://github.com/microsoft/playwright/issues/5696&lt;/a&gt; A simple hack I use for now is to manually move the window into view using these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Right-click on Windows taskbar and select cascade windows&lt;/li&gt;
&lt;li&gt;Hold the shift key down and right-click on the app icon and select move&lt;/li&gt;
&lt;li&gt;Use the arrow key to pan the application into view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can comment if you have a fix for this or a better way to do this, please.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fsuodcue81bm760ejwtnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fsuodcue81bm760ejwtnv.png" alt="codegen-initial-state.PNG" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We get this Inspect tool once we run the &lt;code&gt;codegen&lt;/code&gt; command and we can see that a test script is generated showing that the page loads into the URL we provide.&lt;/p&gt;

&lt;p&gt;We can interact with the website and codegen automatically generates a script based on our interaction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fm119f2c7mjkihjebk97i.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fm119f2c7mjkihjebk97i.gif" alt="codegen-in-action.gif" width="760" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generated test scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { test, expect } from '@playwright/test';

test('test', async ({ page }) =&amp;gt; {

  // Go to https://todomvc.com/examples/vanillajs/
  await page.goto('https://todomvc.com/examples/vanillajs/');

  // Click html
  await page.click('html');

  // Click [placeholder="What needs to be done?"]
  await page.click('[placeholder="What needs to be done?"]');

  // Click [placeholder="What needs to be done?"]
  await page.click('[placeholder="What needs to be done?"]');

  // Fill [placeholder="What needs to be done?"]
  await page.fill('[placeholder="What needs to be done?"]', 'play games');

  // Press Enter
  await page.press('[placeholder="What needs to be done?"]', 'Enter');

  // Fill [placeholder="What needs to be done?"]
  await page.fill('[placeholder="What needs to be done?"]', 'watch movies');

  // Press Enter
  await page.press('[placeholder="What needs to be done?"]', 'Enter');

  // Fill [placeholder="What needs to be done?"]
  await page.fill('[placeholder="What needs to be done?"]', 'run to school');

  // Press Enter
  await page.press('[placeholder="What needs to be done?"]', 'Enter');

  // Check text=play gameswatch moviesrun to school &amp;gt;&amp;gt; input[type="checkbox"]
  await page.check('text=play gameswatch moviesrun to school &amp;gt;&amp;gt; input[type="checkbox"]');

  // Check :nth-match(input[type="checkbox"], 3)
  await page.check(':nth-match(input[type="checkbox"], 3)');

  // Click button
  await page.click('button');

  // Click text=Clear completed
  await page.click('text=Clear completed');

  // Click a:has-text("All")
  await page.click('a:has-text("All")');
  await expect(page).toHaveURL('https://todomvc.com/examples/vanillajs/#/');

  // Click button
  await page.click('button');

});

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Following the next tutorials, we will have a full grasp of the scripts generated above.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>testing</category>
      <category>softwaretesting</category>
      <category>playwright</category>
      <category>qualityassurance</category>
    </item>
    <item>
      <title>Playwright Tutorial for Beginners 9 - Assertions</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:09:00 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-9-assertions-2g5c</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-9-assertions-2g5c</guid>
      <description>&lt;h2&gt;
  
  
  Playwright Assertions
&lt;/h2&gt;

&lt;p&gt;Playwright make use of &lt;a href="https://jestjs.io/docs/expect" rel="noopener noreferrer"&gt;expect&lt;/a&gt; library (provided by &lt;a href="https://jestjs.io" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;) for assertions. The library provides different types of matchers like &lt;code&gt;toEqual&lt;/code&gt;, &lt;code&gt;toContain&lt;/code&gt;, &lt;code&gt;toMatch&lt;/code&gt;, &lt;code&gt;toMatchSnapshots&lt;/code&gt; and many more.&lt;/p&gt;

&lt;p&gt;To make use of the library, import it into your test script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { expect } = require('@playwright/test')

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

&lt;/div&gt;



&lt;p&gt;You can extend with async matchers that will wait until the specified assertion condition is met.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(value).toEqual(anotherValue);

await expect(value).toBeTruthy();

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common patterns
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// assert text content
expect(await page.locator('.welcomeMsg').textContent()).toEqual('Welcome pal');

// assert inner text
expect(await page.locator('.goodbyeMsg').innerText()).toBe('Goodbye pal');

// assert inner html
expect(await page.locator('.button-container').innerText()).toEqual(
    '&amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;'
  );

// assert attribute
expect(await page.locator('css=#name-input')).toHaveAttribute('type', 'text');

// assert url
expect(await page.url()).toMatch(/\/users\/test/);

// and many more!

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom assertions
&lt;/h3&gt;

&lt;p&gt;To have custom assertions, you can extend the &lt;code&gt;expect&lt;/code&gt; provided by &lt;a href="https://jestjs.io" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;. For instance, we will create a custom matcher called &lt;code&gt;toBeBetween10And100&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;const { expect, default: test } = require('@playwright/test');

expect.extend({
  toBeBetween10And100(num) {
    const pass = num &amp;gt; 10 &amp;amp;&amp;amp; num &amp;lt; 100;

    if (pass) {
      return {
        message: () =&amp;gt; `expected ${num} to be not within 10 and 100`,
        pass: true
      };
    }
    return {
      message: () =&amp;gt; `expected ${num} to be within 10 and 100`,
      pass: false
    };
  }
});

test('simple test', async () =&amp;gt; {
    // pass
  expect(25).toBeBetween10And100();
});

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

&lt;/div&gt;



&lt;p&gt;There are a bunch of matchers you can use with Playwright depending on what your test suites are.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>qualityassurance</category>
      <category>playwright</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Playwright Tutorial for Beginners 8 - Screenshots</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:08:00 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-8-screenshots-4h69</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-8-screenshots-4h69</guid>
      <description>&lt;p&gt;To screenshot, make use of &lt;code&gt;page.screenshot({ path: 'screenshot/screenshot.png' })&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Full page screenshots
&lt;/h2&gt;

&lt;p&gt;Full page screenshot is a screenshot of a full scrollable page, as if you had a very tall screen and the page could fit it entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.screenshot({ path: 'screenshot.png', fullPage: true });

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Element screenshots
&lt;/h2&gt;

&lt;p&gt;You can also take screenshots of elements too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.locator('.header').screenshot({ path: 'screenshot.png' });

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  An example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { test } = require('@playwright/test');

test('Demo video', async ({ page }) =&amp;gt; {
  await page.goto('https://playwright.dev');
  await page.screenshot({ path: 'screenshot.png' });
});

&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1641909952990%2FH1Iw0ZKq1.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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1641909952990%2FH1Iw0ZKq1.png" alt="screenshot.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>softwaretesting</category>
      <category>playwright</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Playwright Tutorial For Beginners 7 - Videos</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:07:00 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-7-videos-591n</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-7-videos-591n</guid>
      <description>&lt;p&gt;Playwright can record videos for all pages in a &lt;strong&gt;browser context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://playwright.dev/docs/browser-contexts" rel="noopener noreferrer"&gt;BrowserContext&lt;/a&gt; is an isolated incognito-alike session within a browser. Just like when you open an incognito window of your browser, the browser state (cache, cookies etc.) is isolated between test.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using the page provide by Playwright test runner, &lt;code&gt;@playwright/test&lt;/code&gt;, the &lt;code&gt;page&lt;/code&gt; provided in the tests callback opens in a new context out of the box.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To record a video, we will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a new context from a browser with some options in place&lt;/li&gt;
&lt;li&gt;create a new page with from the context&lt;/li&gt;
&lt;li&gt;open a web app in the page&lt;/li&gt;
&lt;li&gt;make sure to close the context (the video is generated after this&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will create a test scripts in &lt;code&gt;demo.spec.js&lt;/code&gt; and run to generate a video:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// demo.spec.js
const { test } = require('@playwright/test');

test('Demo video', async ({ browser }) =&amp;gt; {
  const context = await browser.newContext({ recordVideo: { dir: 'videos' } });
  const page = await context.newPage();
  await page.goto('https://google.com');

  await page.type('input', 'playwright');
  await page.press('input', 'Enter');
  await page.waitForTimeout(1000);

  await context.close();
});

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

&lt;/div&gt;



&lt;p&gt;The test will generate a video in a &lt;code&gt;/videos&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ftzv7tw5dprwzffppcs75.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftzv7tw5dprwzffppcs75.gif" alt="generated video" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>beginners</category>
      <category>playwright</category>
      <category>softwaretesting</category>
    </item>
    <item>
      <title>Playwright Tutorial for Beginners 5 - Performing Actions</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:05:00 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-5-performing-actions-4ibd</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-5-performing-actions-4ibd</guid>
      <description>&lt;h2&gt;
  
  
  Test input
&lt;/h2&gt;

&lt;p&gt;You can easily fill-out form fields with &lt;code&gt;page.fill()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;page.fill()&lt;/code&gt; focuses on the element and triggers an &lt;code&gt;input&lt;/code&gt; event with the specified text. It works on &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;, &lt;code&gt;[contenteditable]&lt;/code&gt; and &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; associated with an input or text area.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { test } = require('@playwright/test');

test('input text into a test element', async ({ page }) =&amp;gt; {
  await page.goto('https://demoblaze.com');
  await page.click('#signin2');
  await page.fill('#sign-username', 'zt4ff');
});

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;To view how the test ran, you can set the &lt;code&gt;headless&lt;/code&gt; and &lt;code&gt;slowMo&lt;/code&gt; property in the &lt;code&gt;playwright.config.js&lt;/code&gt; file. For instance:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// playwright.config.js

// ...
use: {
    launchOptions: {
      slowMo: 400,
      headless: false
    }
// ...

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;page.type()&lt;/code&gt; can also be used but it differs to &lt;code&gt;page.fill()&lt;/code&gt; in sense of it sending a &lt;code&gt;keydown&lt;/code&gt;, &lt;code&gt;keypress/input&lt;/code&gt; and &lt;code&gt;keyup&lt;/code&gt; event for each character of the text while &lt;code&gt;page.fill()&lt;/code&gt; fires only an &lt;code&gt;input&lt;/code&gt; event on the focused element with the specified text.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;page.type()&lt;/code&gt; fires every necessary keyboard event and you can even set the &lt;code&gt;delay&lt;/code&gt; of the typing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checkboxes and radio buttons
&lt;/h2&gt;

&lt;p&gt;When working with checkboxes and radio buttons, &lt;code&gt;page&lt;/code&gt; provide some methods to check, uncheck and get the state of theses input elements (&lt;code&gt;input[type=checkbox]&lt;/code&gt;, &lt;code&gt;input[type=radio]&lt;/code&gt; or &lt;code&gt;[role=checkbox]&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;// Check the checkbox
await page.check('#agree');

// Assert the checked state
expect(await page.isChecked('#agree')).toBeTruthy();

// Uncheck by input &amp;lt;label&amp;gt;.
await page.uncheck('#subscribe-label');

// Select the radio button
await page.check('text=XL');

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Selecting options from &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Single selection matching the value
await page.selectOption('select#colors', 'blue');

// Single selection matching the label
await page.selectOption('select#colors', { label: 'Blue' });

// Multiple selected items
await page.selectOption('select#colors', ['red', 'green', 'blue']);

// Select the option via element handle
const option = await page.$('#best-option');
await page.selectOption('select#colors', option);

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the mouse
&lt;/h2&gt;

&lt;p&gt;You can perform different types of mouse clicks using Playwright. The &lt;code&gt;.click()&lt;/code&gt; method takes an argument of the element you want to click and optional arguments to define the options for the click event. Some examples use cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// generic clicking
await page.click('#edit-button');

// double click
await page.dblclick('#edit-button');

// right click
await page.click('#edit-button', { button: 'right' });

// using modifiers (like shift, control...) with the click
// shift + click
await page.click('#edit-button', { modifiers: ['Shift'] });
// ctrl + click
await page.click('#edit-button', { modifiers: ['Control'] });

// define the position point of click on the element
await page.click('#edit-button', { position: { x: 0, y: 0 } });

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using &lt;code&gt;.dispatchEvent()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For cases where you want to just trigger events programmatically or trigger a custom event that is not directly implemented in the Playwright API, you can make use of the &lt;code&gt;.dispatchEvent()&lt;/code&gt; method.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read about creating and triggering events &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// trigerring a custom event 'build'
// .dispatchEvent(selector, type[, eventInit, options])
await page.dispatchEvent('#edit-button', 'build')

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

&lt;/div&gt;



</description>
      <category>testing</category>
      <category>softwaretesting</category>
      <category>qualityassurance</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Playwright Tutorial for Beginners 4 - Selectors and Locators</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:04:00 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-4-selectors-and-locators-1l41</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-4-selectors-and-locators-1l41</guid>
      <description>&lt;h2&gt;
  
  
  Playwright locators and selectors
&lt;/h2&gt;

&lt;p&gt;To interact with elements, you need to locate the element first. Selectors are used when locating an element. Then we can perform actions and write assertions on the elements by means of methods such &lt;code&gt;click()&lt;/code&gt;, &lt;code&gt;dbclick()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ways to select locate an element in Playwright:&lt;/p&gt;

&lt;h2&gt;
  
  
  Text selectors
&lt;/h2&gt;

&lt;p&gt;The selector locates element that contains specified text. e.g&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('Locate "Log in" button', async() =&amp;gt; {
    await page.locate('text=Log in').click();
});

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

&lt;/div&gt;



&lt;p&gt;Text selector has a few variations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;text=Log in&lt;/code&gt; - default matching case is case-insensitive and searches for a sub string. For instance, &lt;code&gt;text=Log&lt;/code&gt; matches &lt;code&gt;&amp;lt;button&amp;gt;Log in&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;wrap the text single or double quotes to make playwright match the exact text. For instance,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can make use of a JavaScript-like regex wrapped in &lt;code&gt;/&lt;/code&gt; symbol. For instance:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:has-text&lt;/code&gt; pseudo-class matches an element that contains specified text inside somewhere. It is used with other CSS specifiers because it will match all elements that contain the specified test. For instance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CSS selectors
&lt;/h2&gt;

&lt;p&gt;CSS selector can be used in Playwright by :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS selector engine, e.g. &lt;code&gt;page.locator(css='.button')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Using Playwright custom CSS locator with additional pseudo-classes like &lt;code&gt;:visible&lt;/code&gt;, &lt;code&gt;:text&lt;/code&gt; and many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Query CSS selectors directly, for instance&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;await page.locator('.form &amp;gt; .button');

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

&lt;/div&gt;



&lt;p&gt;You can read more about &lt;a href="https://playwright.dev/docs/selectors" rel="noopener noreferrer"&gt;selectors and locators&lt;/a&gt; in the official documentation.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>softwaretesting</category>
      <category>qualityassurance</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Playwright Tutorial for Beginners 3 - Trace Viewer</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sun, 16 Apr 2023 13:03:00 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-3-trace-viewer-la2</link>
      <guid>https://dev.to/zt4ff_1/playwright-tutorial-for-beginners-3-trace-viewer-la2</guid>
      <description>&lt;p&gt;In this tutorial, we will learn about another GUI tool provided by Playwright called the Trace Viewer.&lt;/p&gt;

&lt;p&gt;The Playwright Trace Viewer is a GUI tool that helps in exploring recorded Playwright traces after a tests script is executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recording a Trace
&lt;/h2&gt;

&lt;p&gt;We set the &lt;code&gt;trace&lt;/code&gt; configuration in the Playwright configuration file, &lt;code&gt;playwright.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// playwright.config.js

const config = {
    retries: 1,
    use: {
        trace: 'on-first-retry'
    }
};

module.exports = config;

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

&lt;/div&gt;



&lt;p&gt;When you run a test with the above configuration, a &lt;code&gt;trace.zip&lt;/code&gt; file would be created for each test that was retried.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you specify the &lt;code&gt;retries&lt;/code&gt; key in the config file, Playwright retries the test until the test is passed or the maximum number of &lt;code&gt;retries&lt;/code&gt; specified is reached.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Available options for the &lt;code&gt;trace&lt;/code&gt; key:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;off&lt;/code&gt; - does not record a trace at all&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;on&lt;/code&gt; - records a trace for each test ran&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;retain-on-failure&lt;/code&gt; - record trace for each test but removes it when the test runs successfully&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;on-first-retry&lt;/code&gt; - record a trace only when retrying a test for the first time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lets practice now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lets configure trace to run on every test in the &lt;code&gt;playwright.config.js&lt;/code&gt; file and make use of the &lt;code&gt;Desktop Chrome&lt;/code&gt; device:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lets create a test:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Running the test with &lt;code&gt;npx playwright test simple_test.spec.js&lt;/code&gt; would generate a &lt;code&gt;trace.zip&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can view the trace by running this command in the CLI. (The &lt;code&gt;trace.zip&lt;/code&gt; file is stored in the &lt;code&gt;test-results&lt;/code&gt; folder:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Doing this would open the Trace Viewer window now you can see the actions performed by the script.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzwmebe93ozitn5es4p8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzwmebe93ozitn5es4p8k.png" alt="playwright-trace-viewer-window.PNG" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;trace-viewer&lt;/code&gt; shows the action on the script on the left side of the window and clicking each of the actions reveals:

&lt;ul&gt;
&lt;li&gt;action snapshot&lt;/li&gt;
&lt;li&gt;action log&lt;/li&gt;
&lt;li&gt;source code location&lt;/li&gt;
&lt;li&gt;network log for the action&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;For instance, clicking on the &lt;code&gt;locator.click text=Phones&lt;/code&gt;:&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F52sbgl3qr3k3geg50dch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F52sbgl3qr3k3geg50dch.png" alt="clicked-action-trace-viewer.PNG" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;trace viewer&lt;/code&gt; is a really useful tool when you want to trace how some of your tests ran (flaky or failing).&lt;/p&gt;

&lt;p&gt;You can play more around the tool. And read more on the official &lt;a href="https://playwright.dev/docs/trace-viewer#viewing-the-trace" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>softwaretesting</category>
      <category>qualityassurance</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Track Errors in Your NestJS Application with AppSignal</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Wed, 01 Mar 2023 13:54:02 +0000</pubDate>
      <link>https://dev.to/appsignal/track-errors-in-your-nestjs-application-with-appsignal-2j7g</link>
      <guid>https://dev.to/appsignal/track-errors-in-your-nestjs-application-with-appsignal-2j7g</guid>
      <description>&lt;p&gt;Many variables — such as your users' device type and configuration, external hosting services, and third-party libraries — can impact an application's performance. Without a performance monitoring system in place, numerous problems can arise. These issues could even mean that users stop using your application.&lt;/p&gt;

&lt;p&gt;AppSignal provides application performance monitoring (APM) — with features such as error tracking, performance monitoring, host monitoring, anomaly detection, and uptime monitoring — to help you track errors and monitor your app's performance.&lt;/p&gt;

&lt;p&gt;In this article, we will set up AppSignal for a NestJS application and give some tips for tracking errors using AppSignal.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing a NestJS Application
&lt;/h2&gt;

&lt;p&gt;NestJS is a framework for building Node.js server-side applications. NestJS is built with Typescript and supports Typescript right out of the box, but it still enables developers to write pure JavaScript code. It provides a layer of abstraction over HTTP server frameworks like Express (the default) or Fastify and exposes the API so developers can integrate many of NestJS’ third-party modules.&lt;/p&gt;

&lt;p&gt;You can install a NestJS TypeScript starter project on your machine by running the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/nestjs/typescript-starter.git sample_app
&lt;span class="nb"&gt;cd &lt;/span&gt;sample_app
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring AppSignal for NestJS
&lt;/h2&gt;

&lt;p&gt;If you don’t have an AppSignal account, &lt;a href="https://appsignal.com/users/sign_up" rel="noopener noreferrer"&gt;create one&lt;/a&gt;, then run the command below to install and configure AppSignal in your app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @appsignal/cli &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install the necessary packages and you'll be asked for a configuration method. Select the &lt;strong&gt;Using the appsignal.cjs configuration file&lt;/strong&gt; option.&lt;br&gt;
The CLI tools will generate a configuration file named &lt;code&gt;appsignal.cjs&lt;/code&gt; in the &lt;code&gt;src/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;The configuration that's generated includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a valid Push API key&lt;/li&gt;
&lt;li&gt;an application name&lt;/li&gt;
&lt;li&gt;setting &lt;code&gt;active&lt;/code&gt; to true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can get the Push API key from your AppSignal account by clicking through to &lt;strong&gt;Organization Settings → Administration → API Keys&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fp69v337vux6emq9qsowh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fp69v337vux6emq9qsowh.png" alt="appsignal_push_api_key.png" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will call our application "sample_app".&lt;/p&gt;
&lt;h2&gt;
  
  
  NestJS Error Tracking with AppSignal
&lt;/h2&gt;

&lt;p&gt;The AppSignal for Node.js package automatically instruments NestJS. This command starts the application in development mode with hot code reloading and uses &lt;code&gt;--require&lt;/code&gt; to preload &lt;code&gt;appsignal.cjs&lt;/code&gt; at startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nest start &lt;span class="nt"&gt;--watch&lt;/span&gt; &lt;span class="nt"&gt;--exec&lt;/span&gt; &lt;span class="s2"&gt;"node --require ./src/appsignal.cjs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should add the &lt;code&gt;--require&lt;/code&gt; flag to any script that starts your app. For our demo, we'll only add it to &lt;code&gt;start:dev&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;You can also include the command above as a script in 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 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;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&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;"start:dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nest start --watch --exec &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;node --require ./src/appsignal.cjs&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then start your application by running the 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 run start:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AppSignal tracks any errors raised by your NestJS application and will start collecting metrics immediately.&lt;/p&gt;

&lt;p&gt;To test this, update the &lt;code&gt;getHello()&lt;/code&gt; method in the &lt;code&gt;app.service.ts&lt;/code&gt; file to raise an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app.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="s2"&gt;@nestjs/common&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getHello&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SOME SAMPLE ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// return 'Hello World';&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;Then open &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; in your browser, so your application raises an error. Go to your dashboard on AppSignal and click on &lt;strong&gt;Overview&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fb158aycmldhkx9kf302n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fb158aycmldhkx9kf302n.png" alt="appsignal_dashboard.png" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AppSignal's error tracking provides different insights that help keep your application under control. The dashboard overview gives simple but powerful visuals for important metrics like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error rate&lt;/li&gt;
&lt;li&gt;Throughput&lt;/li&gt;
&lt;li&gt;Response time&lt;/li&gt;
&lt;li&gt;Worst 10 hosts by&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more!&lt;/p&gt;

&lt;p&gt;When you click on an error listed in the &lt;strong&gt;Latest open errors&lt;/strong&gt; section, this opens a page that contains further details to help with debugging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdybj217k1petum3zyc8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdybj217k1petum3zyc8n.png" alt="error_details" width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using this information, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see the host's state on the day the error occurred&lt;/li&gt;
&lt;li&gt;find out more about the request environment or request headers&lt;/li&gt;
&lt;li&gt;backtrace the error via its callstack, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also integrate personal issue trackers or GitHub to assign issues and manage errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;Read more about AppSignal for Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Errors with AppSignal
&lt;/h2&gt;

&lt;p&gt;There are situations where you'll want AppSignal to ignore some errors raised by your application — for instance, exceptions raised by bots using your app.&lt;/p&gt;

&lt;p&gt;To do this, you can add the &lt;code&gt;ignoreErrors&lt;/code&gt; property to the configuration object in &lt;code&gt;appsignal.cjs&lt;/code&gt;. &lt;code&gt;ignoreErrors&lt;/code&gt; takes an array of specific error names.&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;Appsignal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@appsignal/nodejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Appsignal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;ignoreErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SpecificError&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="s2"&gt;AnotherError&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="s2"&gt;SomeError&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;To handle exceptions in your application, use the &lt;code&gt;sendError&lt;/code&gt; method provided by the &lt;code&gt;@appsignal/node&lt;/code&gt; package to record an incident.&lt;/p&gt;

&lt;p&gt;NestJS has a built-in exceptions layer that automatically processes unhandled exceptions in your app. It catches unhandled errors and sends appropriate user-friendly responses. As we've seen, such errors are also tracked and reported by AppSignal.&lt;/p&gt;

&lt;p&gt;You may want full control over the exceptions layer to customize the content of the response you send to the client. You can use the &lt;code&gt;ExceptionFilter&lt;/code&gt; class from &lt;code&gt;@nestjs/common&lt;/code&gt; for this.&lt;/p&gt;

&lt;p&gt;Create a new file called &lt;code&gt;appsignalexception.filter.ts&lt;/code&gt; in the &lt;code&gt;src/exception_filters/&lt;/code&gt; directory and copy the code below into the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ExceptionFilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Catch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ArgumentsHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/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;sendError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@appsignal/nodejs&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;Response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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;Catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpException&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;AppSignalExceptionFilter&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ExceptionFilter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ArgumentsHost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;switchToHttp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;sendError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//  handle the exceptions however you want: logging, additional info, HTTP response, etc.&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handle the error however you may want&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;The &lt;code&gt;AppSignalExceptionFilter&lt;/code&gt; extends the &lt;code&gt;ExceptionFilter&lt;/code&gt; class, overriding the catch method.&lt;/p&gt;

&lt;p&gt;In the app service, update your &lt;code&gt;app.service.ts&lt;/code&gt; file, so &lt;code&gt;getHello&lt;/code&gt; raises an &lt;code&gt;HttpException&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpException&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="s2"&gt;@nestjs/common&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getHello&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;THIS IS AN ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="cm"&gt;/* status code */&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;In the app's controller, make use of the exception filter by updating the &lt;code&gt;app.controller.ts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UseFilters&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/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;AppService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.service&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;AppSignalExceptionFilter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./exception_filters/appsignalexception.filter&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;Controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UseFilters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AppSignalExceptionFilter&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;AppController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;getHello&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHello&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 you run the application, AppSignal will track incidents sent by the &lt;code&gt;sendError&lt;/code&gt; method (see the 'latest open errors' part of the screenshot below):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F0gxmgbxpuh7pacmbzf2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0gxmgbxpuh7pacmbzf2b.png" alt="appsignal_exception_handling" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Invite Team Members and Set Up Alerts for Errors in AppSignal
&lt;/h2&gt;

&lt;p&gt;AppSignal can be utilized to manage a collaborative workflow including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assigning tasks to team members&lt;/li&gt;
&lt;li&gt;sending specific notifications to some team members&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To add team members to your AppSignal application, click the &lt;strong&gt;App settings&lt;/strong&gt; button on the bottom-left of your dashboard.&lt;/p&gt;

&lt;p&gt;Then &lt;strong&gt;Team Permissions → Manage this team → Invitations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AppSignal also provides a notification system that can send alerts via email and integrates with many communication tools like Slack, Discord, Microsoft Teams, etc.&lt;/p&gt;

&lt;p&gt;AppSignal's alerts can be configured to suit your organization's workflow. For instance, if you mainly use Slack and email, you can configure your alert settings to send uptime monitoring alerts to every team member's emails and send error tracker metrics to a particular Slack channel.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;App settings&lt;/strong&gt; and the &lt;strong&gt;Notifications&lt;/strong&gt; option to access the configuration panel.&lt;br&gt;
You can add integrations based on your workflow and configure older integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fa01y1kdgu3ua8wgbfrno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fa01y1kdgu3ua8wgbfrno.png" alt="notification-configuration.png" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AppSignal can also offer webhooks for notifications so you can create workflows, functions, and operations to handle the incidents occurring in your application. &lt;a href="https://docs.appsignal.com/application/integrations/webhooks.html" rel="noopener noreferrer"&gt;Read the docs to find out more about AppSignal webhooks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Uptime Monitoring in AppSignal
&lt;/h2&gt;

&lt;p&gt;AppSignal’s uptime monitoring monitors when your application is down and alerts you. It checks URLs you provide and logs a given endpoint's performance in different regions.&lt;/p&gt;

&lt;p&gt;AppSignal pings the given URL in multiple regions worldwide, and if there’s no response within 30 seconds from a region, it considers the application down in that region.&lt;/p&gt;

&lt;p&gt;To create an uptime monitor, click the &lt;strong&gt;Add uptime monitor&lt;/strong&gt; button on the &lt;strong&gt;Uptime Monitoring&lt;/strong&gt; page and provide the necessary information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fanw5nfd0yq2vyjb0ww9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fanw5nfd0yq2vyjb0ww9k.png" alt="appsignal_uptime_monitor_setup.png" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.appsignal.com/2021/05/20/more-in-one-uptime-monitoring-is-now-available-in-appsignal.html" rel="noopener noreferrer"&gt;Read more about uptime monitoring in AppSignal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://blog.appsignal.com/2023/01/30/monitoring-your-nestjs-application-with-appsignal.html" rel="noopener noreferrer"&gt;Monitoring Your NestJS Application with AppSignal&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this article, we installed AppSignal for a NestJS application. Then we explored how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;track errors and dig into error details&lt;/li&gt;
&lt;li&gt;set up alerts from AppSignal to track errors in a way that suits your workflow&lt;/li&gt;
&lt;li&gt;enable uptime monitoring for different URL endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy debugging!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery" rel="noopener noreferrer"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>The 20 Most Trending Open Source Tools for Ecommerce</title>
      <dc:creator>Kayode</dc:creator>
      <pubDate>Sat, 04 Feb 2023 15:53:18 +0000</pubDate>
      <link>https://dev.to/zt4ff_1/the-20-most-trending-open-source-tools-for-ecommerce-5cie</link>
      <guid>https://dev.to/zt4ff_1/the-20-most-trending-open-source-tools-for-ecommerce-5cie</guid>
      <description>&lt;p&gt;In the past decade, ecommerce and marketing have drifted into a more digitized landscape. More investments and research are poured towards ecommerce and tools are created to help set up online stores faster, improve sales, market digitally, etc.&lt;/p&gt;

&lt;p&gt;This article compiles a list of different categories of open source tools to help you set up and improve your online stores.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Should You Use Open Source Tools?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Open source simply refers to software with source code that is publicly visible or accessible. Availability of the source code means developers and non-developers can contribute to the software.&lt;/p&gt;

&lt;p&gt;One of the biggest advantages of open source tools is that they are cost-effective in comparison to proprietary tools and offer as good a value. Open source software is generally free, but there are exceptions. The freeness depends on the restrictiveness of the software license.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Linus%27s_law"&gt;Linuss law&lt;/a&gt; asserts that given enough eyeballs, all bugs are shallow. Open source ensures security and transparency due to the openness of source code. More involvement means more use cases, and more use cases lead to more edge cases being discovered and bugs being fixed.&lt;/p&gt;

&lt;p&gt;The large involvement common with popular open source software reduces the duplication of effort. It encourages you to focus on the competency that makes you unique or gives you an advantage by utilizing common components provided by open source tools.&lt;/p&gt;

&lt;p&gt;Below is a list of some open source tools that can improve and optimize the experience of your online stores. Beside each listed tool is the number of GitHub stars currently available on their respective repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trending Ecommerce Engines
&lt;/h2&gt;

&lt;p&gt;These are tools that help you set up an ecommerce store. They provide many features like CMS integration, payment integration, carting system, etc. necessary to run an effective online store and may provide options for extensibility. See some examples below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Medusa (15.8k)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9LJqj3GT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525415425/57c7e8b1-a9e5-4a59-a99f-809fb65ab921.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9LJqj3GT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525415425/57c7e8b1-a9e5-4a59-a99f-809fb65ab921.png" alt="medusa" width="880" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to build a scalable and sophisticated commerce setup with low effort and great developer experience, &lt;a href="https://www.notion.so/ff41fb38eb7a42a5b93bd79ee8a9d158"&gt;&lt;strong&gt;Medusa&lt;/strong&gt;&lt;/a&gt; is the choice for you. It is an open source, JavaScript-based, headless commerce platform whose abstraction-based architecture makes it more extensible and easy to customize.&lt;/p&gt;

&lt;p&gt;Medusa has a large community of developers using it and contributing to its ecosystem to make it better and more extensible with custom tools and third-party services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.reactioncommerce.com/docs/v1.4.1/intro"&gt;&lt;strong&gt;Reaction Commerce (11.9k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OHLuKyKk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525433628/27413871-9c2b-4eec-b244-bf7d6543ac72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OHLuKyKk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525433628/27413871-9c2b-4eec-b244-bf7d6543ac72.png" alt="reactioncommerce" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reaction Commerce, now known as MailChimp Open Commerce, is an API-first ecommerce tool powered by Meteor.js made for technical retailers. Since its launch, it has gained the attention of people because of its high level of customizability.&lt;/p&gt;

&lt;p&gt;You can write your API plugin for your store integrated with third-party services and also reuse codes between plugins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devdocs.magento.com/"&gt;&lt;strong&gt;Magento (10.4k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SfT90ggv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525440853/f666ed20-212d-4a79-a83a-2876e12c6a81.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SfT90ggv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525440853/f666ed20-212d-4a79-a83a-2876e12c6a81.webp" alt="magento" width="880" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now known as Adobe Commerce, Magento is an open source ecommerce platform acquired by Adobe in 2018. Magento has built a large community of people contributing to its ecosystem.&lt;/p&gt;

&lt;p&gt;It supports a series of payment gateway options so that you can make multiple payment integrations.&lt;/p&gt;

&lt;p&gt;You need just a little understanding of technology to be able to build yourself a store with this tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://woocommerce.com/documentation/"&gt;&lt;strong&gt;WooCommerce (8.3k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hC_2nqRE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525452494/9ffa8aa4-7c1e-4103-bd1c-3ec5fc71f213.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hC_2nqRE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525452494/9ffa8aa4-7c1e-4103-bd1c-3ec5fc71f213.webp" alt="woocommerce" width="880" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WooCommerce helps you build online stores with WordPress. All you need to do is to install the WooCommerce plugin into your WordPress website to get started. It is beginner-friendly and because it uses WordPress, you can access a variety of free or paid themes and plugins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.opencart.com/"&gt;&lt;strong&gt;OpenCart (6.6k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Noddt-qv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525467777/b5a5057d-9acb-4310-ad54-304a68bce3cb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Noddt-qv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525467777/b5a5057d-9acb-4310-ad54-304a68bce3cb.png" alt="opencart" width="880" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OpenCart is a PHP-based store management software. To use OpenCart, download the software from its official website or GitHub and install it.&lt;/p&gt;

&lt;p&gt;It has multi-store support that lets you manage different stores from a single interface. You can also use specific themes and set products for each store.&lt;/p&gt;

&lt;p&gt;And just like many platforms, it is highly customizable and extensible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trending Content Management Systems (CMS)
&lt;/h2&gt;

&lt;p&gt;A content management system is a tool that helps you create, manage, and modify content on a frontend client without the need for specialized technical knowledge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html"&gt;&lt;strong&gt;Strapi (50.8k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VT4VcP6N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525476291/2c47ebac-2e83-4375-985f-8970e28484d8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VT4VcP6N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525476291/2c47ebac-2e83-4375-985f-8970e28484d8.png" alt="strapi" width="880" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Strapi is a headless Node.js-based content management system. Headless CMS is a backend-only CMS built as a content repository that makes content accessible via an API to any frontend client. It makes it easier to build applications using Jamstack technology, separating the backend from the frontend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.wordpress.org/"&gt;&lt;strong&gt;WordPress (17k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aaErPv8H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525489498/6bc549ff-7f0f-4c8b-9cd1-a18b1acd4a9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aaErPv8H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525489498/6bc549ff-7f0f-4c8b-9cd1-a18b1acd4a9e.png" alt="wordpress" width="880" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WordPress is an open source content management system originally associated with many blogs but is now used widely in different varieties like professional publications, ecommerce stores, wikis, etc.&lt;/p&gt;

&lt;p&gt;WordPress has a large number of users and people contributing to it (creating plugins, community support, theme creation, etc.) making it provide many customization options. It is also beginner-friendly and requires minimal technical knowledge to start creating a website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keystonejs.com/docs"&gt;&lt;strong&gt;KeystoneJS (7.3k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LHtOOCc1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525500912/cb704021-f3cd-420f-941a-d708bff773e6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LHtOOCc1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525500912/cb704021-f3cd-420f-941a-d708bff773e6.png" alt="keystone" width="880" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KeystoneJS is a Node.js-based content management system that provides a standardized set of components that allows for the fast and easy development of web applications. Asides from its basic functions, it provides you with a GraphQL API that can be integrated with a frontend application of your choice and a backend admin dashboard to manage your application content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.joomla.org/"&gt;&lt;strong&gt;Joomla (4.3k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DoHgCmSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525510773/16f57546-9de5-4527-b72e-040b16858f05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DoHgCmSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525510773/16f57546-9de5-4527-b72e-040b16858f05.png" alt="joomla" width="880" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Joomla is developed by a community supported by Open Source Matters Inc. It removes much of the technical aspect of setting up and running a website. Like WordPress, it provides plugins and site modules so users can enhance their websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.drupal.org/documentation"&gt;&lt;strong&gt;Drupal (3.8k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jsbBYTNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525521032/dc7ab1ea-ac54-4f62-9eda-d63fac4bf667.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jsbBYTNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525521032/dc7ab1ea-ac54-4f62-9eda-d63fac4bf667.jpeg" alt="drupal" width="880" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drupal is highly scalable, making it popular with high-traffic sites. In comparison to WordPress, it has a relatively higher learning curve. It improves performance through caching which reduces page load times and resource requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trending Payments Tools
&lt;/h2&gt;

&lt;p&gt;These tools provide ways to receive payments and also provide integrations for many payment methods as well as multi-currency support.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stripe.com/docs"&gt;&lt;strong&gt;Stripe&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yj3KkBjP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525527044/62f66b5a-ebd2-4e14-a6ce-d00a3a16bf50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yj3KkBjP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525527044/62f66b5a-ebd2-4e14-a6ce-d00a3a16bf50.png" alt="stripe" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stripe is a payment gateway that is easy and quick to implement. It handles the step between a paying customer and the recipient and acknowledging that payment has been received.&lt;/p&gt;

&lt;p&gt;From a developers perspective, Stripe takes all the hard work out by providing developer-friendly SDKs to interact with its APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.paypal.com/home"&gt;&lt;strong&gt;PayPal&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ONFC4vsp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525745418/daa7d0b2-bd89-49db-9d5f-e54ff7a5ee6f.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ONFC4vsp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525745418/daa7d0b2-bd89-49db-9d5f-e54ff7a5ee6f.webp" alt="paypal" width="841" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paypal is one of the first online payment providers to be established globally. Paypal works as a service platform between people (or businesses) wanting to exchange. PayPal provides a list of software development kits (SDKs) that can be integrated with your online stores.&lt;/p&gt;

&lt;h3&gt;
  
  
  Marketing
&lt;/h3&gt;

&lt;p&gt;Marketing is very important to ecommerce. It helps your customers to be aware of your store, engages them and helps them make the buying decision. These tools provide functions that can improve your business marketing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.matomo.org/"&gt;&lt;strong&gt;Matomo (17.2k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pmX-t0ju--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525557771/645d1ff3-72c6-48b8-beeb-8e094b58cbe3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pmX-t0ju--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525557771/645d1ff3-72c6-48b8-beeb-8e094b58cbe3.png" alt="matomo" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data analytics are important to the success of modern web-based businesses. Matomo, formerly known as Piwik Analytics, is an open source web analytics platform that provides detailed reports on your website visitors. It provides information that can be used to improve the retention rate of online visitors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.chatwoot.com/docs/product"&gt;&lt;strong&gt;Chatwoot (14.2k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rqCc7fVj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525568483/4242989e-7808-4649-9ca3-a056c73a6bca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rqCc7fVj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525568483/4242989e-7808-4649-9ca3-a056c73a6bca.png" alt="chatwoot" width="880" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chatwoot is an open source customer engagement platform that helps business engage their customers on their website, email, SMS, etc. It is an open source alternative to Intercom, Zendesk, etc.&lt;/p&gt;

&lt;p&gt;It combines many features to become a central hub for communication and allows you to interact with many channels (SMS, email, Facebook, live chats, etc.) without leaving the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://plausible.io/docs/"&gt;Plausible Analytics (13.3k)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WmQy4pl2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525573194/1e3d172b-b875-4002-aa9f-4552099ee637.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WmQy4pl2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525573194/1e3d172b-b875-4002-aa9f-4552099ee637.png" alt="plausible analytics" width="880" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plausible Analytics is an alternative to Matomo although its a newer player in this market.&lt;/p&gt;

&lt;p&gt;Unlike Matomo, Plausible is built with simplicity and ease of use in mind. It focuses on essential stats and metrics only while Matomo is a full-fledged Google Analytics alternative providing a huge number of metrics and reports you can choose from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://listmonk.app/docs/"&gt;&lt;strong&gt;Listmonk (9.2k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eGEBs2-f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525614508/72992fa6-6d84-43cb-8ef3-7ae017045874.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eGEBs2-f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525614508/72992fa6-6d84-43cb-8ef3-7ae017045874.png" alt="listmonk" width="880" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Listmonk is an open source self-hosted email marketing software that can manage subscribers lists providing tools to create email templates and can segment subscribers for arbitrary message campaigns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trending Business Tools
&lt;/h2&gt;

&lt;p&gt;These tools are important to efficiently manage your business processes.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://Rocket.Chat"&gt;&lt;strong&gt;Rocket.Chat&lt;/strong&gt;&lt;/a&gt; &lt;a href="https://docs.rocket.chat/"&gt;&lt;strong&gt;(34.4k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D4de9219--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525618770/89e96751-f34e-4463-8463-5300fdf58ef2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D4de9219--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525618770/89e96751-f34e-4463-8463-5300fdf58ef2.png" alt="rocket chat" width="880" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://Rocket.Chat"&gt;Rocket.Chat&lt;/a&gt; is an open source platform designed for communities and organizations with high standards for data protection. You can install and host it however you want.&lt;/p&gt;

&lt;p&gt;It provides a lot of features to manage internal and external business communications with a marketplace providing apps for integration with common social media channels like Facebook Messenger, WhatsApp, Instagram, SMS, etc).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.odoo.com/documentation/16.0/"&gt;&lt;strong&gt;Odoo (27.5k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h6bl8sEF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525628740/8eee65ff-e8cb-4984-831e-80e0efd74afc.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h6bl8sEF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525628740/8eee65ff-e8cb-4984-831e-80e0efd74afc.jpeg" alt="odoo" width="880" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Odoo, formerly known as OpenERP, is an open source all-inclusive suite of business apps that can help you manage your business processes.&lt;/p&gt;

&lt;p&gt;Due to the large community surrounding the tool, Odoo comes with many modules that you can integrate to boost your business processes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.n8n.io/"&gt;&lt;strong&gt;n8n (27.2k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kK33yMUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525634450/8dd5699d-7815-47cb-b820-44fa9d51e90e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kK33yMUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525634450/8dd5699d-7815-47cb-b820-44fa9d51e90e.png" alt="n8n" width="880" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;n8n, pronounced nodemation, is an open source workflow automation tool that is self-hosted and easy to extend. With n8n, you can perform simple automation integrations and also complex workflows that combine both third-party APIs and your internal tools.&lt;/p&gt;

&lt;p&gt;It provides an intuitive user interface that allows non-technical users to automate tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://erpnext.com/about"&gt;&lt;strong&gt;ERPNext (12.4k)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QGGqQ7fz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525638990/4399b674-e694-4bc3-b598-dd9c2b3ce820.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QGGqQ7fz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1675525638990/4399b674-e694-4bc3-b598-dd9c2b3ce820.png" alt="ERPNext" width="880" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just like Odoo, ERPNext helps you manage your business processes. It consolidates your business operations into a single monolithic application.&lt;/p&gt;

&lt;p&gt;With this tool, you can avoid jumping from one spreadsheet to another app to get things done. Due to data being central, all data stored can speak and interact with others.&lt;/p&gt;

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

&lt;p&gt;This article outlined 20 open source tools to boost your sites performance across different categories. Open source ecommerce tools are growing rapidly; there are many more tools available. However, with these ones, you can build an online store with a wide range of functions made available.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ecommerce</category>
      <category>cms</category>
    </item>
  </channel>
</rss>
