<?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: Pavel Bucka</title>
    <description>The latest articles on DEV Community by Pavel Bucka (@penge).</description>
    <link>https://dev.to/penge</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%2F165812%2F1d8ca62d-d94f-45b0-9083-22b7e2d2f4cf.png</url>
      <title>DEV Community: Pavel Bucka</title>
      <link>https://dev.to/penge</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/penge"/>
    <language>en</language>
    <item>
      <title>Learn the most useful Chrome APIs by creating Block Site Chrome extension</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Thu, 30 Jul 2020 12:50:35 +0000</pubDate>
      <link>https://dev.to/penge/learn-the-most-useful-chrome-apis-by-creating-block-site-chrome-extension-2de8</link>
      <guid>https://dev.to/penge/learn-the-most-useful-chrome-apis-by-creating-block-site-chrome-extension-2de8</guid>
      <description>&lt;p&gt;This article will explain you how to use the most useful Chrome APIs by creating a simple Chrome extension called &lt;strong&gt;Block Site&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agenda:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the APIs you will learn in this tutorial are called &lt;strong&gt;"storage"&lt;/strong&gt; and &lt;strong&gt;"tabs"&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;the full list of APIs available to Chrome extensions is &lt;a href="https://developer.chrome.com/extensions/api_index"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block Site&lt;/strong&gt;, which we are about to create to learn and practice the two APIs, is available &lt;a href="https://github.com/penge/block-site"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Block Site&lt;/strong&gt; is a simple Chrome extension that improves your productivity by blocking the access to time-consuming websites (like during the working hours) as you specify in &lt;strong&gt;Options&lt;/strong&gt;. &lt;strong&gt;Block Site&lt;/strong&gt; is by default disabled and doesn't block any website until you say so in &lt;strong&gt;Options&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Options&lt;/strong&gt; refers to &lt;strong&gt;"options_page"&lt;/strong&gt; which the extension can have. To open &lt;strong&gt;Options&lt;/strong&gt;, generally you &lt;strong&gt;right-click&lt;/strong&gt; on the extension icon in the toolbar and choose &lt;strong&gt;Options&lt;/strong&gt; from the menu. The same will apply to &lt;strong&gt;Block Site&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"storage" API&lt;/strong&gt; will be needed to store the websites user wants to block the access to, to boost his productivity, and it will also be used to store an option to quickly disable or enable the blocking at any given moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"tabs" API&lt;/strong&gt; will be needed to get the tab &lt;strong&gt;url&lt;/strong&gt; we are trying to open, and based on whether the domain is on the blocked list or not, we close the tab instantly, or let it proceed.&lt;/p&gt;

&lt;p&gt;Let's now create the extension &lt;strong&gt;Block Site&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First steps
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir block-site
$ cd block-site
$ touch manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have now created a new folder called &lt;code&gt;block-site&lt;/code&gt; and prepared a file &lt;code&gt;manifest.json&lt;/code&gt; which every extension has to have.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;manifest.json&lt;/code&gt; to contain following:&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;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Block Site"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Blocks access to time-consuming websites (as you specify) to improve your productivity."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options_page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"options.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&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="s2"&gt;"storage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tabs"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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="s2"&gt;"background.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"persistent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;The structure of this file is explained &lt;a href="https://developer.chrome.com/extensions/manifest"&gt;here&lt;/a&gt;. Any other fields besides &lt;strong&gt;"manifest_version"&lt;/strong&gt;, &lt;strong&gt;"name"&lt;/strong&gt; and &lt;strong&gt;"version"&lt;/strong&gt;, are optional and we add them as needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"options_page"&lt;/strong&gt; is a page to open when you &lt;strong&gt;right-click&lt;/strong&gt; the extension in the toolbar, and select &lt;strong&gt;Options&lt;/strong&gt; from the menu. In our case, we will use this page to set a list of websites to block, and also to easily enable/disable the blocking. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"permissions"&lt;/strong&gt; lists permissions needed by the extension. It can be requesting API access as in our case, or also a match pattern. More about possible options &lt;a href="https://developer.chrome.com/extensions/declare_permissions"&gt;here&lt;/a&gt;. Permissions are requested by the extension when installing. Based on the requested permissions, Chrome may display a warning as explained &lt;a href="https://developer.chrome.com/extensions/permission_warnings"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"background"&lt;/strong&gt; sets the script to be run in the background. In our case, it will be a place where we put the main logic to stop the blocked websites from opening. Because Chrome extensions are event-based, background script is a good place to put event-based scripts, especially if they don't require an UI (like blocking the websites). It's also a good place to put any heavy calculation that could slow down the UI. As you can see, the background is set to be no persistent. That means, when not needed, the script is unloaded from memory. More about background scripts &lt;a href="https://developer.chrome.com/extensions/background_pages"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create &lt;strong&gt;Options&lt;/strong&gt; page (use &lt;strong&gt;"storage"&lt;/strong&gt;)
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;options.html&lt;/code&gt; and give it a simple markup like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Block Site&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Block Site&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"textarea"&lt;/span&gt; &lt;span class="na"&gt;rows=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="na"&gt;cols=&lt;/span&gt;&lt;span class="s"&gt;"30"&lt;/span&gt; &lt;span class="na"&gt;spellcheck=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"save"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Enabled?&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"options.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI is pretty simple. We have 3 elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;#textarea&lt;/code&gt; to specify the websites to block&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#save&lt;/code&gt; button to save the modified &lt;code&gt;#textarea&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#checkbox&lt;/code&gt; to enable or disable the blocking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create &lt;code&gt;options.js&lt;/code&gt; and give it this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textarea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;textarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;textarea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blocked&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;enabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;local&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;textarea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see &lt;code&gt;chrome.storage.local&lt;/code&gt; being used, which is made available by having the &lt;strong&gt;"storage"&lt;/strong&gt; permission.&lt;/p&gt;

&lt;p&gt;When we click on &lt;code&gt;#save&lt;/code&gt;, we save the list of blocked sites in &lt;code&gt;#textarea&lt;/code&gt; under the key &lt;code&gt;blocked&lt;/code&gt;. Before saving them, we remove any empty lines or trailing whitespaces.&lt;/p&gt;

&lt;p&gt;Example on how the list of blocked sites in &lt;code&gt;#textarea&lt;/code&gt; can look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;facebook.com
instagram.com
youtube.com
twitter.com
reddit.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we click on &lt;code&gt;#checkbox&lt;/code&gt;, we save the boolean under the key &lt;code&gt;enabled&lt;/code&gt;, to tell if the blocking should be enabled or not.&lt;/p&gt;

&lt;p&gt;When the page is loaded, we read &lt;code&gt;blocked&lt;/code&gt; and &lt;code&gt;enabled&lt;/code&gt;, and set the UI accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A closer look on &lt;strong&gt;"storage"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Using &lt;strong&gt;"storage"&lt;/strong&gt; made &lt;code&gt;chrome.storage.local&lt;/code&gt; available, but what is it actually? And is that all?&lt;/p&gt;

