<?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: Amber Wilkie</title>
    <description>The latest articles on DEV Community by Amber Wilkie (@amberwilkie).</description>
    <link>https://dev.to/amberwilkie</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%2F157848%2F5980eb34-2251-423b-bca7-7151f891286c.jpeg</url>
      <title>DEV Community: Amber Wilkie</title>
      <link>https://dev.to/amberwilkie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amberwilkie"/>
    <language>en</language>
    <item>
      <title>How to set up a brand new Macbook, for programmers</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Tue, 06 Aug 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/amberwilkie/how-to-set-up-a-brand-new-macbook-for-programmers-51d5</link>
      <guid>https://dev.to/amberwilkie/how-to-set-up-a-brand-new-macbook-for-programmers-51d5</guid>
      <description>&lt;p&gt;I started a new job on Monday (it's going awesome, thanks for asking) and that means a brand new, blank-slate Macbook Pro. Fortunately, I still have my old work computer (my last job maybe wasn't so wonderful, as I had to bring my own every day...). But next time, I'll probably have to turn my new work computer in, so I wanted to create a record of my setup.  Maybe it's helpful for others too!  By the way, almost all of these programs are F-R-E-E.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Terminal
&lt;/h1&gt;

&lt;p&gt;It's absolutely essential to get your terminal set up so you can work efficiently. If you are running the default terminal with no adjustments, these tips could save you a &lt;em&gt;lot&lt;/em&gt; of time and frustration.&lt;/p&gt;

&lt;h2&gt;
  
  
  iTerm2
&lt;/h2&gt;

&lt;p&gt;Go on and download &lt;a href="https://iterm2.com/"&gt;iTerm2&lt;/a&gt; and then be very pleased with all the features. My favorites are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll (arrow keys) up and down to move through commands. Type partial commands to filter, then scroll.&lt;/li&gt;
&lt;li&gt;Auto-copy - just highlight text in iTerm and it will automatically be copied to the clipboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  oh my zsh
&lt;/h2&gt;

&lt;p&gt;If you, like me, want to make your terminal work for you, get &lt;a href="https://github.com/robbyrussell/oh-my-zsh"&gt;oh my zsh&lt;/a&gt;. Here's what my terminal prompt looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R2gYpcX8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wilkie.tech/static/16ec1dc80035c62daf8b7aa49401875d/ffa66/iterm-demo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R2gYpcX8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wilkie.tech/static/16ec1dc80035c62daf8b7aa49401875d/ffa66/iterm-demo.png" alt="oh-my-zsh config demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I have uncommitted changes, I get a yellow x to the left of my cursor. It's really handy for recognizing that I have changes hanging out.&lt;/p&gt;

&lt;p&gt;You can do lots of things with oh my zsh - there's a library of different ways you can style your terminal. I use theme "robbyrussel". Note that you will also want to use &lt;code&gt;.zshrc&lt;/code&gt; instead of &lt;code&gt;.bashrc&lt;/code&gt; for aliases and other modifications to terminal settings.&lt;/p&gt;

&lt;p&gt;While we're here, let's give a huge shout to terminal aliases. I love the "insider" language I have with my terminal. Here are a few I put into &lt;code&gt;.zshrc&lt;/code&gt;. I don't need all of them anymore, but I left them here to show some of the ridiculously long commands that can be aliased to something very short.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias j-u='jest --updateSnapshot'
alias ytu='yarn test-update'
alias dcu='docker-compose up'
alias dcd='docker-compose down'
alias lint-front='docker-compose exec front yarn gulp lint'
alias back-bash='docker-compose exec back bash'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  .gitconfig
&lt;/h2&gt;

&lt;p&gt;You probably have a &lt;code&gt;.gitconfig&lt;/code&gt; on your computer, but you may not be using git aliases to save yourself some keystrokes. Here's mine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This is Git's per-user configuration file.
[user]
    name = amberwilkie
    email = amber@amberwilkie.com
[alias]
    co = checkout
    st = status
    ci = commit
    lp = log --oneline
    poh = push origin head
    rc = rebase --continue
    prom = pull --rebase origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Under that &lt;code&gt;[alias]&lt;/code&gt; header, you can put whatever you want, including complicated git commands particular to your organization. It's super-handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  .gitignore_global
&lt;/h2&gt;

&lt;p&gt;Did you know you can automatically ignore files in &lt;em&gt;every git repo&lt;/em&gt; on your computer? Put them in &lt;code&gt;.gitignore_global&lt;/code&gt; and never have to fuss with &lt;code&gt;.DS_Store&lt;/code&gt; in your &lt;code&gt;.gitignore&lt;/code&gt; again. I put &lt;code&gt;.idea&lt;/code&gt; in mine as well, since my editor of choice generates profiles in every repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Github SSH keys
&lt;/h2&gt;

&lt;p&gt;New computer, new SSH keys. Follow the &lt;a href="https://help.github.com/en/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent"&gt;Github instructions&lt;/a&gt; so you don't have to type in your credentials ever again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trash
&lt;/h2&gt;

&lt;p&gt;Have you ever felt that &lt;code&gt;rm -rf folder&lt;/code&gt; was a little too final? With this simple &lt;a href="https://github.com/sindresorhus/trash"&gt;Trash npm package&lt;/a&gt;, you can call &lt;code&gt;trash file/folder&lt;/code&gt; to literally move it to your computer's trash instead of deleting it from memory. It can be recalled, or otherwise managed. This has saved me plenty of times.&lt;/p&gt;

