<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Alexa Steinbrück</title>
    <description>The latest articles on Forem by Alexa Steinbrück (@alexabruck).</description>
    <link>https://forem.com/alexabruck</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%2F101517%2F69e46bf4-ebe7-4b88-8efb-7f22837f0603.jpg</url>
      <title>Forem: Alexa Steinbrück</title>
      <link>https://forem.com/alexabruck</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alexabruck"/>
    <language>en</language>
    <item>
      <title>Write your first CRON job &amp; monitor product discounts with Nodejs</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 04 Jan 2021 22:10:15 +0000</pubDate>
      <link>https://forem.com/alexabruck/write-your-first-cron-job-monitor-product-discounts-with-nodejs-3kd9</link>
      <guid>https://forem.com/alexabruck/write-your-first-cron-job-monitor-product-discounts-with-nodejs-3kd9</guid>
      <description>&lt;p&gt;There are (paid) services out there that let you monitor the price of a certain product on the internet. But did you know that you can write this kind of monitoring tool yourself?&lt;/p&gt;

&lt;p&gt;This use case is perfect for a cron job: A cron job schedules the execution of code at specific times (e.g. once a day, every 5 minutes, etc). Cron jobs are usually used by system administrators to make backups of their servers etc. But it can be useful for other (fun) things too!&lt;/p&gt;

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

&lt;h1&gt;
  
  
  🗂️ 1. The &lt;code&gt;crontab&lt;/code&gt; command
&lt;/h1&gt;

&lt;p&gt;The single Unix utility to know in order to get started with cronjobs is called &lt;code&gt;crontab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's named cron*tab* because it refers to the cron*table*, which is a configuration file (also called table). To get more information on the &lt;code&gt;crontab&lt;/code&gt; utility, type &lt;code&gt;man crontab&lt;/code&gt; into the Terminal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two important commands to remember:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✨ &lt;code&gt;crontab -l&lt;/code&gt; This displays the content of your current cron table, meaning all your scheduled cron jobs. (If you have never initialized a cron job, it will say "crontab: no crontab for {user}")&lt;/p&gt;