&lt;p&gt;It turns out, &lt;strong&gt;"storage"&lt;/strong&gt; gives us access one step further, to &lt;code&gt;chrome.storage&lt;/code&gt; which is documented &lt;a href="https://developer.chrome.com/extensions/storage"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chrome.storage&lt;/code&gt; is similar to &lt;code&gt;localStorage&lt;/code&gt;, in terms of its API and storage limitations. The main benefit comes from it being &lt;strong&gt;asynchronous&lt;/strong&gt; and having an &lt;code&gt;onChanged&lt;/code&gt; listener that can be used to synchronize the UI or otherwise react to changes in data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chrome.storage&lt;/code&gt; gives us 3 storage areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chrome.storage.local&lt;/code&gt; that is best for storing the data locally&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chrome.storage.sync&lt;/code&gt; that supports to store and synchronize (although very limited in size) the data across other computers where the extension is installed and same Google Account is used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chrome.storage.managed&lt;/code&gt; which is like read-only area for administrator purposes only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most commonly used storage out of these three is &lt;code&gt;chrome.storage.local&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The most common methods across these storages are &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, and &lt;code&gt;remove&lt;/code&gt;. See the documentation &lt;a href="https://developer.chrome.com/extensions/storage"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create &lt;strong&gt;Background&lt;/strong&gt; script (use &lt;strong&gt;"tabs"&lt;/strong&gt;)
&lt;/h2&gt;

&lt;p&gt;Now when we have the Options page ready, which can set &lt;code&gt;blocked&lt;/code&gt; (array of websites to block) and &lt;code&gt;enabled&lt;/code&gt; (boolean if blocking should be applied or not), it is time to work with these in the background. &lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;background.js&lt;/code&gt; and give it this content:&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="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onInstalled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blocked&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;enabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onUpdated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;changeInfo&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changeInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pendingUrl&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;changeInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blocked&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;enabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;local&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the top we can see &lt;code&gt;chrome.runtime&lt;/code&gt; being used. More about this API &lt;a href="https://developer.chrome.com/extensions/runtime"&gt;here&lt;/a&gt;. List of all available APIs &lt;a href="https://developer.chrome.com/extensions/api_index"&gt;here&lt;/a&gt;. And list of all possible permissions &lt;a href="https://developer.chrome.com/extensions/declare_permissions"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As we can see, not every API requires a permission. Some APIs are generally available in extensions, like &lt;code&gt;chrome.runtime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chrome.runtime.onInstalled.addListener&lt;/code&gt; calls a given callback any time the extension is installed or updated. What we do here, we simply check if &lt;code&gt;blocked&lt;/code&gt; and &lt;code&gt;enabled&lt;/code&gt; are of a correct format, and if not, we reset them.&lt;/p&gt;

&lt;p&gt;The more interesting, is the use of &lt;code&gt;chrome.tabs&lt;/code&gt;. Most of this API is generally available as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  A closer look on &lt;strong&gt;"tabs"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;chrome.tabs&lt;/code&gt; which is described &lt;a href="https://developer.chrome.com/extensions/tabs"&gt;here&lt;/a&gt;, opens many options like creating a new tab, updating an existing tab, or reacting to various events about tabs. Most of the API is generally available, and doesn't require a &lt;strong&gt;"tabs"&lt;/strong&gt; permission.&lt;/p&gt;

&lt;p&gt;We are using &lt;strong&gt;"tabs"&lt;/strong&gt; permission to get the access to &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;pendingUrl&lt;/code&gt; inside the &lt;code&gt;onUpdated&lt;/code&gt; event. This way, we can detect if the address we try to open matches any website from the &lt;code&gt;blocked&lt;/code&gt; list, and if yes, we close the tab instantly as a way of blocking the access.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pendingUrl&lt;/code&gt; is quite new (available since Chrome 79), and it captures the url we indent to open before the tab committed to it. &lt;code&gt;pendingUrl&lt;/code&gt; precedes &lt;code&gt;url&lt;/code&gt;. &lt;code&gt;url&lt;/code&gt; is more like a fallback. One tab can go through many events.&lt;/p&gt;

&lt;p&gt;To close the tab that would navigate to a blocked site, we use &lt;code&gt;chrome.tabs.remove&lt;/code&gt; and provide it with a &lt;code&gt;tabId&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing &lt;strong&gt;Block Site&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Block Site&lt;/strong&gt; is now ready to test.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;chrome://extensions&lt;/code&gt; in a new tab and navigate to &lt;code&gt;block-site&lt;/code&gt; folder to load the extension. If no errors were made, extension should be successfully loaded.&lt;/p&gt;

&lt;p&gt;Open any website you'd like to block, see that it works as usual.&lt;/p&gt;

&lt;p&gt;Now, &lt;strong&gt;right-click&lt;/strong&gt; on &lt;strong&gt;Block Site&lt;/strong&gt; icon and select &lt;strong&gt;Options&lt;/strong&gt; to open. Type in the website you would like to block and hit &lt;strong&gt;Save&lt;/strong&gt; and &lt;strong&gt;Enabled&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, try to open the blocked site again. It should not be possible! Try disabling the blocking via &lt;strong&gt;Options&lt;/strong&gt; and playing around with the used APIs by checking the values from the console.&lt;/p&gt;