&lt;p&gt;Pro tip: Always run &lt;code&gt;rm -rf node_modules&lt;/code&gt; instead of &lt;code&gt;trash node_modules&lt;/code&gt; (you 100% never need to recall your old &lt;code&gt;node_modules&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Homebrew &amp;amp; Cask
&lt;/h2&gt;

&lt;p&gt;If you have a mac, you already know you need &lt;a href="https://brew.sh/"&gt;Homebrew&lt;/a&gt; and &lt;a href="https://github.com/Homebrew/homebrew-cask"&gt;Cask&lt;/a&gt;. The first to install packages, the next for applications distributed in binary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;/usr/bin/ruby &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/master/install&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;cask
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Programs
&lt;/h1&gt;

&lt;p&gt;My editor of choice is Webstorm, though I'm trying to create a workflow with VS Code at the moment. I'll skip all the editor-related stuff, since it's covered so well in my many other places. Here's the rest of what I install on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  TimeOut
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.dejal.com/timeout/"&gt;TimeOut&lt;/a&gt; blocks your screen at intervals, forcing you to take a break. I keep mine at 2 minutes every hour and 15 seconds every 15 minutes. It can get annoying, but it's good for my health. We know sitting for extended periods of time is bad for us, but it's far too easy to let four hours go while we just fix this liiiiittttlllllle thing. Conveniently, my break popped up while I was writing this paragraph. (Normally the image and timer are aligned, not sure what is up with that.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rat2LOBD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wilkie.tech/static/d0dd90cf13ce5e6160e0d330861a2693/6cb7a/timeout.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rat2LOBD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wilkie.tech/static/d0dd90cf13ce5e6160e0d330861a2693/6cb7a/timeout.png" alt="timeout break generator demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can set the image to be whatever you want and can add text.&lt;/p&gt;

&lt;h2&gt;
  
  
  gitx
&lt;/h2&gt;

&lt;p&gt;I would love to install &lt;a href="http://gitx.frim.nl/"&gt;gitx&lt;/a&gt; because I was using it extensively on my old computer. Unfortunately, it's no longer maintained! I have been experimenting with other git UIs but none of them are meeting my needs yet. More investigation is needed. If you have an older version of Mac, you might be able to get your hands on this original, extremely useful, tool. And if you can write natively, consider contributing!&lt;br&gt;
GitX is extremely useful for quickly reviewing changes in your current commit and editing those changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alfred
&lt;/h2&gt;

&lt;p&gt;I always install Alfred, though I honestly have not yet taken the time to fall in love. I am aware that there are a thousand features that developers use every day. It's on my productivity improvements list to figure out! I'm likely to buy the power pack so that I can access the improved clipboard, which looks awesome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7XUJOD4C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.alfredapp.com/help/features/clipboard/clipboard-viewer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7XUJOD4C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.alfredapp.com/help/features/clipboard/clipboard-viewer.png" alt="Alfred clipboard"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I was using &lt;a href="https://github.com/Clipy/Clipy"&gt;Clipy&lt;/a&gt; before, but the visual preview of what you are going to paste seems incredibly helpful.&lt;/p&gt;

&lt;p&gt;But whatever you do, get a damn clipboard extension! Having only one clipboard slot is impossible. How many times have you had to go back and forth between things copying and pasting? Having a better clipboard manager significantly improved my efficiency as a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spectacle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.spectacleapp.com/"&gt;This program&lt;/a&gt; allows you to snap windows to various parts of the screen. My new workplace has provided me with a baller 4k monitor, but that thing is so damn huge, when I plug it in, my windows are floating in a sea of desktop. Spectacle allows me to snap them where they belong with keyboard shortcuts. Magic!&lt;/p&gt;

&lt;h2&gt;
  
  
  Giphy Capture
&lt;/h2&gt;

&lt;p&gt;This may sound silly, but as a web developer who works on the front end (sometimes), I find myself needing to make short gifs to explain functionality constantly. &lt;a href="https://giphy.com/apps/giphycapture"&gt;Giphy Capture&lt;/a&gt; is the best tool I've found for this - it's intuitive and does everything you need it to do.&lt;/p&gt;

&lt;p&gt;And that is everything I consider core for getting to work as a web developer on a Mac! Naturally, a thousand other programs follow, as dictated by need, but these are the settings and programs I find indispensable in getting started. If you have any tips on other productivity tools that might useful, I'd love to hear.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post originally appeared on &lt;a href="https://wilkie.tech"&gt;wilkie.tech&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hide the new Twitter sidebar: a simple, locally-hosted Chrome extension</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Thu, 25 Jul 2019 18:51:23 +0000</pubDate>
      <link>https://dev.to/amberwilkie/hide-the-new-twitter-sidebar-a-simple-locally-hosted-chrome-extension-f7</link>
      <guid>https://dev.to/amberwilkie/hide-the-new-twitter-sidebar-a-simple-locally-hosted-chrome-extension-f7</guid>
      <description>&lt;p&gt;After seeing folks complain about the new Twitter design for days, I finally got it. Indeed, the meat of the page seems to be lost. After realizing I could quickly get rid of the right side-bar by simply hiding it, I decided to write a Chrome extension so I wouldn't have to go in and do that again.&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%2F203pst8veealo3kgan2t.png" 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%2F203pst8veealo3kgan2t.png" alt="the new Twitter, before changes" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install this guy, head to &lt;a href="https://github.com/AmberWilkie/make-new-twitter-suck-less" rel="noopener noreferrer"&gt;the github repo&lt;/a&gt; and follow the README instructions. If you've never played around with Chrome extensions, this is a great intro - an incredibly simple extension that adjusts the CSS on one page. Extensions are really neat, and there's a world of things you can make with them.&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%2F2zxebyhltt5bbha4zhqb.png" 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%2F2zxebyhltt5bbha4zhqb.png" alt="the new Twitter, after removing the sidebar" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The extension will run locally on your machine. If at any time you want to see the side bar again, just turn off the extension (at &lt;code&gt;chrome://extensions&lt;/code&gt;) or click the little icon for the extension and remove its permissions.&lt;/p&gt;

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

</description>
      <category>hacking</category>
      <category>twitter</category>
      <category>css</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Tell me about your experiences with tech recruiters</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Mon, 10 Jun 2019 17:47:05 +0000</pubDate>
      <link>https://dev.to/amberwilkie/tell-me-about-your-experiences-with-tech-recruiters-3ai1</link>
      <guid>https://dev.to/amberwilkie/tell-me-about-your-experiences-with-tech-recruiters-3ai1</guid>
      <description>&lt;p&gt;I'm mid-career, which means I've already been through one round of job-hunting where I got "help" from recruiters. On the one hand, having someone write you about job opportunities is awesome. On the other, they can be very unprofessional, and I get the feeling that there are a class of recruiter jobs and another entire pile of jobs that recruiters don't have access to. And I wonder if that second pile is where all the "good" jobs are.&lt;/p&gt;

&lt;p&gt;What has been your experience? Did you work with a recruiter at your current role? Do you recommend or advise against letting a / many recruiters steer your job hunt?&lt;/p&gt;

</description>
      <category>career</category>
      <category>jobs</category>
      <category>recruiters</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to create a searchable log with Gatsby</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Thu, 16 May 2019 17:23:45 +0000</pubDate>
      <link>https://dev.to/amberwilkie/how-to-create-a-searchable-log-with-gatsby-328b</link>
      <guid>https://dev.to/amberwilkie/how-to-create-a-searchable-log-with-gatsby-328b</guid>
      <description>&lt;h4&gt;
  
  
  For all your developer note-taking needs
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DzKpy9YY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AjxvEoOYeWq64HVZAVNoI7g.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DzKpy9YY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AjxvEoOYeWq64HVZAVNoI7g.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Taking notes is key to remembering most things in our lives. How many times have you worked on a project, then three months later needed to get back in the code, and it took you hours to come back up to speed? If you had taken a few minutes to jot down some documentation, you could have cut to the chase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UKbDo5Df--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AIUCezy45wgJJY9YyGTghdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UKbDo5Df--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AIUCezy45wgJJY9YyGTghdg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Personally, I keep my notes all over the place — in notebooks, mostly, but also right here on this blog. Many times when I finish a large, difficult feature, I like to blog key elements of it so I can come back later and figure out how I did what I did. Plus, it might help someone else along the way. However, there are tons of things I learn every day that just slip away. I keep learning and re-learning them and that’s inefficient.&lt;/p&gt;

&lt;p&gt;I recently wanted a way to quickly jot down things I learn throughout the day, or lessons I want to keep in mind. But that’s not enough — I also need to be able to &lt;em&gt;search&lt;/em&gt; these logs so I can find exactly what I’m looking for right away. That’s exactly what I’m going to show you how to build today. This project, front-to-back, took me maybe an hour and a half.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gatsby
&lt;/h3&gt;

&lt;p&gt;This project is built using &lt;a href="https://www.gatsbyjs.org"&gt;Gatsby&lt;/a&gt;, the wildly popular front-end framework for creating static websites. I’m going to skip all the sales pitch stuff and just jump into the code, but if you want to back up a step, I wrote a &lt;a href="https://medium.freecodecamp.org/how-to-leverage-your-react-skills-with-static-site-generator-gatsby-js-81843e928606"&gt;long blog post about why I love Gatsby so much&lt;/a&gt;. In short: it’s awesome if you know React, and probably worth learning anyway if you need a static site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a new Gatsby site using the beautiful “Julia” template
&lt;/h3&gt;

&lt;p&gt;Assuming you’ve got the Gatsby CLI working, run this to pull the pared-down but beautifully laid-out &lt;a href="https://github.com/niklasmtj/gatsby-starter-julia"&gt;Julia template&lt;/a&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gatsby new &amp;lt;site-name&amp;gt; https://github.com/niklasmtj/gatsby-starter-julia
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pop open the gatsby-config.js and swap out your details for “Julia Doe” under siteMeta. You’re halfway there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add logging
&lt;/h3&gt;

&lt;p&gt;Now we want to add some functionality to the site. In the content directory, add a markdown file or twenty. Nest them however you like. You’ll follow this format:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: "Whatever title you want"
date: "2019-05-010"
draft: false
path: "/logs/some-slug-for-the-file"
tags: testing, documentation
---

_# Monday, May 6, 2019_  
\* Added documentation ....
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that path needs to be unique for each file. I named mine by date (with each week getting one file) but obviously you can do anything you like.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2A: follow the Gatsby documentation for creating pages from Markdown
&lt;/h4&gt;

&lt;p&gt;I could reiterate, but the &lt;a href="https://www.gatsbyjs.org/docs/adding-markdown-pages/"&gt;Gatsby documentation itself&lt;/a&gt; is incredibly straightforward and easy to follow. You’ll install the required plugins, configure them in gatsby-config.js, create a template for how your posts should look, and set up gatsby-node.js to build pages from your markdown files.&lt;/p&gt;

&lt;p&gt;To steal a tip from somewhere else on the internet: if you head to a localhost page you know doesn’t take you anywhere (I prefer localhost:8000/garbage), you can see all the available links for your page. It’s a quick way to check Gatsby has created all your markdown pages appropriately.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yd0yIsJm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ANxvJemAEOQDj_3pWWYFeCQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yd0yIsJm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ANxvJemAEOQDj_3pWWYFeCQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Keep it clean
&lt;/h4&gt;

&lt;p&gt;I learned working on this project that you can assign multiple folders to get scanned by Gatsby’s file system plugin:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  resolve: `gatsby-source-filesystem`,
  options: {
    name: `images`,
    path: `${__dirname}/src/images`,
  },
},
{
  resolve: `gatsby-source-filesystem`,
  options: {
    name: `markdown-pages`,
    path: `${__dirname}/src/content`,
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So no problem if you are already using gatsby-source-filesystem to read, for instance, your image files. I also tested nesting, and Gatsby will grab anything in your content folder recursively — so you can go ahead and organize any way you like.&lt;/p&gt;

&lt;p&gt;Good times! If you took that diversion to the Gatsby docs, you should now have a fully-functioning log system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add search
&lt;/h3&gt;

&lt;p&gt;Now the fun part. We’ll add the ability to search our logs using the &lt;a href="https://github.com/gatsby-contrib/gatsby-plugin-elasticlunr-search"&gt;Gatsby lunr elastic search plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configure
&lt;/h4&gt;

&lt;p&gt;First, yarn add @gatsby-contrib/gatsby-plugin-elasticlunr-search, then we’ll add to gatsby-config.js:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  resolve: `@gatsby-contrib/gatsby-plugin-elasticlunr-search`,
  options: {
    // Fields to index
    fields: [`title`, `tags`, `html`],
    resolvers: {
      MarkdownRemark: {
        title: node =&amp;gt; node.frontmatter.title,
        tags: node =&amp;gt; node.frontmatter.tags,
        path: node =&amp;gt; node.frontmatter.path,
**html: node =&amp;gt; node.internal.content,**
      },
    },
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that I’ve added a field not included on the lunr docs: html. We’ll need this for full text search of the logs, rather than just searching by tags.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add a search bar
&lt;/h4&gt;

&lt;p&gt;Obviously yours can go anywhere. I put mine right on the index under my name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The search bar component:&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { graphql, StaticQuery } from "gatsby"
import Search from "./search"

export default () =&amp;gt; {
  return (
    &amp;lt;StaticQuery
      query={graphql`
          query SearchIndexQuery {
            siteSearchIndex {
              index
            }
          }
        `}
      render={data =&amp;gt; (
        &amp;lt;Search searchIndex={data.siteSearchIndex.index}/&amp;gt;
      )}
    /&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nothing much going on here — we’re just grabbing the search index from the elastic search data.&lt;/p&gt;

&lt;p&gt;The search component, essentially copied directly from the lunr docs:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { Component } from "react"
import { Index } from "elasticlunr"
import { Link } from "gatsby"
import styled from "@emotion/styled"

export default class Search extends Component {
  state = {
    query: ``,
    results: []
 }

  render() {
    return (
      &amp;lt;div&amp;gt;
        &amp;lt;input type="text" value={this.state.query} onChange={this.search} /&amp;gt;
        &amp;lt;ul&amp;gt;
          {this.state.results.map(page =&amp;gt; (
            &amp;lt;li key={page.id}&amp;gt;
              &amp;lt;Link to={"/" + page.path}&amp;gt;{page.title}&amp;lt;/Link&amp;gt;
              {': ' + page.tags}
            &amp;lt;/li&amp;gt;
          ))}
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }

  getOrCreateIndex = () =&amp;gt; {
    return this.index
      ? this.index
      : // Create an elastic lunr index and hydrate with graphql query results
      Index.load(this.props.searchIndex)
  }

  search = evt =&amp;gt; {
    const query = evt.target.value
    this.index = this.getOrCreateIndex()
    this.setState({
      query,
      // Query the index with search string to get an [] of IDs
      results: this.index
        .search(query, { expand: true })
        // Map over each ID and return the full document
        .map(({ ref }) =&amp;gt; {
          return this.index.documentStore.getDoc(ref)
        }),
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You build a search index, fetch results based on a partial string, hydrate those results based on what the index returns, then map over them to display.&lt;/p&gt;

&lt;p&gt;And that is seriously it. Your markdown pages will be built when Gatsby build runs and your search will index the first time you try to search.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9NF8RiIN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/950/1%2AgDARf4Ic8ft3REARmuHakw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9NF8RiIN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/950/1%2AgDARf4Ic8ft3REARmuHakw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Add security
&lt;/h3&gt;

&lt;p&gt;I’m not putting any state secrets or env variables in these logs, but I would rather not have a potential employer stumble upon them, mostly because I want to be free to talk about my struggles or be very clear about what I don’t know. If I have to censor myself, it will affect the quality of my logs.&lt;/p&gt;

&lt;p&gt;At the same time, I can’t be bothered with a login or anything too fancy. So I opted for the silliest, loosest, easiest security I could come up with: a basic localStorage token. If you have it, you see the logs, and if not, too bad. Here’s how that works.&lt;/p&gt;

&lt;p&gt;In landing-bio.js and anywhere else I want to protect:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const isBrowser = () =&amp;gt; typeof window !== "undefined"
const isAuthenticated = isBrowser() &amp;amp;&amp;amp; window.localStorage.getItem('authenticated');

[...]

{isAuthenticated ? &amp;lt;SearchBar /&amp;gt; : &amp;lt;div&amp;gt;You aren't Amber, so you don't get to read her logs.&amp;lt;/div&amp;gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I would never use this for actually-sensitive information, but it’s great for a tiny bit of peace of mind that my coworkers won’t be sneaking around my personal logs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MhE5Kwc7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AxqnLsxtodfpAgXsiRDewEA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MhE5Kwc7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AxqnLsxtodfpAgXsiRDewEA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the browser check (first line) is needed for this to pass tests on Netlify — it works fine without it otherwise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Deploy with Netlify
&lt;/h3&gt;

&lt;p&gt;I talked about how much I love &lt;a href="https://www.netlify.com"&gt;Netlify&lt;/a&gt; on my &lt;a href="https://medium.freecodecamp.org/how-to-leverage-your-react-skills-with-static-site-generator-gatsby-js-81843e928606"&gt;previous Gatsby blog post&lt;/a&gt;, and I still love them. It’s so dang easy to get your stuff right online.&lt;/p&gt;

&lt;p&gt;All you’ll do is head over to Netlify, authorize them to access the Github where your logs are stored, and they will monitor Github and make new releases for you whenever you push to master. They will also create deploy previews when you make PRs! It’s really wonderful and I super-recommend them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gF_GzbM3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A-IcqAHgJ3DHJYu8tzYEihQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gF_GzbM3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A-IcqAHgJ3DHJYu8tzYEihQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are going to create logs in markdown, I highly recommend a deploy system as easy as this one, and I don’t know of another that is as seamless.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>tech</category>
      <category>react</category>
      <category>gatsbyjs</category>
    </item>
    <item>
      <title>When to use a function declaration vs. a function expression</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Fri, 19 Apr 2019 15:44:14 +0000</pubDate>
      <link>https://dev.to/amberwilkie/when-to-use-a-function-declaration-vs-a-function-expression-5fjb</link>
      <guid>https://dev.to/amberwilkie/when-to-use-a-function-declaration-vs-a-function-expression-5fjb</guid>
      <description>&lt;h4&gt;
  
  
  Tech Jargon Series
&lt;/h4&gt;

&lt;p&gt;It’s likely you already know how to write functions in both these ways. function doStuff() {} and () =&amp;gt; {} are characters we type all day. But how are they different and why use one over the other?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Examples are given in JavaScript. _Y_our _M_ileage _M_ay _V_ary with other languages.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ai6ZBOiPaCeOTkUWhrb4TRw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ai6ZBOiPaCeOTkUWhrb4TRw.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The first difference: a name
&lt;/h3&gt;

&lt;p&gt;When you create a function with a &lt;em&gt;name&lt;/em&gt;, that is a &lt;strong&gt;function declaration&lt;/strong&gt;. The name may be omitted in &lt;strong&gt;function expressions&lt;/strong&gt; , making that function “anonymous”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function declaration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function doStuff() {};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Function expression:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const doStuff = function() {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We often see anonymous functions used with ES6 syntax like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const doStuff = () =&amp;gt; {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hoisting
&lt;/h3&gt;

&lt;p&gt;Hoisting refers to the availability of functions and variables “at the top” of your code, as opposed to only after they are created. The objects are initialized at compile time and available anywhere in your file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function declarations are hoisted but function expressions are not.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s easy to understand with an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doStuff();

function doStuff() {};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above does not throw an error, but this would:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doStuff();

const doStuff = () =&amp;gt; {};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The case for function expressions
&lt;/h3&gt;

&lt;p&gt;It might seem like function declarations, with their powerful hoisting properties, are going to edge out function expressions for usefulness. But choosing one over the other requires thinking about &lt;strong&gt;when and where the function is needed&lt;/strong&gt;. Basically, who needs to know about it?&lt;/p&gt;

&lt;p&gt;Function expressions are invoked to &lt;strong&gt;avoid polluting the global scope&lt;/strong&gt;. Instead of your program being aware of many different functions, when you keep them anonymous, they are used and forgotten immediately.&lt;/p&gt;

&lt;h4&gt;
  
  
  IIFE
&lt;/h4&gt;

&lt;p&gt;The name — &lt;strong&gt; immediately invoked function expressions &lt;/strong&gt; — pretty much says it all here. When a function is created at the same time it is called, you can use an IIFE, which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(function() =&amp;gt; {})()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(() =&amp;gt; {})()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an in-depth look at IIFEs, check out &lt;a href="https://mariusschulz.com/blog/use-cases-for-javascripts-iifes" rel="noopener noreferrer"&gt;this comprehensive article&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Callbacks
&lt;/h4&gt;

&lt;p&gt;A function passed to another function is often referred to as a “callback” in JavaScript. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function mapAction(item) {
  // do stuff to an item
}

array.map(mapAction)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem here is that mapAction will be available to your entire application — there’s no need for that. If that callback is a function expression, it will not be available outside of the function that uses it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array.map(item =&amp;gt; { //do stuff to an item })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mapAction = function(item) {
  // do stuff to an item
}

array.map(callbackFn)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;though mapAction will be available to code &lt;em&gt;below&lt;/em&gt; its initialization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In short, use function declarations when you want to create a function on the global scope and make it available throughout your code. Use function expressions to limit where the function is available, keep your global scope light, and maintain clean syntax.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function" rel="noopener noreferrer"&gt;Function declaration&lt;/a&gt;, MDN docs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function" rel="noopener noreferrer"&gt;Function expression&lt;/a&gt;, MDN docs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Hoisting" rel="noopener noreferrer"&gt;Hoisting&lt;/a&gt;, MDN glossary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Tech Jargon Series
&lt;/h3&gt;

&lt;p&gt;There are so many phrases that get thrown around at tech meetups and conferences, assuming that everyone is already down with the lingo. I’m often not down with the lingo. It’s common for developers to act astonished that I lack a piece of knowledge.&lt;/p&gt;

&lt;p&gt;The truth is, I often just don’t know the right word for it. As humans, but especially developer humans, we love to dismiss those who don’t “talk the talk”, so this series is about getting a solid understanding of programming concepts that one “should know”.&lt;/p&gt;

&lt;p&gt;This is the second article in the series. The first was &lt;a href="https://dev.to/amberwilkie/higher-order-functions-what-they-are-and-a-react-example-1ief"&gt;higher-order functions&lt;/a&gt;. Look out for more as I go to meetups and conferences and pretend to know what my fellow techies are talking about, but then have to go home and Google it.&lt;/p&gt;




</description>
      <category>programming</category>
      <category>technology</category>
      <category>webdev</category>
      <category>functionalprogrammi</category>
    </item>
    <item>
      <title>Uploading source maps to Sentry with Gulp: solved!</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Thu, 18 Apr 2019 14:59:02 +0000</pubDate>
      <link>https://dev.to/amberwilkie/uploading-source-maps-to-sentry-with-gulp-solved-3jha</link>
      <guid>https://dev.to/amberwilkie/uploading-source-maps-to-sentry-with-gulp-solved-3jha</guid>
      <description>&lt;p&gt;I’m learning that the first thing any new developer on the job wants to do is upend all the tooling. I was crazy-frustrated when we onboarded a dude at my old company who wanted to do this. Now that I’ve started a new job, I’m the one complaining about tooling (and feeling humble).&lt;/p&gt;

&lt;p&gt;So here I was, trying to get into the code base at this tiny startup. I’d gotten my login for &lt;a href="https://www.sentry.io" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;, the error tracking service, and was rearing to pick some bugs and start fixing. Unfortunately, this is what I saw:&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%2F5h2bxvud2nappomzaq86.png" 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%2F5h2bxvud2nappomzaq86.png" width="800" height="248"&gt;&lt;/a&gt;Useless minified reference to error in the code&lt;/p&gt;

&lt;p&gt;A reference to minified code. This sent me down what seems like an unnecessarily complicated rabbit-hole of sourcemappery. May you, dear reader, avoid this suffering with the tips to follow.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a sourcemap?
&lt;/h3&gt;

&lt;p&gt;A sourcemap is a guide to translate a minified version of Javascript code to the human-readable code we work with. Because we write massive amounts of Javascript and send it willy-nilly to browsers all over the place, we minify it to eke out those easily-tossable bytes. We end up with code like in the screenshot above.&lt;/p&gt;

&lt;p&gt;Typically, we will bundle up the Javascript in our files, dump it all into one file, then minify it for shipping to the browser. A function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myFunction = (paramOne, paramTwo, paramThree) =&amp;gt; {
  console.log(paramOne);
  return paramTwo + paramThree
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;gets minified to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myFunction=(o,n,c)=&amp;gt;(console.log(o),n+c);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great for browsers, not so great for anyone who needs to figure out what the heck myFunction is doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t upload source maps to production (I guess)
&lt;/h3&gt;

&lt;p&gt;The easier it is to figure out how your code is doing what it’s doing, the easier it will be for bad guys to find a way to exercise their badiness. Source maps are essentially a guide to your code, so &lt;a href="https://security.stackexchange.com/questions/113480/should-javascript-and-css-map-source-maps-be-included-on-production-servers" rel="noopener noreferrer"&gt;it can be a security risk&lt;/a&gt; to upload them to production. That said, the internets seem to be of two minds on this. If you feel comfortable sending them to the world, I guarantee you that’s an easier way to get your proper stack trace on Sentry.&lt;/p&gt;

&lt;p&gt;Sentry allows you to directly upload source maps, bypassing any security issues with having them online. But they are very particular about how you upload those files and nothing less than exactly right will produce code you actually want to see in their error log.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting point
&lt;/h3&gt;

&lt;p&gt;When I walked into this project, we were already generating source maps with &lt;a href="https://www.npmjs.com/package/gulp-sourcemaps" rel="noopener noreferrer"&gt;gulp-sourcemaps&lt;/a&gt;, and sending them to sentry using &lt;a href="https://www.npmjs.com/package/gulp-sentry-release" rel="noopener noreferrer"&gt;gulp-sentry-release&lt;/a&gt;, an npm package that hasn’t been updated in three years (!). Here’s a super-pared-down version of our gulp scripts task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gulp.src('./scripts/\*\*/\*.js')
  .pipe(plugins.sourcemaps.init())
  .pipe(plugins.concat('./scripts.js'))
  .pipe(plugins.uglify)
  .pipe(plugins.sourcemaps.write('.'))
  .pipe(gulp.dest('./dist'))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and Sentry deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sentryRelease = plugins.sentryRelease({
  API\_URL: 'https://app.getsentry.com/api/0/projects/our-team',
  API\_KEY: process.env.SENTRY\_API\_KEY,
});

const version = // some git thing that wasn't working

gulp.src('\*\*/\*.js.map')
  .pipe(sentryRelease.release(`${process.env.APP_ENV}-${version}`));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem one: versioning
&lt;/h3&gt;

&lt;p&gt;The first thing I had to fix was versioning. Sentry expects you to provide information about a release. If a user is looking at a certain release on your site, then you need to have told Sentry which source maps you are dealing with. We were using a git versioning that stopped working when the company switched to Docker nearly a year ago. Sentry had been looking at everything we pushed to production as staging- or production-.&lt;/p&gt;

&lt;p&gt;I solved this by creating a version in my package.json and incrementing it when we push to production with &lt;a href="https://www.npmjs.com/package/gulp-bump" rel="noopener noreferrer"&gt;gulp-bump&lt;/a&gt;. My gulp task looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (process.env.APP\_ENV === 'production') {
  gulp.src('./package.json')
    .pipe(plugins.bump({type: 'minor'}))
    .pipe(gulp.dest('./'));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I read from package.json to version my sentry release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { version } from '../../../package.json';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then I can use the same code I had before to send to Sentry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gulp.src('\*\*/\*.js.map')
  .pipe(sentryRelease.release(`${process.env.APP_ENV}-${version}`));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Adding the release to the code shipped to the browser
&lt;/h4&gt;

&lt;p&gt;This is great for telling Sentry that these source maps belong to this release. But what about the user browsing along on my app and getting an error? The browser needs to be able to tell Sentry which release that person is viewing. In our code, we use the Sentry &lt;a href="https://docs.sentry.io/clients/javascript/" rel="noopener noreferrer"&gt;Raven client&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raven.config('our-api-url-for-sentry', {
**release: 'SENTRY\_VERSION',**
  dataCallback: function(data){
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We later regex out the SENTRY_VERSION from our code using &lt;a href="https://www.npmjs.com/package/gulp-replace" rel="noopener noreferrer"&gt;gulp-replace&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { version } from '../../../package.json';

gulp.src('./html/\*\*/\*.html').pipe(plugins
  .replace('SENTRY\_VERSION',(`${process.env.APP_ENV}-${version}`)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the version in our HTML will match the version we send to Sentry.&lt;/p&gt;

&lt;p&gt;Note: the file doesn’t seem to get saved early enough in the gulp process. I’m hopeful a switch to gulp 4 will just resolve this. If not, there’s plenty more work to do figuring out how to version this in any logical way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem two: uploading the right source maps
&lt;/h3&gt;

&lt;p&gt;For ages, I thought I had it but Sentry was still trying to grab source maps from the internet. I knew because it was throwing an error saying they could not be found. Indeed, I had not uploaded them to production.&lt;/p&gt;

&lt;p&gt;Though gulp-sentry-release has not been touched for three years, it still handles the Sentry API just fine, as long as you manage to pass in the right options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sentryRelease = plugins.sentryRelease({
  API\_URL: 'https://app.getsentry.com/api/0/projects/our-team',
  API\_KEY: process.env.SENTRY\_API\_KEY,
  DOMAIN: '~'
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did you miss the change? DOMAIN defaults to '' in this outdated package. Sentry has since decided they want to see a tilde on the front of sourcemaps. When I added this piece, suddenly it all came together.&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%2Fyaekmqorfm822lphxbp5.png" 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%2Fyaekmqorfm822lphxbp5.png" width="800" height="542"&gt;&lt;/a&gt;Finally seeing human-readable code in Sentry&lt;/p&gt;

&lt;p&gt;There’s a good chance this didn’t solve your problem, as Sentry has a whole bunch of documentation on how to &lt;a href="https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting/" rel="noopener noreferrer"&gt;troubleshoot this issue&lt;/a&gt;. The tilde is just one of many, many problems people have trying to make this work. If you’re still on the hunt, best of luck! And if this did help you, I’d love to hear about it.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>deployment</category>
      <category>javascript</category>
      <category>gulp</category>
    </item>
    <item>
      <title>Higher-order functions: what they are, and a React example</title>
      <dc:creator>Amber Wilkie</dc:creator>
      <pubDate>Tue, 02 Apr 2019 16:58:06 +0000</pubDate>
      <link>https://dev.to/amberwilkie/higher-order-functions-what-they-are-and-a-react-example-1ief</link>
      <guid>https://dev.to/amberwilkie/higher-order-functions-what-they-are-and-a-react-example-1ief</guid>
      <description>&lt;h4&gt;
  
  
  Tech Jargon series
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ax4AH7NNM6KIASH0-9dOKOg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ax4AH7NNM6KIASH0-9dOKOg.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are so many phrases that get thrown around at tech meetups and conferences, assuming that everyone is already down with the lingo. I’m often not down with the lingo. It’s common for developers to act astonished that I lack a piece of knowledge.&lt;/p&gt;

&lt;p&gt;The truth is, I often just don’t know the right word for it. As humans, but especially developer humans, we love to dismiss those who don’t “talk the talk”, so this series is about getting a solid understanding of programming concepts that one “should know”.&lt;/p&gt;

&lt;p&gt;My first topic for this series is Higher-Order Functions. I was at a tech meetup the other day, and we were discussing React and how difficult it can be for React newbies to get into the code. I mentioned that higher-order components (HOCs) can be tough to understand. A response was that they are much like higher-order functions, don’t I agree? And I said: “I don’t know what that is.” When I asked for an example, I was told “map”. I made a joke about how I have no idea what “map” is and we moved on.&lt;/p&gt;

&lt;p&gt;But still: &lt;em&gt;what is a higher-order function?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(Note: all the examples given are in Javascript, but this concept applies to every programming language.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Higher-order functions: a definition
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A higher-order function is one which either a) takes a function as an argument or b) returns a function.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a function doesn’t do either of those things, it is a &lt;strong&gt;first-order function&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Map
&lt;/h3&gt;

&lt;p&gt;Let’s start with the example I was given: map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3].map(num =\&amp;gt; num \* 2)
\&amp;gt; [2, 4, 6]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The map function is called on an array and takes a “callback” function. It applies the function to each of the items in the array, returning a new array. [1, 2, 3] is our array and num =&amp;gt; num * 2 is our function. A callback is the function argument passed to our higher-order function.&lt;/p&gt;

&lt;p&gt;This HOF is baked into the language, prototyped on Array (Array.prototype.map).&lt;/p&gt;

&lt;p&gt;Other examples of HOFs prototyped on Array are filter, reduce, and some.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom example
&lt;/h3&gt;

&lt;p&gt;So let’s write our own higher-order function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passed function
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myFunc = age =\&amp;gt; age \* 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Higher-order function
&lt;/h4&gt;

&lt;p&gt;Now we write a function that &lt;em&gt;takes in&lt;/em&gt; a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const hof = (customFunc, age) =\&amp;gt; customFunc(age + 5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll pass a number to hof, which will add 5 and then call our passed function, which will double it. If we pass 10, we pass 15 to our first function, which then doubles to 30.&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%2Fcdn-images-1.medium.com%2Fmax%2F942%2F1%2AhihD4HHej1EcMr04jctg9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F942%2F1%2AhihD4HHej1EcMr04jctg9A.png"&gt;&lt;/a&gt;Our dead-simple higher-order function running in the terminal&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom example with React “components”
&lt;/h3&gt;

&lt;p&gt;As I noted above, this topic came up in reference to React’s components. As a React component is a function, when passing it to another function, we are creating our own higher-order function, which React calls “higher-order components”. If you are using stateful components (and extending React’s Component), you are already using HOCs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stateless Component
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const details = ({ name, randomNum }) =\&amp;gt;
 `${name}, ${randomNum}`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a function, called details, into which we pass props. We are deconstructing them as they come in and assigning them to local variables name and randomNum. This is ES6 syntax — if it looks unfamiliar give it a google (you’ll love it).&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;first-order function&lt;/strong&gt;  — it takes one argument (a props object) and returns a template literal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Higher-order component
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const hoc = (component, props) =\&amp;gt; {
 const randomNum = Math.floor(Math.random() \* 100)

return component({ ...props, randomNum })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;strong&gt;higher-order function&lt;/strong&gt;  — it takes in a function (the component, which it then calls, passing in additional props). This is an extremely basic example of what every stateless React component is doing.&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%2Fcdn-images-1.medium.com%2Fmax%2F934%2F1%2ASV9bA8FBOWuGCmMBJ22-Jg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F934%2F1%2ASV9bA8FBOWuGCmMBJ22-Jg.png"&gt;&lt;/a&gt;Our super-basic “component” running in the console&lt;/p&gt;

&lt;p&gt;You can employ this pattern to abstract code that is shared among many components in your application.&lt;/p&gt;

&lt;p&gt;Are you wondering if you can nest higher-order functions? You can! But be careful. Abstractions should make code &lt;em&gt;easier to read and work with&lt;/em&gt;. It’s easy to get down a path here where your code is so obtuse no one can figure out how to do anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Higher-order_function" rel="noopener noreferrer"&gt;Higher-order-function&lt;/a&gt;, Wikipedia&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://eloquentjavascript.net/05_higher_order.html" rel="noopener noreferrer"&gt;Higher-order functions&lt;/a&gt;, Eloquent Javascript (chapter 5)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype" rel="noopener noreferrer"&gt;Array.prototype MDN docs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>technology</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