&lt;p&gt;✨ &lt;code&gt;crontab -e&lt;/code&gt; with which you can edit your cron table, meaning adding and deleting cron jobs! (If you haven't initiated a crontab yet, it will say: "crontab: no crontab for {user} - using an empty one")&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes about text editors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The command &lt;code&gt;crontab -e&lt;/code&gt; will try to open the crontab file with a text editor. If you haven't configured this before, the default will be vim, which is fine. By contrast, I had difficulties using vscode.&lt;/p&gt;

&lt;p&gt;Tip: If your default editor isn't vim but you want to use vim only once for this occasion (without changing the default editor settings in your bashprofile), type &lt;code&gt;export EDITOR=vi&lt;/code&gt; into your Terminal, this will set your default editor to vim until the end of this terminal session (e.g. until you close the Terminal).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions&lt;/strong&gt;&lt;br&gt;
Why does &lt;code&gt;crontab -e&lt;/code&gt; create a temporary file in /tmp? This is normal behavior. Instead of editing the crontab directly, they will let you write into a temporary file first, which will then be copied to the real crontab.&lt;/p&gt;
&lt;h1&gt;
  
  
  🤡 2. Writing your first (silly) cron job
&lt;/h1&gt;

&lt;p&gt;To get started, let's do something silly. Let's create a cron job that makes your computer say a word out loud every minute. (Very useful to annoy a friend or roommate).&lt;/p&gt;

&lt;p&gt;First, open the crontab with the crontab command:&lt;br&gt;
&lt;code&gt;crontab -e&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then add the following line to the file and save the file.&lt;br&gt;
&lt;code&gt;* * * * * say Hello&lt;/code&gt;&lt;br&gt;
This will immediately start your first cron job!&lt;/p&gt;

&lt;p&gt;But what does this mean? The stars here represent the time instructions (5 stars separated by a space mean „every minute“), followed by the actual shell command (&lt;code&gt;say Hello&lt;/code&gt;) that will be executed in the specified rhythm.&lt;/p&gt;

&lt;p&gt;Why does * * * * * mean every minute? Because this is the magic instruction syntax of crontabs! And the star means "every" like in regexes.&lt;/p&gt;

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

&lt;p&gt;If you want to learn more about the syntax and how to express situations like &lt;em&gt;every day at midnight&lt;/em&gt;, or &lt;em&gt;every 15 minutes in August&lt;/em&gt; watch &lt;a href="https://www.youtube.com/watch?list=PL-osiE80TeTvGhHkpvfmKWOiIPF8UVy6c&amp;amp;v=QZJ1drMQz1A&amp;amp;feature=youtu.be"&gt;this video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Okay, this cronjob was just a silly test, so let's delete it! You can just remove the line by editing the file (with &lt;code&gt;crontab -e&lt;/code&gt;). Or remove the whole crontab (with &lt;code&gt;crontab -r&lt;/code&gt;).&lt;/p&gt;
&lt;h1&gt;
  
  
  ⛓️ 3. Write a cron job that runs code from another file
&lt;/h1&gt;

&lt;p&gt;Instead of typing the actual code we want to execute into the crontab itself, we can write our code into a file and execute the file from the crontab. The file could be written in any programming language you like, e.g. shell, Node, Python etc...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1 (Shell)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;* * * * . path/to/my-shell-script.sh&lt;/code&gt;&lt;br&gt;
will execute a Shell script. The single dot before the file path means execute („source“) the following script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2 (Node)&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;* * * * path/to/your/node/binary path/to/my-node-script.js&lt;/code&gt;&lt;br&gt;
will execute a Node script.&lt;/p&gt;

&lt;p&gt;Note Example 2: Note that you can't just type &lt;code&gt;node path/to/my-node-script.js&lt;/code&gt;, but you have to insert the full path to the node binary too. Why is that? The fact that you can usually run node just by typing &lt;code&gt;node&lt;/code&gt; is because you configured your &lt;code&gt;PATH&lt;/code&gt;. Cron jobs do not read this PATH like you would expect, that's why they don't know what node or npm is. &lt;/p&gt;

&lt;p&gt;You can get the path to your node binary by typing &lt;code&gt;which node&lt;/code&gt; into the console. If you haven't installed node at all on your machine, you should do that first (ideally via nvm). But note that this is by no means a requirement to write a cron job. You can choose any other language!&lt;/p&gt;
&lt;h1&gt;
  
  
  🕵️‍♀️ 4. Writing the (Node) script that finds the discount
&lt;/h1&gt;

&lt;p&gt;Now let's get to the actual heart of it all: Analysing a website to get details about a certain product. This part very much depends on the website you're analysing. Here is how I approach this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(1)&lt;/strong&gt; First I check with a browser plugin called &lt;strong&gt;"Wappalyzer“&lt;/strong&gt; which technologies are used on the site. This gives me hints about how the website works: Is it a Single-Page-App that consumes a Rest API or is it server side rendered. Does it use any known APIs?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2)&lt;/strong&gt; Then I check the network tab in the &lt;strong&gt;Browser Dev Tools&lt;/strong&gt; and filter for „XHR“ requests, and quickly scan through their JSON responses. Is there something that looks like a Rest API to me? Are there any key names in data that seem relevant to me, e.g. product name, price, etc?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(3)&lt;/strong&gt; If this is the case, we're lucky! We can just parse these JSON outputs with a (Node) script which we will build now.&lt;/p&gt;

&lt;p&gt;Note: In case there aren't any JSON responses with relevant data, the site is probably server-side rendered. This means we have to do a little more work by parsing the HTML and look for relevant CSS classes and ids in order to get the data. I'd prefer to do this task in Node, because it is plain Javascript and it has the DOM API natively baked in. But if you write your script in Python, you would have to use a library called Beautiful Soup.&lt;/p&gt;

&lt;p&gt;Our little node script is really a piece of cake. We need 1 library, which is called &lt;code&gt;node-fetch&lt;/code&gt;, which makes http requests easier.&lt;br&gt;
So let's create a new Node project by &lt;br&gt;
&lt;code&gt;yarn init&lt;/code&gt;&lt;br&gt;
And then install the library&lt;br&gt;
&lt;code&gt;yarn add node-fetch&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let's write our little Node script. Note that the content depends on your usecase, website, etc. You have to write your own! ;-)&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;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-fetch&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;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url-for-your-product-from-the-rest-api&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;MAX_PRICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;fetch&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="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="p"&gt;)&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;data&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;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_PRICE&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`PRICE ALARM :-) &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;sendNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;sendNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* Because this is a cron job this plain console.log is enough to send an email to me... */&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="nx"&gt;message&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;h1&gt;
  
  
  📬 5. Let the cron job report back to you
&lt;/h1&gt;

&lt;p&gt;Note that in our little script the function &lt;code&gt;sendNotification&lt;/code&gt; is really just doing a plain &lt;code&gt;console.log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But ask yourself, where will a &lt;code&gt;console.log&lt;/code&gt; end up if it is run by a cron job? All cron jobs are run in non-interactive shells, there is no terminal screen attached to it!&lt;/p&gt;

&lt;p&gt;Most of the time cron &lt;em&gt;emails&lt;/em&gt; the output to the user whose crontab the job came from, but only if they have set up a „mailer daemon“ (like sendmail, qmail, postfix). If this isn't the case, the output just lands somewhere on your computer, and nobody really knows where. :-D&lt;/p&gt;

&lt;p&gt;In my case I already had such a mailer deamon installed, and the emails ended up in a file under &lt;code&gt;/var/mail&lt;/code&gt;. Check out if you have such a file. If this is the case, then your mailer daemon works, and you can easily set the recipient to a real email address, e.g. your Gmail address, like so:&lt;/p&gt;

&lt;p&gt;At the top of the crontab file write:&lt;br&gt;
&lt;code&gt;MAILTO="youremailadress@gmail.com"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then check your Gmail spam folder, after the cronjob was executed (if necessary, change the cron job timing back to each minute for testing). Then click on „report as not spam“ and it will go to your regular inbox.&lt;/p&gt;

&lt;p&gt;Yaay, you should now receive an email when the product has a discount!!&lt;/p&gt;

&lt;h1&gt;
  
  
  😴 6. But wait - what happens when I close my laptop?
&lt;/h1&gt;

&lt;p&gt;Question: Will it run the cronjob nevertheless? &lt;br&gt;
Answer: No! Cron doesn't execute while the computer is asleep.&lt;/p&gt;

&lt;p&gt;But there is a trick you can do: You can schedule your computer to "wake up" 5 minutes or so before your cron job is scheduled.&lt;br&gt;
On Mac you can do this via Preferences &amp;gt;&amp;gt; Energy Saver &amp;gt;&amp;gt; Schedule.&lt;/p&gt;

&lt;p&gt;Happy cron jobbing!&lt;/p&gt;




&lt;p&gt;Credits: Title image by &lt;a href="https://www.flickr.com/photos/photosvega/8184903936/in/photolist-dtgLMo-4w9qaW-7svqiD-8v1q6T-e4pR7-rqW93q-23jppVH-5qhemo-oeXqzE-cted5W-9RGUB8-7ASABK-5dLnHV-8Luk2K-5eqYC3-erDaj-5DhZnG-Av2fPK-sAt6C-HmAzJ-skDmxU-co64gJ-dMpjq-agJK1z-nxhgPZ-6JMRS8-7vQ99J-89xj6U-9xKyFU-Bz6AT-g12GCs-a6NXy4-Bz6L1-3eKq11-2jZ2RLn-4EUabQ-8jqbkg-uoGiwg-4xVdmq-dNSmDa-B4uAyk-amT8d2-8SfrZm-4rFABb-7SphZq-6GeJF5-4m3z8z-53ZyPq-prhAo-9SWqmg"&gt;David Vega&lt;/a&gt; under CC BY 2.0&lt;/p&gt;

</description>
      <category>cronjob</category>
      <category>commandline</category>
      <category>node</category>
      <category>automation</category>
    </item>
    <item>
      <title>Github authentication facts I forget every two months</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 10 Aug 2020 16:36:47 +0000</pubDate>
      <link>https://forem.com/alexabruck/github-authentication-facts-i-forget-every-two-months-3e7i</link>
      <guid>https://forem.com/alexabruck/github-authentication-facts-i-forget-every-two-months-3e7i</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Git recommends SSH over HTTPS!

&lt;ul&gt;
&lt;li&gt;You make the decision for SSH/HTTPS, when you

&lt;ul&gt;
&lt;li&gt;clone a remote repository, or&lt;/li&gt;
&lt;li&gt;assign a remote to a local repository&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When you do HTTPS:

&lt;ul&gt;
&lt;li&gt;You can use the credential.helper in OSX to cache your password&lt;/li&gt;
&lt;li&gt;PITFALL POTENTIAL: If you use 2FA, then your password is &lt;em&gt;not&lt;/em&gt; your password, but your &lt;strong&gt;Personal Access Token&lt;/strong&gt;, which you can create here &lt;a href="https://github.com/settings/tokens"&gt;https://github.com/settings/tokens&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;When you do SSH:

&lt;ul&gt;
&lt;li&gt;You need to have a key available. Otherwise you get "Not authenticated (public key error)" or something along these lines...&lt;/li&gt;
&lt;li&gt;Test if you have a key by typing in the console: &lt;code&gt;ssh -vT git@github.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you dont have a key, then go create one: &lt;a href="https://github.com/settings/keys"&gt;https://github.com/settings/keys&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Why you shouldn't use the file creation time to represent a date</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 10 Aug 2020 12:53:13 +0000</pubDate>
      <link>https://forem.com/alexabruck/why-gatsby-s-file-birthtime-value-is-breaking-on-ci-cd-5g45</link>
      <guid>https://forem.com/alexabruck/why-gatsby-s-file-birthtime-value-is-breaking-on-ci-cd-5g45</guid>
      <description>&lt;p&gt;Let's say you build a blog with Gatsby where each article is written in markdown and queried from your local filesystem with GraphQL with the help of the plugin &lt;code&gt;gatsby-source-filesystem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you also want to show the date of when the article was created.&lt;/p&gt;

&lt;p&gt;So you go to Gatsby's interactive GraphQL interface (see below) and search for a field name that looks like it's a date. You find &lt;code&gt;birthTime&lt;/code&gt;. Sounds great! The intuition here is that the article creation date is identical to the date &lt;strong&gt;when the file was first created on a hard drive/file system&lt;/strong&gt;, which is what &lt;code&gt;birthTime&lt;/code&gt; signifies.&lt;/p&gt;

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

&lt;p&gt;So you query this field and it gives you some dates that look about right. Then you render them in your frontend and everything looks great on the &lt;strong&gt;development server&lt;/strong&gt;. Even when do a real build on your local machine (&lt;code&gt;gatsby build&lt;/code&gt; &amp;amp; &lt;code&gt;gatsby serve&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The surprise comes when you involve CI/CD. Let's say you deploy with Netlify. Once your site is build by Netlify based on your Git repository, you will see &lt;strong&gt;different dates&lt;/strong&gt; - namely: &lt;strong&gt;The time it is right now&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Why is that? Remember that we said earlier that &lt;code&gt;birthTime&lt;/code&gt; is referring to the date when the file was first created on a hard drive/file system. Now, if you have a CI/CD service like Netlify building your site, it first fetches your repository from Github and creates all those files &lt;strong&gt;again on its own filesystem&lt;/strong&gt;. Those are entirely new files! That's why their &lt;code&gt;birthTime&lt;/code&gt; is different.&lt;/p&gt;

&lt;p&gt;So how can you add a creation date to your blog entries?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hardcode a date string into the frontmatter of your markdown files&lt;/li&gt;
&lt;li&gt;Use a CMS (like Netlify CMS) that offers a UI for these things, or adds dates to the data layer automatically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Just like &lt;a class="comment-mentioned-user" href="https://dev.to/pentacular"&gt;@pentacular&lt;/a&gt;
 said: "If it's a meaningful part of the file content, it better be part of the file content."&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>graphql</category>
      <category>netlify</category>
      <category>dates</category>
    </item>
    <item>
      <title>Have you used Netlify for real client projects?</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Thu, 30 Apr 2020 12:00:26 +0000</pubDate>
      <link>https://forem.com/alexabruck/have-you-used-netlify-for-real-client-projects-2c2a</link>
      <guid>https://forem.com/alexabruck/have-you-used-netlify-for-real-client-projects-2c2a</guid>
      <description>&lt;p&gt;I read a lot of case studies of developers who use Netlify for their personal projects (blog, portfolio, experiments, ...).&lt;/p&gt;

&lt;p&gt;I've almost never heard anybody telling how they used Netlify as a hosting/CD solution for real-world client projects.&lt;/p&gt;

&lt;p&gt;I would be curious to hear about your experience using Netlify for your client projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which plan did you choose (free or professional)?&lt;/li&gt;
&lt;li&gt;How did you explain Netlify to your client? I have the impression that the decoupled nature of JAM stack websites is confusing for clients (as opposed to a monolithic Wordpress site)&lt;/li&gt;
&lt;li&gt;How was the handover? Did you make a Netlify account for your client?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please share!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>netlify</category>
      <category>hosting</category>
      <category>clients</category>
    </item>
    <item>
      <title>Understanding gatsby-image (Part 3): Controlling sizes, breakpoints and styling</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 09 Dec 2019 12:57:04 +0000</pubDate>
      <link>https://forem.com/alexabruck/understanding-gatsby-image-part-3-controlling-sizes-breakpoints-and-styling-10kf</link>
      <guid>https://forem.com/alexabruck/understanding-gatsby-image-part-3-controlling-sizes-breakpoints-and-styling-10kf</guid>
      <description>&lt;p&gt;&lt;strong&gt;This is Part 3 of a three-part series covering the Gatsby plugin gatsby-image&lt;/strong&gt;&lt;br&gt;
Part 1: &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-1-graphql-generated-files-markup-2ehd"&gt;Graphql, generated files &amp;amp; markup&lt;/a&gt;&lt;br&gt;
Part 2: &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-2-responsive-images-101-56j5"&gt;Responsive images 101&lt;/a&gt;&lt;br&gt;
Part 3: Controlling src-set, breakpoints and styling&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-1-graphql-generated-files-markup-2ehd"&gt;Part 1&lt;/a&gt; we've learned what gatsby-image is outputting, in &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-2-responsive-images-101-56j5"&gt;Part 2&lt;/a&gt; we learned the basics of responsive images in order to understand what gatsby-image is outputting. In this part we're going to learn how to tweak what gatsby-image is outputting in order to get the images that serve our use case.&lt;/p&gt;
&lt;h2&gt;
  
  
  Gatsby Image: What src-set property does it generate?
&lt;/h2&gt;

&lt;p&gt;If you’re dealing with a &lt;strong&gt;fixed image&lt;/strong&gt; it is producing a &lt;code&gt;src-set&lt;/code&gt; with a &lt;strong&gt;width-descriptor&lt;/strong&gt; appended to each source (e.g. &lt;code&gt;600w&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"srcSet": 
 "/static/1234/1111/my-image.jpg 600w, 
  /static/1234/2222/my-image.jpg 900w”
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the case of a &lt;strong&gt;fluid image&lt;/strong&gt; it is producing a &lt;code&gt;src-set&lt;/code&gt; width a &lt;strong&gt;x-descriptor&lt;/strong&gt; appended to each source (e.g. 1.5x)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"srcSet": 
 "/static/1234/1111/my-image.jpg 1x, 
  /static/1234/2222/myImage.jpg 1.5x, 
  /static/1234/3333/myImage.jpg 2x”
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Gatsby Image: What sizes property does it generate?
&lt;/h2&gt;

&lt;p&gt;This only applies to &lt;strong&gt;fluid images&lt;/strong&gt;. Fixed images don’t have a size property, because they use x-descriptors in their &lt;code&gt;srcSet&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Gatsby image just takes the &lt;code&gt;sizes&lt;/code&gt; property from what gatsby-plugin-sharp is outputting. Remember, in Part 1 we showed how the fragment &lt;code&gt;GatsbyImageSharpFluid&lt;/code&gt; includes a &lt;code&gt;size&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;If you haven’t indicated a &lt;code&gt;maxWidth&lt;/code&gt; in your graphql query it will generate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sizes="(max-width: 800px) 100vw, 800px"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you have indicated a maxWidth of 1200px, it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sizes="(max-width: 1200px) 100vw, 1200px"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see here that the &lt;code&gt;100vw&lt;/code&gt; is based on the &lt;strong&gt;assumption&lt;/strong&gt; that your image will take up the full available viewport width. It doesn’t take into account that your full-width image might be smaller because it’s living in a container with paddings and margins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting custom sizes and breakpoints
&lt;/h2&gt;

&lt;p&gt;But you can adjust that to your needs, by overriding the &lt;code&gt;sizes&lt;/code&gt; property in the object you pass to the fluid property of your gatsby image. In case your image lives in a container that has a margin of 20px on each side, you can substract 40px from the viewport width:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Img&lt;/span&gt;
  &lt;span class="na"&gt;fluid=&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;
    &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sizes:&lt;/span&gt; &lt;span class="err"&gt;"(&lt;/span&gt;&lt;span class="na"&gt;max-width:&lt;/span&gt; &lt;span class="na"&gt;1200px&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="na"&gt;calc&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;100vw&lt;/span&gt; &lt;span class="na"&gt;-&lt;/span&gt; &lt;span class="na"&gt;40px&lt;/span&gt;&lt;span class="err"&gt;),&lt;/span&gt; &lt;span class="na"&gt;1200px&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt;
  &lt;span class="err"&gt;}}&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This way you don’t load images that are much bigger than what you really need. You might also want to override the &lt;code&gt;sizes&lt;/code&gt; property to add additional breakpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sizes: "(max-width: 300px) calc(100vw - 20px), (max-width: 600px) calc(100vw - 40px), 1200px",
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Another technique for overriding &lt;code&gt;sizes&lt;/code&gt; is to include your custom sizes as a query parameter in your graphql query, like in this &lt;a href="https://medium.com/@stefanledin/custom-sizes-attribute-with-gatsby-image-by-a-gatsby-newbie-456a8f6105ea"&gt;example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;childImageSharp { 
  fluid(sizes: “(max-width: 1200px) calc(100vw - 40px), 1200px”){ 
   ...GatsbyImageSharpFluid
  } 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Controlling which image sizes are generated
&lt;/h2&gt;

&lt;p&gt;If you want more control over which image sizes are generated by gatsby-plugin-sharp you can use the &lt;code&gt;srcSetBreakpoints&lt;/code&gt; parameter in your fluid query. This could be an array like &lt;code&gt;[200, 350, 900]&lt;/code&gt;. You probably want to use this in combination with a custom &lt;code&gt;sizes&lt;/code&gt; property in the gatsby-image React component, as described above. This way you can refer to concrete numbers in your sizes property.&lt;/p&gt;

&lt;p&gt;Checkout the documentation of gatsby-plugin-sharp here: &lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-sharp#parameters-2"&gt;https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-sharp#parameters-2&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ways to style/layout the image created by gatsby-image
&lt;/h2&gt;

&lt;p&gt;We’ve covered the markup and layout that gatsby-image creates in the first Part 1 of this series.&lt;/p&gt;

&lt;p&gt;Gatsby image accepts the following properties related to styling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;style={} /* styles for the wrapper container */
imgStyle={} /* Styles for the actual img element */
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/gatsbyjs/gatsby/issues/14988"&gt;Here’s an interesting discussion&lt;/a&gt; of how to apply custom styling to a gatsby image.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;That was the 3-part series about gatsby-image. I hope it was helfpul!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>graphql</category>
      <category>responsiveimages</category>
    </item>
    <item>
      <title>Understanding gatsby-image (Part 2): Responsive images 101</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 09 Dec 2019 12:39:20 +0000</pubDate>
      <link>https://forem.com/alexabruck/understanding-gatsby-image-part-2-responsive-images-101-56j5</link>
      <guid>https://forem.com/alexabruck/understanding-gatsby-image-part-2-responsive-images-101-56j5</guid>
      <description>&lt;p&gt;&lt;strong&gt;This is Part 2 of a three-part series covering the Gatsby plugin gatsby-image&lt;/strong&gt;&lt;br&gt;
Part 1: &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-1-graphql-generated-files-markup-2ehd"&gt;Graphql, generated files &amp;amp; generated markup&lt;/a&gt;&lt;br&gt;
Part 2: Responsive images 101&lt;br&gt;
Part 3: &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-3-controlling-sizes-breakpoints-and-styling-10kf"&gt;Controlling src-set, breakpoints and styling&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post we’ll cover these things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; as child elements&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; attribute&lt;/li&gt;
&lt;li&gt;Using the browser devtools to find out which image files are really fetched by the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is providing some helpful background knowledge to use gatsby-image, but it is not specific to gatsby-image.&lt;/p&gt;
&lt;h2&gt;
  
  
  How does the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element work?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element contains zero or more &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements and one &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture"&gt;MDN&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;“The browser will consider each child source element and choose the best match among them; if no matches are found or the browser doesn’t support the picture element, the URL of the img element’s src attribute is selected. The selected image is then presented in the space occupied by the img element.”&lt;/blockquote&gt;

&lt;blockquote&gt;
“The img element serves two purposes: it describes the size and other attributes of the image and its presentation, and it provides a fallback in case none of the offered source elements are able to provide a usable image.”
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  How does &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with the &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; attribute work?
&lt;/h2&gt;

&lt;p&gt;Checkout the following image markup. The srcset and sizes properties use a distinct notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; 
 &lt;span class="na"&gt;srcset=
  &lt;/span&gt;&lt;span class="s"&gt;"my-img-280w.jpg 280w, 
   my-img-440w.jpg 440w, 
   my-img-800w.jpg 800w"&lt;/span&gt;
 &lt;span class="na"&gt;sizes=
  &lt;/span&gt;&lt;span class="s"&gt;"(max-width: 320px) 280px, 
   (max-width: 480px) 440px, 
   800px"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;"srcset defines the set of images we will allow the browser to choose between, and what size each image is." (MDN)&lt;/p&gt;

&lt;p&gt;It reads as a string with comma-separated pairs of information: The file path followed by the &lt;strong&gt;width&lt;/strong&gt; of the actual image as a number (without px) but with ‘w’ at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about the &lt;code&gt;sizes&lt;/code&gt; attribute?
&lt;/h3&gt;

&lt;p&gt;"sizes defines a set of media conditions (e.g. screen widths) and indicates what image size would be best to choose" (MDN)&lt;/p&gt;

&lt;p&gt;It reads as a string with comma-separated pairs of information: a &lt;strong&gt;media condition&lt;/strong&gt; in brackets, followed by the &lt;strong&gt;width&lt;/strong&gt; of the slot the image will fill when the media condition is true.&lt;/p&gt;

&lt;p&gt;“The last slot width has no media condition (this is the default that is chosen when none of the media conditions are true). The browser ignores everything after the first matching condition, so be careful how you order the media conditions.” (MDN)&lt;/p&gt;

&lt;h3&gt;
  
  
  Another option: &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with &lt;code&gt;srcset&lt;/code&gt; but without &lt;code&gt;sizes&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Check out this srcset attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;srcset=
 "my-img-300w.jpg 1x, 
  my-img-450w.jpg 1.5x, 
  my-img-600w.jpg 3x"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Instead of providing a width, we’re providing a so called &lt;strong&gt;x-descriptor&lt;/strong&gt; that informs the browser to check the &lt;strong&gt;device pixel ratio&lt;/strong&gt; (DPR) of the client’s monitor, and choose the right image.&lt;/p&gt;

&lt;p&gt;This is useful for optimization for retina displays.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should I use &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; and when &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; &amp;amp; &lt;code&gt;sourceset&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;On first sight both ways seem to provide a solution for the same problem: Offering a choice of image files to let the browser choose from. The main guideline is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Use &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; for art direction and image-format-switching.&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;2. Use &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; &amp;amp; &lt;code&gt;sourceset&lt;/code&gt; for resolution-switching.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're wondering: "Art direction…? But I'm not an art director!" -  Read this definition of art direction within the domain of web development:&lt;/p&gt;


&lt;blockquote&gt;Art direction: The problem whereby you want to serve cropped images for different layouts — for example a landscape image showing a full scene for a desktop layout, and a portrait image showing the main subject zoomed in for a mobile layout.&lt;/blockquote&gt; &lt;small&gt;(&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images"&gt;MDN&lt;/a&gt;)&lt;/small&gt;

&lt;p&gt;What is meant by image-format-switching? Let's say we want to serve our images as the fast newer image format &lt;em&gt;webp&lt;/em&gt; to our readers. But this format isn't supported yet by all browsers, so we have to provide a jpg image as a fallback. In this case we would use a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element with two &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements: One for the webp and one for the jpg.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing: How to check which images are REALLY requested by the browser?
&lt;/h2&gt;

&lt;p&gt;⚠️ Attention: It is not what you see inside the &lt;code&gt;src&lt;/code&gt; of the &lt;code&gt;&amp;lt;img &amp;gt;&lt;/code&gt; tag (but it can be)! Even more confusing: It doesn’t even have to be one from the &lt;code&gt;srcSet&lt;/code&gt; array of the &lt;code&gt;img&lt;/code&gt; element (but it can be)!&lt;/p&gt;

&lt;p&gt;Two options to find out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open your browser’s developer tools &lt;strong&gt;Network&lt;/strong&gt; Panel and checkout which file was fetched over the network&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open your browser’s developer tools “Inspector” or “Elements” panel: Select the img element and type into the Browser console: &lt;code&gt;$0.currentSrc&lt;/code&gt; (&lt;code&gt;$0&lt;/code&gt; stands for the currently selected element)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;Continue with &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-3-controlling-sizes-breakpoints-and-styling-10kf"&gt;Part 3&lt;/a&gt; of this series about gatsby-image: “Controlling sizes, breakpoints and styling”&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>responsivewebdesign</category>
      <category>retina</category>
      <category>gatsby</category>
    </item>
    <item>
      <title>Understanding gatsby-image (Part 1): graphql, generated files &amp; markup</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 09 Dec 2019 12:18:45 +0000</pubDate>
      <link>https://forem.com/alexabruck/understanding-gatsby-image-part-1-graphql-generated-files-markup-2ehd</link>
      <guid>https://forem.com/alexabruck/understanding-gatsby-image-part-1-graphql-generated-files-markup-2ehd</guid>
      <description>&lt;p&gt;&lt;strong&gt;This is Part 1 of a three-part series covering the Gatsby plugin gatsby-image:&lt;/strong&gt;&lt;br&gt;
Part 1: Graphql, generated files &amp;amp; markup&lt;br&gt;
Part 2: &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-2-responsive-images-101-56j5"&gt;Responsive images 101&lt;/a&gt;&lt;br&gt;
Part 3: &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-3-controlling-sizes-breakpoints-and-styling-10kf"&gt;Controlling src-set, breakpoints and styling&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disclaimer: This is for the reader who has used gatsby-image before &amp;amp; understands what it is capable of, but needs a more in-depth understanding in order to control it better. (Written in 12/2019 &amp;amp; based on gatsby 2.18.x, gatsby-image 2.2.x, gatsby-transformer-sharp 2.3.x and gatsby-plugin-sharp 2.3.x)&lt;/p&gt;

&lt;p&gt;On first sight, the Gatsby plugin gatsby-image is a jack of all trades plugin. But gatsby-image is essentially just a node module that exports a React component, and it works hand-in-hand with 2 other plugins: gatsby-plugin-sharp and gatsby-transformer-sharp, which do the heavy lifting on the server/build side.&lt;/p&gt;

&lt;p&gt;Used together they can achieve the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating a bunch of image files into your /public/static folder based on an input image file and a graphql query that describes what kind of images you want (gatsby-plugin-sharp)&lt;/li&gt;
&lt;li&gt;Produce markup and css to take care of the appearance of these images on the page (full width, cover/contain, etc.) (gatsby-image)&lt;/li&gt;
&lt;li&gt;Getting a smooth appearance of a newly loaded image, e.g. by first showing a blurred base-64 image and replacing it with a full-resolution one, once it is loaded. This is known as the "blur up" technique popularized by Medium and Facebook (gatsby-image)&lt;/li&gt;
&lt;li&gt;Prevent image jumping, when the image loads due to the exact image size not known before loading(gatsby-image)&lt;/li&gt;
&lt;li&gt;Give you lazyloading by using IntersectionObserver in the browser (gatsby-image)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: You could probably use gatsby-image's image generating capacities exclusively, without using the gatsby-image component (and the quite opinionated markup), by writing your own markup. To do this you would have to query the appropriate fields that would be needed to satisfy a native &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element, or your custom markup with &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fluid vs. Fixed
&lt;/h2&gt;

&lt;p&gt;Before you work with gatsby-image you have to make a binary decision about the type of image you are working with: Is it fixed or fluid?&lt;br&gt;
From the &lt;a href="https://www.gatsbyjs.org/packages/gatsby-image/"&gt;Gatsby Docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;"To decide between the two, ask yourself: "do I know the exact size this image will be?" If yes, it's the first type [Fixed]. If no and its width and/or height need to vary depending on the size of the screen, then it's the second type. [FLUID]"&lt;/blockquote&gt;

&lt;p&gt;The result of your fixed or fluid graphql query is then passed respectively to the fixed or fluid property of your gatsby-image component. The markup that gatsby-image outputs will differ if it's a fluid or a fixed image.&lt;/p&gt;
&lt;h2&gt;
  
  
  The graphql query
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Fixed
&lt;/h3&gt;

&lt;p&gt;A query for a fixed image could look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;imageSharp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&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;GatsbyImageSharpFixed&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;Here, &lt;code&gt;GatsbyImageSharpFixed&lt;/code&gt; is a &lt;strong&gt;fragment&lt;/strong&gt;. It is equivalent to this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;imageSharp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;base64&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;
      &lt;span class="nx"&gt;src&lt;/span&gt;
      &lt;span class="nx"&gt;srcSet&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Fluid
&lt;/h3&gt;

&lt;p&gt;The following is a query for a fluid image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;imageSharp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fluid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&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;GatsbyImageSharpFluid&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is equivalent to this query (without using a fragment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;imageSharp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fluid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;base64&lt;/span&gt;
       &lt;span class="nx"&gt;aspectRatio&lt;/span&gt;
       &lt;span class="nx"&gt;src&lt;/span&gt;
       &lt;span class="nx"&gt;srcSet&lt;/span&gt;
       &lt;span class="nx"&gt;sizes&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;(Note the additional "sizes" parameter in the fluid query above)&lt;br&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/blob/b8b2b05fe56ceee651ff368b83475517208b548f/packages/gatsby-transformer-sharp/src/fragments.js#L34-L42"&gt;Here's the source code&lt;/a&gt; of these fragments, so you know what they contain.&lt;/p&gt;

&lt;h2&gt;
  
  
  The generated image files
&lt;/h2&gt;

&lt;p&gt;With your graphql query you decide which images are being generated: the dimensions and the formats (jpg/png, webp, base64). The images will be saved into your &lt;code&gt;/public/static&lt;/code&gt; folder. Each image will get its own folder, and each image version will get its own folder within this folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixed
&lt;/h3&gt;

&lt;p&gt;In the case of a fixed query, it will generate images that have the width/height you specified in your graphql query PLUS it will try to generate higher resolution images for retina displays: 150% and 200% of the size you specified (but only if the source image actually has that many pixels available).&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluid
&lt;/h3&gt;

&lt;p&gt;If you haven't indicated a maxWidth in your graphql query it will generate images with the widths of 800px, 400px and 200px (in case your original image isn't smaller than 800px width). If you do have indicated a maxWidth (example), then it will generate images with 100% , 50% and 25% maxWidth.&lt;/p&gt;

&lt;p&gt;If the indicated maxWidth exceeds the width of the original image, it will still try to produce 50% and 25% width images (as long as these don't exceed the original image width), but the maximum size will be the original image. If the indicated maxWidth is smaller than the width of the original image, it will also generate images bigger than the indicated maxWidth, namely 150% and 200%, this is to satisfy retina displays.&lt;/p&gt;

&lt;p&gt;If you want more control over which sizes are generated, check out Part 3 of this series.&lt;/p&gt;

&lt;p&gt;👀 &lt;strong&gt;TIP&lt;/strong&gt;: If you're using VS Code you can see the dimensions of images in your workspace at the lower bar on the right side.&lt;/p&gt;

&lt;h2&gt;
  
  
  The generated markup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fixed
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4b-50gW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2rpniv73how0nlid0qpk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4b-50gW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2rpniv73how0nlid0qpk.jpg" alt="A peak into the generated markup with Firefox devtools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A relatively positioned wrapper &lt;code&gt;&amp;lt;div class="gatsby-image-wrapper"&amp;gt;&lt;/code&gt; that has the proportions of the image it contains (see width and height). Inside this wrapper we see a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element that contains several &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements and one &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element. The &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element is positioned absolutely and takes up the whole width and height of its parent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluid
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fVt5pfNq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zhg4ck2h23ooqy86fht6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fVt5pfNq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zhg4ck2h23ooqy86fht6.jpg" alt="A peak into the generated markup with Firefox devtools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This looks similar to the fixed one, except that &lt;code&gt;&amp;lt;div class="gatsby-image-wrapper"&amp;gt;&lt;/code&gt; doesn't have a defined width or height anymore. Instead, we have an additional child element, an empty &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; that has a procentual padding-bottom. This percentual padding happens to be the exact aspect ratio of the image it contains. Thanks to this, the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element can be positioned absolutely again and take up the whole width and height of its parent.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Continue with &lt;a href="https://dev.to/alexabruck/understanding-gatsby-image-part-2-responsive-images-101-56j5"&gt;Part 2&lt;/a&gt; of this series about gatsby-image: "Responsive images 101"&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>staticsitegenerators</category>
      <category>graphql</category>
      <category>responsiveweb</category>
    </item>
    <item>
      <title>Debugging a live site by replacing remote files with local ones</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Fri, 17 May 2019 16:49:13 +0000</pubDate>
      <link>https://forem.com/alexabruck/tricks-for-debugging-a-live-site-58ck</link>
      <guid>https://forem.com/alexabruck/tricks-for-debugging-a-live-site-58ck</guid>
      <description>&lt;p&gt;At one point in your web developer life you might come across the following scenario:&lt;/p&gt;

&lt;p&gt;Your site is live and you need to fix a problem in a Javascript file. &lt;br&gt;
For some reason you can't set up and run the whole project locally. Or maybe what you want is to run the Javascript in a production environment against a live database.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can you do?
&lt;/h2&gt;

&lt;p&gt;I recently discovered a browser extension named &lt;a href="//app.requestly.io"&gt;Requestly&lt;/a&gt; (available for Firefox and Chrome). It allows you to intercept and redirect network requests of your browser and replace the requested remote assets (like a JS File) with assets served from your own machine's localhost or any other remote server.&lt;/p&gt;

&lt;p&gt;Remember, that's only for debugging and testing on the browser side, it will not actually change the original files on the server!&lt;/p&gt;

&lt;p&gt;Let's exercise this scenario with some random website. I will use the website of Hackernews &lt;a href="https://news.ycombinator.com/"&gt;https://news.ycombinator.com/&lt;/a&gt;. As a proof of concept I just want to add an alert in their script saying "Hello world".&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Downloading the original file
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0u0c60119799tbtdgpw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0u0c60119799tbtdgpw.jpg" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Firefox what I do is opening the Devtools, go to the network panel, filter for JS resources only, right-click on the relevant JS file, choose "Open in new tab", and then download the file from there. &lt;/p&gt;

&lt;p&gt;In the case of our example (Hacker News) the file we want to replace is named &lt;code&gt;hn.js&lt;/code&gt; followed by a query string including a hash &lt;code&gt;?2c3QnShZ2ErBfQjZ9gFC&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Editing the file
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4p3jgfuzjm2hywpq2spc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4p3jgfuzjm2hywpq2spc.jpg" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's do some changes to the downloaded file with our favorite code editor. Let's just add one line of code right at the beginning of the file. Obviously in reality you would do your foxy debugging magic here!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Serving the file
&lt;/h2&gt;

&lt;p&gt;When you tell Requestly to set up a redirect, the destination has to be a URL. A file from within your file system will not work. I use the super handy &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer"&gt;Live Server&lt;/a&gt; plugin for VS Code to serve my local files straight from my IDE in a matter of a click. Here we go, my edited JS file is served by localhost under: &lt;a href="http://localhost:5500/hn.js"&gt;http://localhost:5500/hn.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Configuring the redirect with Requestly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fekybu7vccx3rlvlfuq79.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fekybu7vccx3rlvlfuq79.jpg" width="800" height="324"&gt;&lt;/a&gt;&lt;br&gt;
When you have the Requestly browser extension installed, click on it in the browser toolbar, then choose "Open app". Select "New Rule", then the "Redirect Request" option from the menu.&lt;br&gt;
Enter the URL of the file you want to replace (Request Url) and the URL of your replacement file (Destination Url). If the original Url contains a (versioning) hash you might want to select "contains" instead of "equals".&lt;/p&gt;

&lt;p&gt;Now refresh the Hacker News site in the browser. Do we see the "Hello world" alert? Nope. But why? When we open the browser console we see a hint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggie0rcrnmo6it91g1gz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggie0rcrnmo6it91g1gz.jpg" width="800" height="48"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Understanding Content Security Policy (CSP)
&lt;/h2&gt;

&lt;p&gt;Let's look at this console error more closely: &lt;br&gt;
&lt;code&gt;Content Security Policy: The page’s settings blocked the loading of a resource at http://localhost:5500/hn.js (“script-src”).&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The message refers to a HTTP header named Content Security Policy (CSP) which is attached to the HTTP response of the original site. The exact content of the header can be examined again with the browser Devtools: Go to the Network tab again, filter by HTML, click on the file, this will show the details to the right. Select the tab "Headers".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wyi6s7cms32hjr99ahe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wyi6s7cms32hjr99ahe.jpg" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what's in it:&lt;br&gt;
&lt;code&gt;Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://cdnjs.cloudflare.com/; frame-src 'self' https://www.google.com/recaptcha/; style-src 'self' 'unsafe-inline'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The interesting part of this CSP string is the part that is following  the keyword/directive &lt;code&gt;script-src&lt;/code&gt;. It translates to: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;This site is allowed to execute scripts from resources that are hosted on the same domain (&lt;code&gt;'self'&lt;/code&gt;), or embedded as inline scripts (&lt;code&gt;'unsafe-inline'&lt;/code&gt;). Furthermore the site will accept scripts from a few selected external providers (Google, Gstatic, Cloudfare).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Obviously, our localhost is not invited by this policy! That's why the request could not be redirected to localhost. Luckily we can also change that by telling Requestly to modify the HTTP headers of the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Modify the CSP HTTP header to include localhost
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ho183hb808g48bz085e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ho183hb808g48bz085e.jpg" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new Requestly rule. This rule should be of the type "Modify Headers". Then, inside the form enter "Content-Security-Policy" (without quotes) in the "Header" input field. In the "Value" input field enter the original CSP header of the site and finally add localhost after the script-src directive. At the input field for Request Url enter the URL of the site you want to change (in our example the site of Hacker News).&lt;br&gt;
Select "Response", because we want to change the Reponse HTTP Headers.&lt;/p&gt;

&lt;p&gt;The updated CSP header for our example would be: &lt;br&gt;
&lt;code&gt;default-src 'self'; script-src 'self' 'unsafe-inline' http://localhost:5500 https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://cdnjs.cloudflare.com/; frame-src 'self' https://www.google.com/recaptcha/; style-src 'self' 'unsafe-inline'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;(Note that the existing CSP HTTP header of your site might be different. Use the one of your site!)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;A word of caution&lt;/strong&gt; ⚠️ &lt;br&gt;
Be aware that tinkering with HTTP security headers can be dangerous if you don't know what you're doing. Modifying the CSP header by adding localhost to your trusted hosts is of relatively low risk (because localhost === you). But disabling the CSP header altogether for a site could expose you to a security risk. By entering the wrong parameters (like a wildcard * for the URL pattern) you could easily disable important security mechanisms for all sites you visit. So be very, very careful!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: HTTP + HTTPS = Mixed Content
&lt;/h2&gt;

&lt;p&gt;This is the last hurdle finally. If the website is served over HTTPS, but your replacement file is served over HTTP, you have a situation called "Mixed Content". Most browsers are blocking mixed content to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content"&gt;keep you safe&lt;/a&gt;. In this case you will see an error like this in the console: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Blocked loading mixed active content http://localhost:5500/hn.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To solve this you have 2 options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://medium.freecodecamp.org/how-to-get-https-working-on-your-local-development-environment-in-5-minutes-7af615770eec"&gt;Serving&lt;/a&gt; your replacement file over HTTPS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.mozilla.org/en-US/kb/mixed-content-blocking-firefox"&gt;Telling&lt;/a&gt; your browser to (temporarily) unblock mixed content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used the second option for this demo (note the lock icon with the red line in the address bar). And voila we see the alert!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66ge4u3bn5b3azvvannk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66ge4u3bn5b3azvvannk.jpg" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota bene&lt;/strong&gt;&lt;br&gt;
Don't forget to deactivate your Requestly rules once you're done! Speaking from experience! You will forget that you set up this redirect and wonder why things are behaving so strangely. That's because there is no visual hint on the site to remind you that you have tampered with it (unless you're checking the network panel)!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy (live) debugging!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>devtools</category>
      <category>http</category>
      <category>csp</category>
    </item>
    <item>
      <title>Boilerplate/Starterkit for framework-less Frontend projects</title>
      <dc:creator>Alexa Steinbrück</dc:creator>
      <pubDate>Mon, 01 Apr 2019 11:06:37 +0000</pubDate>
      <link>https://forem.com/alexabruck/boilerplate-starterkit-for-framework-less-frontend-projects-1bbb</link>
      <guid>https://forem.com/alexabruck/boilerplate-starterkit-for-framework-less-frontend-projects-1bbb</guid>
      <description>&lt;p&gt;Hello lovely community!&lt;br&gt;
Do you know about any boilerplate tools ("starter kits", "bootstrap tools") for kickstarting simple Frontend projects that don't require a JS-framework? Basically like create-react-app, but for vanilla javascript. My main motivation is to cut down on set-up time and to become productive immediately.&lt;/p&gt;

&lt;p&gt;It should also provide support for: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transpiling (Babel)&lt;/li&gt;
&lt;li&gt;SASS&lt;/li&gt;
&lt;li&gt;Module bundling&lt;/li&gt;
&lt;li&gt;Linting&lt;/li&gt;
&lt;li&gt;Minification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was searching on Github, but couldn't really find any repositories matching my need. Maybe the framework-less approach is slowly becoming extinct?! Anyway, I am thankful for your ideas!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tools</category>
      <category>frontend</category>
      <category>boilerplate</category>
    </item>
  </channel>
</rss>