&lt;p&gt;Thank you very much for reading the article. I hope you enjoyed it and it left you full of excitement to continue learning. Cheers!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A summary of used resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/manifest"&gt;Manifest file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/api_index"&gt;List of all Chrome APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/runtime"&gt;Chrome Runtime API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/storage"&gt;Chrome Storage API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/tabs"&gt;Chrome Tabs API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/extensions/declare_permissions"&gt;All possible permissions&lt;/a&gt; and &lt;a href="https://developer.chrome.com/extensions/permission_warnings"&gt;all possible warnings related to them&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/background_pages"&gt;All about Background scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/penge/block-site"&gt;Block Site on GitHub&lt;/a&gt; - give it a like pls! :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Here are the extensions I made on Web Store:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/skip-ad/bimlffinhbdhgpomhngmnhidjgnfcnoc"&gt;&lt;strong&gt;Skip Ad&lt;/strong&gt;&lt;/a&gt; (article &lt;a href="https://dev.to/penge/chrome-extension-that-skips-youtube-ads-steps-how-to-create-it-3ibp"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chrome.google.com/webstore/detail/my-notes/lkeeogfaiembcblonahillacpaabmiop"&gt;&lt;strong&gt;My Notes&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chrome.google.com/webstore/detail/block-site/bjcnpgekponkjpincbcoflgkdomldlnl"&gt;&lt;strong&gt;Block Site&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>chrome</category>
      <category>extension</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A simple way to detect if your JS App is online/offline/or having a slow connection (+ Alerts, + Emulating the slow Internet)</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Mon, 22 Jun 2020 19:56:01 +0000</pubDate>
      <link>https://dev.to/penge/a-simple-way-to-detect-if-your-js-app-is-online-offline-or-having-a-slow-connection-alerts-emulating-the-slow-internet-1lb3</link>
      <guid>https://dev.to/penge/a-simple-way-to-detect-if-your-js-app-is-online-offline-or-having-a-slow-connection-alerts-emulating-the-slow-internet-1lb3</guid>
      <description>&lt;p&gt;In this article, we will cover 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;How to detect your JS application (it can be SPA, PWA, Electron, or plain JS) is having a troubled connection (slow, offline), when it gets back online and how to re-download the data without a page refresh (in case it hasn't got enough time to finish while online).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating a simple JS application that downloads and displays a picture, where we would cover all the cases from a previous step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learning how to throttle the Internet connection in Chrome, and test the application we created.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To detect if the application got offline, or back online, is quite simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am offline.&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am back online.&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;If you are building a Chrome extension that requires the Internet connection, for example to upload a file to Google Drive, you can leverage following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onLine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Upload the file...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To detect if the application is loading for too long, can be done by creating a timer and giving it a time, after which we assume the connection is slow, if not loaded yet. After the application is loaded, we reset the timer. Here's an example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Our simple App&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onstart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;onstart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Loading...&lt;/span&gt;

  &lt;span class="c1"&gt;// The application is now loaded&lt;/span&gt;
  &lt;span class="nx"&gt;onload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isSlow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isSlow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thing are getting slow...&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="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10 seconds&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSlow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;loaded&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loaded.&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;The logic by which we decide if the application is loading for too long, depends on our app.&lt;/p&gt;

&lt;p&gt;Now, we can proceed to the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We will now create a simple app, that will load a random picture from &lt;a href="https://picsum.photos"&gt;https://picsum.photos&lt;/a&gt;. If the Internet connection will get slow, offline, or back online, we will display a particular message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MvPf8sZu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/re9hfmp79j94htxamf74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvPf8sZu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/re9hfmp79j94htxamf74.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VcuYdvv7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fyrmnohybgvdvhhumcyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VcuYdvv7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fyrmnohybgvdvhhumcyi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mshGOaAO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a43ggzix743j9dznqdno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mshGOaAO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a43ggzix743j9dznqdno.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x5-t7Rcf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/38egzojmcldc34at7iwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x5-t7Rcf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/38egzojmcldc34at7iwg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The message will be displayed in the top center when needed. To make the loading of an image visually nicer, it will have a pulsing effect to it.&lt;/p&gt;

&lt;p&gt;Let's start by creating &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"app.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"slow"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Slow Internet Connection.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"offline"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No Internet Connection.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"online"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Back Online.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Continue by creating &lt;code&gt;app.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f1f1f1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;silver&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="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;640px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;480px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="nc"&gt;.loading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt; &lt;span class="n"&gt;ease-out&lt;/span&gt; &lt;span class="n"&gt;alternate&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;-100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;.25s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#slow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FF9800&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#offline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#E91E63&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#online&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#4CAF50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.slow&lt;/span&gt; &lt;span class="nf"&gt;#slow&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.offline&lt;/span&gt; &lt;span class="nf"&gt;#offline&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.online&lt;/span&gt; &lt;span class="nf"&gt;#online&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Messages (or Alerts) have different color each, and are off the screen when not needed. When required, the message slides in from the top center.&lt;/p&gt;

&lt;p&gt;And finally, create &lt;code&gt;app.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simple App that loads a picture.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onstart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;onstart&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;h1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://picsum.photos/640/480&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;onload&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isSlow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;loaded&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;loadApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;loaded&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="nx"&gt;isSlow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Show "Slow Internet Connection." message.&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slow&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="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Intentionally a low number for testing. Try some different values here, or play with different Internet Throttling setting.&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;loaded&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="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSlow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Hide message after 1s.&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="c1"&gt;// We are "offline".&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Show "No Internet Connection." message.&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offline&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="c1"&gt;// When we back "online".&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Show "Back online" message.&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Hide message after 1s.&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// There was not enough time to load the App. Do it again.&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Reconnecting...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;loadApp&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadApp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This simple App will load a picture and display it. While the picture is loading, it will have a &lt;code&gt;.loading&lt;/code&gt; class added, to show the pulse effect. After the image is loaded, the &lt;code&gt;.loading&lt;/code&gt; class will be removed, and the timer will be stopped. If the loading took longer than we specified, &lt;code&gt;Slow Internet Connection.&lt;/code&gt; message will be shown.&lt;/p&gt;

&lt;p&gt;If the Internet is off, &lt;code&gt;No Internet Connection.&lt;/code&gt; message will be displayed, and once back online, &lt;code&gt;Back Online.&lt;/code&gt; message will be displayed.&lt;/p&gt;

&lt;p&gt;In case the picture wasn't loaded before we got offline, it will be loaded once again we are back online.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Time to test our App under different network conditions. Open &lt;strong&gt;Chrome -&amp;gt; DevTools -&amp;gt; Network&lt;/strong&gt;, look for &lt;strong&gt;Throttling&lt;/strong&gt; section and click &lt;strong&gt;Add...&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---6tz1coY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qj33dsyspej2ub9kja5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---6tz1coY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qj33dsyspej2ub9kja5t.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YPYQZU2E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p8las34m39jz2xlft63k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YPYQZU2E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p8las34m39jz2xlft63k.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Define 2 new &lt;strong&gt;Throttling&lt;/strong&gt; profiles as seen below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Asu9mZpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pj8b34waa7e6w2m2mew1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Asu9mZpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pj8b34waa7e6w2m2mew1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A random picture we are about to display, can range anywhere from &lt;strong&gt;20KB&lt;/strong&gt; to &lt;strong&gt;80KB&lt;/strong&gt; in size, that means, in &lt;strong&gt;Very slow&lt;/strong&gt; profile that would take about 5 seconds to load, in &lt;strong&gt;Incredibly slow&lt;/strong&gt; profile about 30 seconds. We basically adjust the speed to the size of content, to get a good testing.&lt;/p&gt;

&lt;p&gt;Now, open &lt;code&gt;index.html&lt;/code&gt; with the &lt;strong&gt;DevTools&lt;/strong&gt; open (to have &lt;strong&gt;Throttling&lt;/strong&gt; applied), keep refreshing the page with different initial &lt;strong&gt;Throttling&lt;/strong&gt; setting (&lt;strong&gt;Online&lt;/strong&gt;, &lt;strong&gt;Offline&lt;/strong&gt;, &lt;strong&gt;Very slow&lt;/strong&gt; or &lt;strong&gt;Incredibly slow&lt;/strong&gt;), and try changing the profile while the page is loading (from &lt;strong&gt;Offline&lt;/strong&gt; to &lt;strong&gt;Online&lt;/strong&gt;; from &lt;strong&gt;Incredibly slow&lt;/strong&gt; to &lt;strong&gt;Offline&lt;/strong&gt; to &lt;strong&gt;Online&lt;/strong&gt;; etc.).&lt;/p&gt;

&lt;p&gt;It can look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rrp33PCt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mei2bjkd18s1wmp8m0ig.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rrp33PCt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mei2bjkd18s1wmp8m0ig.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it. I hope you enjoyed the article and had fun!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And. Thank you for reading!&lt;/strong&gt; 🙂&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Create your first awesome Chrome Extension in just 5 minutes! 🔥🔥🔥 (FAQ included 🤔 =&gt; 😊)</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Thu, 18 Jun 2020 13:50:24 +0000</pubDate>
      <link>https://dev.to/penge/create-your-first-awesome-chrome-extension-in-just-5-minutes-faq-included-2n5p</link>
      <guid>https://dev.to/penge/create-your-first-awesome-chrome-extension-in-just-5-minutes-faq-included-2n5p</guid>
      <description>&lt;p&gt;&lt;strong&gt;In this post, you will learn how to create your first chrome extension, install it in every major browser, and get the basis that will guide you next!&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;The extension we are about to create, will show a random joke. The name of the extension will be, &lt;strong&gt;Joker&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1
&lt;/h3&gt;

&lt;p&gt;Prepare a new folder &lt;code&gt;joker&lt;/code&gt;. Start by creating &lt;code&gt;manifest.json&lt;/code&gt;. It is a file that is required by any extension. It's the entrypoint. Put the following content into the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Joker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Why so serious?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"joker.png"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"browser_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"joker.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_popup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"popup.html"&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;Most things are self-explanatory.&lt;/p&gt;

&lt;p&gt;Let's look more closely at &lt;code&gt;"browser_action"&lt;/code&gt;. This specifies, that the extension will open a popup once we click on the extension icon, which will be added to the browser's toolbar after the extension is installed. In the popup, we will display a random joke.&lt;/p&gt;

&lt;p&gt;To see the full list of possible attributes, that you can specify in this file, see &lt;a href="https://developer.chrome.com/extensions/manifest"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's continue now by creating the files we specified in the manifest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2
&lt;/h3&gt;

&lt;p&gt;Open &lt;a href="https://www.flaticon.com"&gt;&lt;strong&gt;flaticon&lt;/strong&gt;&lt;/a&gt; and look for an icon you would like to use for the extension. Make sure the icon is of size 128, png format. Save the icon as &lt;code&gt;joker.png&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;popup.html&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Joker&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"popup.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"popup.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"joke"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"one-more"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Haha, one more!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

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



&lt;h3&gt;
  
  
  Step 4
&lt;/h3&gt;

&lt;p&gt;Now, create &lt;code&gt;popup.css&lt;/code&gt; and make it pretty! 💁‍♀️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;350px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#9550bb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#joke&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#one-more&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#one-more&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-bottom-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;popup.js&lt;/code&gt;, the last file we need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getJoke&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joke&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://icanhazdadjoke.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&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;Accept&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;joke&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No Internet Connection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joke&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;joke&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getJoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// initial joke&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;one-more&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getJoke&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6
&lt;/h3&gt;

&lt;p&gt;Check that you have all the files. See &lt;strong&gt;&lt;a href="http://github.com/penge/joker"&gt;http://github.com/penge/joker&lt;/a&gt;&lt;/strong&gt; for reference.&lt;/p&gt;

&lt;p&gt;You should have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- manifest.json
- joker.png
- popup.html
- popup.css
- popup.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7
&lt;/h3&gt;

&lt;p&gt;It is time to try the extension in every browser!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chrome:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;chrome://extensions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load unpacked&lt;/strong&gt; (click &lt;strong&gt;Developer mode&lt;/strong&gt; if you don't see the button)&lt;/li&gt;
&lt;li&gt;Open folder &lt;code&gt;joker&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Firefox:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;about:debugging#/runtime/this-firefox&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load Temporary Add-on...&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Open any file in folder &lt;code&gt;joker&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Edge:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;edge://extensions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load Unpacked&lt;/strong&gt; (click &lt;strong&gt;Developer mode&lt;/strong&gt; if you don't see the button)&lt;/li&gt;
&lt;li&gt;Open folder &lt;code&gt;joker&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Opera:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;opera://extensions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load unpacked&lt;/strong&gt; (click &lt;strong&gt;Developer mode&lt;/strong&gt; if you don't see the button)&lt;/li&gt;
&lt;li&gt;Open folder &lt;code&gt;joker&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 8
&lt;/h3&gt;

&lt;p&gt;Enjoy the extension! 🙂&lt;/p&gt;




&lt;h1&gt;
  
  
  FAQ
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;1. Will my extension work on any OS? Any browser?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your extension will work on any common OS (Windows, Linux, OSX, Chrome OS) and any Chromium-based browser (Chrome, Edge, Opera) that supports &lt;a href="https://developer.chrome.com/extensions"&gt;&lt;strong&gt;Extensions API&lt;/strong&gt;&lt;/a&gt;, or Firefox, which is compatible to a large extent when using &lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions"&gt;&lt;strong&gt;WebExtensions API&lt;/strong&gt;&lt;/a&gt; (a common API). Minimal to no changes should be needed to make it compatible, and look the same elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What are some good resources to start?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will be pretty good to go with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions"&gt;https://developer.chrome.com/extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions"&gt;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Where can I get some inspiration? What to create? What is possible?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Check the list of all &lt;a href="https://developer.chrome.com/extensions/api_index"&gt;&lt;strong&gt;Chrome APIs&lt;/strong&gt;&lt;/a&gt;, that will give you a good overview about the available APIs, and also the sense of what they can do, and you can create based on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check &lt;a href="https://developer.chrome.com/extensions/manifest"&gt;&lt;strong&gt;Manifest File Format Summary&lt;/strong&gt;&lt;/a&gt;, as this is the main file in every extension.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. What is the folder structure?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every extension needs to have &lt;code&gt;manifest.json&lt;/code&gt; in the root. Any other files can be organized in any way you like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. How to publish the extension? How does it work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every browser has the store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore"&gt;&lt;strong&gt;Chrome Web Store&lt;/strong&gt;&lt;/a&gt; ($5 one time fee; slow reviews)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://addons.mozilla.org/en-US/firefox"&gt;&lt;strong&gt;Firefox ADD-ONS&lt;/strong&gt;&lt;/a&gt; (no fee)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home"&gt;&lt;strong&gt;Edge Add-ons&lt;/strong&gt;&lt;/a&gt; (no fee)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://addons.opera.com/en/extensions"&gt;&lt;strong&gt;Opera addons&lt;/strong&gt;&lt;/a&gt; (no fee; instantly published)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You then pack your extension (&lt;code&gt;zip&lt;/code&gt; or &lt;code&gt;crx&lt;/code&gt;) and submit it for a review. When approved, it is published.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Is there a way to get the extension published faster?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the extension is in a pending review, you cannot interrupt or speed up that process (Web Store). What you can do, is to develop your extension in a certain way, that makes reviewing it much faster. Here are some tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;have a good documentation, describe all the required and optional permissions, why they are needed, and what functionality they provide&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;avoid build step (no transpiling, minification, obfuscation), if possible&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;7. What are required and optional permissions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Permissions allow the extension to use some useful APIs and build some features on top of them. Permissions are defined in &lt;a href="https://developer.chrome.com/extensions/manifest"&gt;&lt;code&gt;manifest.json&lt;/code&gt;&lt;/a&gt;. The most common are &lt;strong&gt;"storage"&lt;/strong&gt; and &lt;strong&gt;"tabs"&lt;/strong&gt;. See the complete list &lt;a href="https://developer.chrome.com/extensions/declare_permissions"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Specifying the permission as &lt;strong&gt;Required&lt;/strong&gt; means, it is needed at all times to function properly (or to provide the basic functionality). &lt;strong&gt;Optional&lt;/strong&gt; permissions, on the other hand, are a good practice to say, these permissions are needed only when user turns on some additional functionality (through a Checkbox).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. What is the best way to develop an extension?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is no best way. Align the toolkit to what you need. It can be any of: JavaScript, &lt;a href="https://v8.dev/features/modules"&gt;&lt;strong&gt;JavaScript modules&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org"&gt;&lt;strong&gt;Typescript&lt;/strong&gt;&lt;/a&gt;, with dependencies, without, with bundler, without.&lt;/p&gt;

&lt;p&gt;Benefits of not having a build step, are obvious: easier and faster to develop, debug, publish, review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Where do I find some good icons?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://www.flaticon.com"&gt;&lt;strong&gt;flaticon&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Does the extension have to have a popup? What other kind of UI is possible?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Popup is optional. Actually, any UI is optional. There may be an extension that has no UI at all!&lt;/p&gt;

&lt;p&gt;Besides popup, other ways to display something, is in the new tab (like when the user clicks on the Toolbar icon), or &lt;a href="https://developer.chrome.com/extensions/override"&gt;&lt;strong&gt;override&lt;/strong&gt;&lt;/a&gt; any new tab with some content.&lt;/p&gt;




&lt;p&gt;Let's see how &lt;strong&gt;Joker&lt;/strong&gt; can be improved!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more jokes (more APIs)&lt;/li&gt;
&lt;li&gt;jokes by a category&lt;/li&gt;
&lt;li&gt;offline jokes (json file)&lt;/li&gt;
&lt;li&gt;save the joke to favorites (can view later)&lt;/li&gt;
&lt;li&gt;share the joke (if from API)&lt;/li&gt;
&lt;li&gt;themes&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Thank you for reading! I hope you had great fun and learned something new!&lt;/strong&gt; 🙂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/penge/joker"&gt;&lt;strong&gt;Joker on GitHub&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://chrome.google.com/webstore/detail/joker/eopobcheejmbpdggiilmdkjaanfonice"&gt;&lt;strong&gt;Joker on Web Store&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chrome</category>
      <category>extension</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Chrome Extension That Skips YouTube Ads (+Steps How To Create It)</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Thu, 02 Jan 2020 15:03:54 +0000</pubDate>
      <link>https://dev.to/penge/chrome-extension-that-skips-youtube-ads-steps-how-to-create-it-3ibp</link>
      <guid>https://dev.to/penge/chrome-extension-that-skips-youtube-ads-steps-how-to-create-it-3ibp</guid>
      <description>&lt;p&gt;Recently I have created chrome extension called &lt;a href="https://dev.to/penge/chrome-extension-that-turns-your-new-tab-into-a-note-taking-tool-4c7e"&gt;&lt;strong&gt;My Notes&lt;/strong&gt;&lt;/a&gt; and as it received nice reviews, I have decided to create another one – &lt;strong&gt;Skip Ad.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am also adding a tutorial this time, on how to create the extension.&lt;/p&gt;




&lt;h1&gt;
  
  
  Skip Ad
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Skip Ad&lt;/strong&gt; is a simple chrome extension that will skip YouTube ads for you, at &lt;a href="https://www.youtube.com" rel="noopener noreferrer"&gt;https://www.youtube.com&lt;/a&gt;, so you can enjoy the content without interruptions.&lt;/p&gt;

&lt;p&gt;I chose to create &lt;strong&gt;Skip Ad&lt;/strong&gt; as it is something I would like to use personally, and is also simple to create, which makes it suitable to showcase how to create chrome extension.&lt;/p&gt;

&lt;p&gt;After this article, you should not only have YouTube "without" ads but also be able to create chrome extension like this one.&lt;/p&gt;




&lt;h1&gt;
  
  
  Chapters
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;1 How to install &lt;strong&gt;Skip Ad&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;2 How &lt;strong&gt;Skip Ad&lt;/strong&gt; looks&lt;/li&gt;
&lt;li&gt;3 How &lt;strong&gt;Skip Ad&lt;/strong&gt; works&lt;/li&gt;
&lt;li&gt;
4 How to create &lt;strong&gt;Skip Ad&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;4.1 Start by creating a new folder&lt;/li&gt;
&lt;li&gt;4.2 Create &lt;code&gt;manifest.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;4.3 Add icon&lt;/li&gt;
&lt;li&gt;4.4 Install extension locally&lt;/li&gt;
&lt;li&gt;4.5 Time to &lt;strong&gt;skip the ads&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;4.6 Setting &lt;strong&gt;content script&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;4.7 Reload the extension&lt;/li&gt;
&lt;li&gt;4.8 Test the extension&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;5 &lt;strong&gt;Repository&lt;/strong&gt;
&lt;/li&gt;

&lt;/ul&gt;




&lt;h1&gt;
  
  
  1 How to install &lt;strong&gt;Skip Ad&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The extension can be installed from the Web Store, a place where extensions are published.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/skip-ad/bimlffinhbdhgpomhngmnhidjgnfcnoc" rel="noopener noreferrer"&gt;https://chrome.google.com/webstore/detail/skip-ad/bimlffinhbdhgpomhngmnhidjgnfcnoc&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  2 How &lt;strong&gt;Skip Ad&lt;/strong&gt; looks
&lt;/h1&gt;

&lt;p&gt;Once the extension is installed, the following icon appears in the extensions list and the toolbar.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhee31xdop4jeuy452tzn.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhee31xdop4jeuy452tzn.png" alt="icon"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you'd like to hide the icon from the toolbar, right-click the icon and select &lt;strong&gt;Hide in Chrome menu&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  3 How &lt;strong&gt;Skip Ad&lt;/strong&gt; works
&lt;/h1&gt;

&lt;p&gt;After you open YouTube page, the extension will periodically check whether new ads are present and close them for you. If you already had some YouTube page open before the extension was installed, a simple page refresh will do.&lt;/p&gt;

&lt;p&gt;The kind of ads that will be closed for you, and normally you would have to close manually by yourself, are shown below.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fucy1tknzkzye0uig8me7.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fucy1tknzkzye0uig8me7.png" alt="video-ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;^^^ Video Ad&lt;/strong&gt; can be closed with the &lt;strong&gt;Skip Ad&lt;/strong&gt; button (single ad is shown), or &lt;strong&gt;Skip Ads&lt;/strong&gt; button (multiple ads in the playlist).&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fy10bft9u5aoj26rdowco.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fy10bft9u5aoj26rdowco.png" alt="banner-ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;^^^ Banner Ad&lt;/strong&gt; can be closed with the &lt;strong&gt;X&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;Video Ad and Banner Ad can appear at the beginning of the video, or during the playback.&lt;/p&gt;

&lt;p&gt;Buttons that are used to close the ad, are loaded with the ad, but in case of Video Ad, many times displayed after a delay. &lt;strong&gt;Skip Ad&lt;/strong&gt; can skip the ad even before the button that closes the ad is shown. As a result, the ad may appear for a quick moment only.&lt;/p&gt;




&lt;h1&gt;
  
  
  4 How to create &lt;strong&gt;Skip Ad&lt;/strong&gt;
&lt;/h1&gt;




&lt;h3&gt;
  
  
  4.1 Start by creating a new folder
&lt;/h3&gt;

&lt;p&gt;We start by creating a new folder, to hold the extension files.&lt;/p&gt;

&lt;p&gt;The name of the folder can be any. Usually, is the same as the name of the extension itself, just in kebab case (also called hyphen case).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; extension name &lt;strong&gt;Skip Ad&lt;/strong&gt; =&amp;gt; folder name &lt;code&gt;skip-ad&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can two extensions have the same name, you might ask? The answer is yes.&lt;br&gt;
Two extensions can have the same name, and the same code, still, they both can be installed because their unique &lt;strong&gt;ID&lt;/strong&gt; will be different.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For learning purposes, let's call the extension differently – &lt;strong&gt;No More Ad&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Create a folder &lt;code&gt;no-more-ad&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  4.2 Create &lt;code&gt;manifest.json&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Every file we create from now on will go inside the folder &lt;code&gt;no-more-ad&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every extension &lt;strong&gt;has to have&lt;/strong&gt; &lt;code&gt;manifest.json&lt;/code&gt; file. How you name and organize the other files, that's up to you.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;manifest.json&lt;/code&gt; with the following content:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No More Ad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Skips YouTube Ads."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Required keys:&lt;/strong&gt; &lt;code&gt;manifest_version&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt;. Anything else is optional. More at: &lt;a href="https://developer.chrome.com/extensions/manifest" rel="noopener noreferrer"&gt;https://developer.chrome.com/extensions/manifest&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You might be surprised, but at this point, we have an extension that can be installed locally.&lt;br&gt;
It won't do anything though, just appear in the list of extensions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4.3 Add icon
&lt;/h3&gt;

&lt;p&gt;Download the icon from the &lt;a href="https://github.com/penge/skip-ad/raw/master/icon128.png" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and put it inside the &lt;code&gt;no-more-ad&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;manifest.json&lt;/code&gt; to assign the icon.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No More Ad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Skips YouTube Ads."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"icon128.png"&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;Now, as the extension has the icon, it will appear in the extensions list and the toolbar. You can try a different icon later.&lt;/p&gt;




&lt;h3&gt;
  
  
  4.4 Install extension locally
&lt;/h3&gt;

&lt;p&gt;Although we have only &lt;code&gt;manifest.json&lt;/code&gt; file, the extension can be installed already and as we update the code, it can be manually reloaded, which is also a way to test if nothing got broken.&lt;/p&gt;

&lt;p&gt;To install the extension, open the &lt;strong&gt;Extensions&lt;/strong&gt; list first, either via the menu or by entering &lt;code&gt;chrome://extensions&lt;/code&gt; into the tab.&lt;/p&gt;

&lt;p&gt;Now, click the &lt;strong&gt;Load unpacked&lt;/strong&gt; button:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fb97wzqry5oxuxph9jcfq.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fb97wzqry5oxuxph9jcfq.png" alt="load-unpacked"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;no-more-ad&lt;/code&gt; folder and click &lt;strong&gt;OPEN&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After the extension is loaded, you should see the following card: &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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fg1jcqm7or4k13462r5of.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fg1jcqm7or4k13462r5of.png" alt="card"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The orange icon indicates, the extension is installed locally.&lt;/p&gt;

&lt;p&gt;If you have installed &lt;strong&gt;Skip Ad,&lt;/strong&gt; disable it temporarily so it doesn't interfere with &lt;strong&gt;No More Ad.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  4.5 Time to &lt;strong&gt;skip the ads&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Buttons that are used to skip the ads (3 How &lt;strong&gt;Skip Ad&lt;/strong&gt; works) have CSS classes that make them easy to find.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS classes:&lt;/strong&gt;&lt;/p&gt;

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

&lt;span class="c1"&gt;// Video Ad; "Skip Ad" or "Skip Ads" button&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ytp-ad-skip-button-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Banner Ad; "X" button&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ytp-ad-overlay-close-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The code to skip the ads will be fairly simple. It should look for the buttons that can close the ad, and if it finds them, trigger the &lt;code&gt;click()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;youtube.js&lt;/code&gt; now:&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;click&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clazz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clazz&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &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;button&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No More Ad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ytp-ad-skip-button-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ytp-ad-overlay-close-button&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="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No More Ad - Init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can try the code by opening YouTube and paste it to the console. Then, check some videos. If the ad gets closed, you should see in the console:&lt;/p&gt;

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

&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No More Ad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The last step of the puzzle is to get this code to the YouTube page without manually pasting it, that is, via the extension.&lt;/p&gt;




&lt;h2&gt;
  
  
  4.6 Setting &lt;strong&gt;content script&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Content script&lt;/strong&gt; can be either css, or js, or both. It is a term that, in other words, adds or modifies (as it can access the &lt;strong&gt;DOM&lt;/strong&gt;) the content of the page, where it is inserted.&lt;/p&gt;

&lt;p&gt;In our case, we intend to insert earlier created &lt;code&gt;youtube.js&lt;/code&gt; to the YouTube page.&lt;/p&gt;

&lt;p&gt;This step is very easy, as it requires only to update &lt;code&gt;manifest.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No More Ad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Skips YouTube Ads."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"icon128.png"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content_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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matches"&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="s2"&gt;"https://*.youtube.com/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"js"&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="s2"&gt;"youtube.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;We have defined, that any page that &lt;strong&gt;matches&lt;/strong&gt; a YouTube page, should include &lt;code&gt;youtube.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The content script defined via &lt;code&gt;manifest.json&lt;/code&gt;, is injected &lt;strong&gt;declaratively,&lt;/strong&gt; which means, automatically. It is the easiest way of inserting a script to the other page.&lt;/p&gt;

&lt;p&gt;Another way how to inject the content script, is &lt;strong&gt;programmatically.&lt;/strong&gt; It is more complicated, but also more customizable.&lt;/p&gt;

&lt;p&gt;Content scripts run in an isolated environment, therefore, they cannot influence other scripts. What they can do, as mentioned above, is access the &lt;strong&gt;DOM.&lt;/strong&gt; And that's exactly what we needed.&lt;/p&gt;

&lt;p&gt;More about content scripts is here: &lt;a href="https://developer.chrome.com/extensions/content_scripts" rel="noopener noreferrer"&gt;https://developer.chrome.com/extensions/content_scripts&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4.7 Reload the extension
&lt;/h2&gt;

&lt;p&gt;The extension we installed in the step 4.4 Install extension locally requires to be reloaded, to apply the changes.&lt;/p&gt;

&lt;p&gt;This is easy to do by clicking the reload button.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fg1jcqm7or4k13462r5of.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fg1jcqm7or4k13462r5of.png" alt="card"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything went well, no &lt;strong&gt;Errors&lt;/strong&gt; should be shown.&lt;/p&gt;




&lt;h2&gt;
  
  
  4.8 Test the extension
&lt;/h2&gt;

&lt;p&gt;Now, it's time to test the extension. Open a new YouTube page, or reload the existing.&lt;/p&gt;

&lt;p&gt;To see that the content script was inserted, visit &lt;strong&gt;Sources:&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;In the console you can see:&lt;/p&gt;

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

&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No More Ad - Init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Check some YouTube videos. What you should experience is, the ads are getting closed automatically.&lt;/p&gt;

&lt;p&gt;Check the console again. For every ad that gets closed, you should see:&lt;/p&gt;

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

&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No More Ad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You have now successfully created your extension.&lt;/p&gt;




&lt;h1&gt;
  
  
  5 &lt;strong&gt;Repository&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;You can check the extension here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/penge/skip-ad" rel="noopener noreferrer"&gt;https://github.com/penge/skip-ad&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I hope you enjoyed the article and learned new.&lt;/p&gt;

&lt;p&gt;If you have any questions, I will gladly answer them.&lt;/p&gt;

&lt;p&gt;If you'd like to see more tips or tricks, or series on this topic, let me know.&lt;/p&gt;

&lt;p&gt;Now, let's enjoy this extension and start 2020 with fewer ads!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>chrome</category>
      <category>extension</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Chrome Extension that turns your "New Tab" into a note taking tool</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Mon, 18 Nov 2019 10:16:38 +0000</pubDate>
      <link>https://dev.to/penge/chrome-extension-that-turns-your-new-tab-into-a-note-taking-tool-4c7e</link>
      <guid>https://dev.to/penge/chrome-extension-that-turns-your-new-tab-into-a-note-taking-tool-4c7e</guid>
      <description>&lt;h1&gt;
  
  
  Before
&lt;/h1&gt;

&lt;p&gt;I am opening TextEdit, many times. Creating a new file, or maintaining one. All that just because of &lt;strong&gt;writing down some notes or text to copy.&lt;/strong&gt; Need to save the file, sometimes forget to. I need to open the file. Need to switch between Chrome and TextEdit (or OneNote, you name it).&lt;/p&gt;

&lt;p&gt;Sounds like enough of extra work for you? This is something I was trying to solve. So here it is.&lt;/p&gt;

&lt;h1&gt;
  
  
  Now
&lt;/h1&gt;

&lt;p&gt;I have made a new &lt;strong&gt;Google Chrome Extension&lt;/strong&gt; that makes copying multiple texts between pages so much easier, or writing down notes, todos, ideas. Every edit is autosaved and can be seen in other Chrome windows as well!&lt;/p&gt;

&lt;p&gt;The name of the extension is &lt;strong&gt;My Notes&lt;/strong&gt;. And what it does? It turns your &lt;strong&gt;"New Tab"&lt;/strong&gt; into &lt;strong&gt;a note taking tool!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Some points
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Great for Notes, Todos, sharing text (Copy/Paste)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It works immediately after you open a "New Tab"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Every edit and paste is saved (and waiting for you once you come back)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is Synchronized across every Chrome window you have open&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it looks
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Where to get it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/my-notes/lkeeogfaiembcblonahillacpaabmiop" rel="noopener noreferrer"&gt;https://chrome.google.com/webstore/detail/my-notes/lkeeogfaiembcblonahillacpaabmiop&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;I hope you will find this tool useful and it helps you be more productive.&lt;br&gt;
If you have any suggestions, do not hesitate to send them.&lt;br&gt;
Thank you!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>google</category>
      <category>chrome</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Chrome Extension that stops your Social Media addiction</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Sat, 16 Nov 2019 10:07:17 +0000</pubDate>
      <link>https://dev.to/penge/i-have-made-a-simple-chrome-extension-that-prevents-you-from-wasting-your-time-on-social-media-31ib</link>
      <guid>https://dev.to/penge/i-have-made-a-simple-chrome-extension-that-prevents-you-from-wasting-your-time-on-social-media-31ib</guid>
      <description>&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;How many times today did you type:&lt;/p&gt;

&lt;p&gt;- &lt;strong&gt;f&lt;/strong&gt; (as faceboook)&lt;br&gt;
- &lt;strong&gt;t&lt;/strong&gt; (as twitter)&lt;br&gt;
- &lt;strong&gt;i&lt;/strong&gt; (as instagram)&lt;br&gt;
- &lt;strong&gt;y&lt;/strong&gt; (as youtube)&lt;br&gt;
- &lt;strong&gt;r&lt;/strong&gt; (as reddit)&lt;/p&gt;

&lt;p&gt;or other?&lt;/p&gt;

&lt;p&gt;How many times today did you open a new tab, and subconsciously, without much thinking, you are on Facebook? Again.&lt;/p&gt;

&lt;p&gt;Things that are easy to access, are hard to avoid. And, I have been in this trap too. Here is a solution I have been working on.&lt;/p&gt;

&lt;h1&gt;
  
  
  Help
&lt;/h1&gt;

&lt;p&gt;I have created a &lt;strong&gt;Google Chrome Extension&lt;/strong&gt; with a simple purpose.&lt;/p&gt;

&lt;p&gt;- It prevents you from visiting social media. (you can also customize the list of sites)&lt;/p&gt;

&lt;p&gt;- It handles your temptation of visiting social media. (or other sites you specify)&lt;/p&gt;

&lt;p&gt;- It makes you more productive!&lt;/p&gt;

&lt;h1&gt;
  
  
  Where to get it
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/stop-social-media/jdeohkoemlaidjgdhlcchdmgdghihjag"&gt;https://chrome.google.com/webstore/detail/stop-social-media/jdeohkoemlaidjgdhlcchdmgdghihjag&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;Any feedback and any thoughts on this topic very appreciated!&lt;br&gt;
Thank you!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>google</category>
      <category>chrome</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to write a blog in Maren?</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Mon, 11 Nov 2019 01:22:46 +0000</pubDate>
      <link>https://dev.to/penge/how-to-write-a-blog-in-maren-3dg2</link>
      <guid>https://dev.to/penge/how-to-write-a-blog-in-maren-3dg2</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xDjRIeZv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uidkidg7nu6pma71hqny.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xDjRIeZv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uidkidg7nu6pma71hqny.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Maren is a simple theme based static site generator.&lt;br&gt;
Let's look first at these words, what they mean.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simple&lt;/strong&gt; (There are only 4 simple commands to know, you don't even have to remember them. Maren also doesn't force you to learn any conventions or rules, therefore, you're freer to focus on what's important, the writing.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Theme based&lt;/strong&gt; (Maren converts your blog, which is a basically set of Markdown files, to HTML, by using a Theme - this is an essential concept of Maren which we'll get back to later. It is nothing complicated or something to be worried about. Actually, it is an exciting playground!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Static site generator&lt;/strong&gt; (It means Maren can take care of creating your blog. You write the blog, but the final product, called the build, which you then upload to the Internet, can be created for you.)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Examples
&lt;/h1&gt;

&lt;p&gt;First, let's see what we can achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://i.ibb.co/KKG8Srz/screenshot.png"&gt;https://i.ibb.co/KKG8Srz/screenshot.png&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maren.io/examples/"&gt;https://maren.io/examples/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Maren
&lt;/h1&gt;

&lt;p&gt;Maren as a name has 2 origins. Maren, at its core, is a theme based markdown renderer (might sound complicated, but isn't).&lt;br&gt;
In those words you can see &lt;strong&gt;ma&lt;/strong&gt;rkdown &lt;strong&gt;ren&lt;/strong&gt;derer and therefore, a memorable Maren was born.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fza9-Frl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jh8xh6al98q1mjx2o5bt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fza9-Frl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jh8xh6al98q1mjx2o5bt.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maren also means "star of the sea" and comes from the Latin name Mary.&lt;br&gt;
I considered that as a very nice name, also easy to remember, and type.&lt;/p&gt;
&lt;h1&gt;
  
  
  Creating our first blog
&lt;/h1&gt;

&lt;p&gt;Get ready. Make yourself comfortable. Grab your favorite tea or coffee. I will now guide you throw the whole process of creating the blog!&lt;/p&gt;

&lt;p&gt;The steps we will cover, are:&lt;br&gt;
1) Starting a new blog&lt;br&gt;
2) Writing the content of the blog (the most important part)&lt;br&gt;
3) Previewing the blog (checking it looks and feels as we expected)&lt;br&gt;
4) Uploading the blog so the whole Internet can see it!&lt;br&gt;
5) Using your own theme!&lt;/p&gt;

&lt;p&gt;Excited? Let's get started!&lt;/p&gt;
&lt;h1&gt;
  
  
  Step 1: Starting a new blog
&lt;/h1&gt;

&lt;p&gt;It all starts by creating a new folder for our blog.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir myblog
cd myblog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's time to install Maren! (run the commands in our &lt;strong&gt;myblog&lt;/strong&gt; directory)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
npm install maren
npx maren init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; is almost done. And it couldn't be faster!&lt;/p&gt;

&lt;p&gt;We have now &lt;code&gt;myblog&lt;/code&gt; folder, installed Maren, and the blog is initiated by &lt;code&gt;maren init&lt;/code&gt; we run. But, what does &lt;code&gt;maren init&lt;/code&gt; do, you might ask?&lt;/p&gt;

&lt;p&gt;It will simply prepare our blog to have the folder structure, that will guide us to organize our files nicely!&lt;br&gt;
The content of our &lt;code&gt;myblog&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/myblog/documents
~/myblog/draft
~/myblog/static
~/myblog/themes
~/myblog/maren.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What are those folders? Let's think about that in step 2!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Writing the content
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;/documents&lt;/strong&gt; =&amp;gt; place to write our Markdown files!&lt;br&gt;
&lt;strong&gt;/draft&lt;/strong&gt; =&amp;gt; place to put our unfinished work (Markdown files, text files, whatever!)&lt;br&gt;
&lt;strong&gt;/static&lt;/strong&gt; =&amp;gt; place to put our images, music files, videos, simply any static content that is supposed to, stay static!&lt;br&gt;
&lt;strong&gt;/themes&lt;/strong&gt; =&amp;gt; this folder is &lt;em&gt;initially empty&lt;/em&gt;, but a whole thing can be going on once we dig into it. It is the place for our themes! Remember? Themes used to render Markdown files to HTML? Here they are.&lt;br&gt;
&lt;strong&gt;/maren.json&lt;/strong&gt; =&amp;gt; A configuration file that can set the current theme, or plugins to use. It is an optional file (doesn't have to exist).&lt;/p&gt;

&lt;p&gt;Let's write our first Markdown files, shall we?&lt;/p&gt;

&lt;p&gt;To write Markdown files, you might use any editor you like! In our scenario, we simply put a few commands to get ready fast! And to make it even more interesting, there are two strategies to do so! Pick the one you like most! You can even combine them and use them simultaneously!&lt;/p&gt;
&lt;h2&gt;
  
  
  Strategy 1
&lt;/h2&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "# My blog" &amp;gt; documents/index.md
echo "# 404" &amp;gt; documents/404.md

mkdir documents/article-1
mkdir documents/article-2
echo "# My first article" &amp;gt; documents/article-1/index.md
echo "# My second article" &amp;gt; documents/article-2/index.md

mkdir draft/not-yet
echo "# My draft" &amp;gt; draft/not-yet/index.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Strategy 1 might work perfectly, it fully mirrors what you might expect to see at your website, as html file of course.&lt;/p&gt;
&lt;h2&gt;
  
  
  Strategy 2
&lt;/h2&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "# My blog" &amp;gt; documents/index.md
echo "# 404" &amp;gt; documents/404.md

echo "# My first article" &amp;gt; documents/article-1.md
echo "# My second article" &amp;gt; documents/article-2.md

echo "# My draft" &amp;gt; draft/not-yet.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Strategy 2 is more natural and helps to get around more easily once you have many files opened. As being said, you're free to use both strategies simultaneously to achieve your best!&lt;/p&gt;
&lt;h1&gt;
  
  
  Step 3: Previewing the blog
&lt;/h1&gt;

&lt;p&gt;We are almost done! To preview the blog, we need to build it first.&lt;br&gt;
To do so, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/myblog $ npx maren build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This step will create a special folder named &lt;strong&gt;_build&lt;/strong&gt;. It is a place where you'll find all html files, themes files, static files. But not drafts. Still though, you can preview the drafts using the local server!&lt;/p&gt;

&lt;p&gt;To preview the blog, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/myblog $ npx maren serve

# Serving at http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it! Open the browser and try to visit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080
http://localhost:8080/any-random-url/
http://localhost:8080/article-1/
http://localhost:8080/article-2/
http://localhost:8080/not-yet/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt; If you'd like to preview your blog and see your edits without restarting the server, simply, instead of &lt;code&gt;maren serve&lt;/code&gt;, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx maren watch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 4: Uploading the blog
&lt;/h1&gt;

&lt;p&gt;Uploading the blog is unfortunately behind the scope of this article, but I will explain to you all the necessary steps.&lt;/p&gt;

&lt;p&gt;To upload the blog, you probably wouldn't like to do it manually!&lt;br&gt;
This is where &lt;strong&gt;plugins&lt;/strong&gt; comes to play. One of these plugins is &lt;strong&gt;maren-s3&lt;/strong&gt; which provides an easy upload capability to &lt;strong&gt;AWS S3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to install the plugin inside &lt;strong&gt;myblog&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install maren-s3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To enable the plugin, we might need to update &lt;strong&gt;maren.json&lt;/strong&gt;, to make it look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "theme": "",
  "plugins": [
    "maren-s3"
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, we simply upload the blog by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx maren upload myblog # name of our S3 bucket.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 5: Using your own theme
&lt;/h1&gt;

&lt;p&gt;By default, &lt;strong&gt;a built-in theme&lt;/strong&gt; is used, to get quicky running.&lt;br&gt;
It is also a perfect fallback.&lt;/p&gt;

&lt;p&gt;Now, it's time to boost things a bit and use some custom theme.&lt;br&gt;
To do so, simply run inside your &lt;strong&gt;myblog&lt;/strong&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/penge/maren-theme-default.git themes/default
(cd themes/default &amp;amp;&amp;amp; npm install)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To use the theme, or to change the theme, we update &lt;strong&gt;maren.json&lt;/strong&gt;, and make in this case, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "theme": "default",
  "plugins": [
    "maren-s3"
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, run the build and server again!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx maren build
npx maren serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And whoala! You should see the blog in a fresh new look!&lt;br&gt;
The best part of it is, the Theme can be developed by any set of tools, and customized to any level of imagination.&lt;/p&gt;
&lt;h1&gt;
  
  
  Final notes
&lt;/h1&gt;

&lt;p&gt;I hope you've enjoyed reading this article as I've enjoyed writing it.&lt;br&gt;
Probably, at this time, the coffee (or tea) is already finished, time for another one!&lt;/p&gt;

&lt;p&gt;Also, I have mentioned, there is no need to remember &lt;strong&gt;maren&lt;/strong&gt; commands. To get a reminder, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx maren
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The output you might see (especially if you have &lt;strong&gt;maren-s3&lt;/strong&gt; installed) might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;maren &amp;lt;command&amp;gt;

Commands:
  maren init                                init current folder
  maren build                               build blog to _build directory
  maren watch                               watch markdown files for changes and
                                            create html
  maren serve [--port]                      serve files for local preview
  maren upload &amp;lt;bucket&amp;gt; [--themes]          upload to S3
  [--static] [--html] [--dryrun]

Options:
  --version  Show version number                                       [boolean]
  --help     Show help                                                 [boolean]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's all for now!&lt;br&gt;
In case you'd like to know more, please, visit &lt;a href="https://maren.io"&gt;https://maren.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>blogging</category>
      <category>writing</category>
      <category>blog</category>
    </item>
    <item>
      <title>Maren (simple theme based static site generator)</title>
      <dc:creator>Pavel Bucka</dc:creator>
      <pubDate>Sat, 02 Nov 2019 12:00:26 +0000</pubDate>
      <link>https://dev.to/penge/maren-simple-theme-based-static-site-generator-52d2</link>
      <guid>https://dev.to/penge/maren-simple-theme-based-static-site-generator-52d2</guid>
      <description>&lt;p&gt;Hi friends, I have created this static site generator, Maren (&lt;a href="https://maren.io"&gt;https://maren.io&lt;/a&gt;) that converts Markdown files to HTML using a theme.&lt;/p&gt;

&lt;p&gt;The main difference to other SSG is in "Themes". Themes are separated, live by their own, and can be developed by any template library of choice (there's no limitation to that).&lt;/p&gt;

&lt;p&gt;Any customization to the theme is easy, also reusability of its parts. There are no scaffolds to follow, no layout files, scortcodes, custom tags, or other structure dictated by other SSG.&lt;/p&gt;

&lt;p&gt;Please, let me know your thoughts on this. Also, if you'd like to help me out to make it more generally available, please, send me a message. Thank you in advance.&lt;/p&gt;

&lt;p&gt;All best! :)&lt;br&gt;
Pavel&lt;/p&gt;

&lt;p&gt;&lt;a href="https://maren.io"&gt;https://maren.io&lt;/a&gt;&lt;br&gt;
&lt;a href="https://discord.gg/VNVHa7r"&gt;https://discord.gg/VNVHa7r&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>theme</category>
      <category>markdown</category>
      <category>blog</category>
    </item>
  </channel>
</rss>
