Today I Learned

Small clippings of things I’ve learned. Not always learned on the day posted.

#17

The Most Important Role of JS Frameworks

2019-08-26

TAGS: reactvuejavascript

My friend Pete passed along this article: The deepest reason why modern JavaScript frameworks exist. Granted, the title is a little questionable, but the thesis raised a good point.

The main problem modern JavaScript frameworks solve is keeping the UI in sync with the state.

So when should you reach for a React or Vue? When you need to keep the state and the UI in sync.

If you don't have state, or the state isn't changing you can get by with Vanilla JS. Anything more, and you're probably better off pulling in React or Vue.

#16

Locally Host Fonts Easily with Typeface npm Package

2019-08-25

TAGS: gatsbyfonts

Turns out "self-hosting" web fonts is much faster than using Google or Adobe's CDN.

You can put the font file into your assets folder in a Gatsby project, and that'll work just fine.

I opted to use this npm package called Typefaces by Gatsby's Kyle Mathews. Trusted source and all that.

More importantly, I didn't have to go and track down the font files I wanted to use.

Setup for Gatsby

In your terminal:

yarn add typeface-open-sans typeface-raleway

Then in gatsby-browser.js

require("typeface-raleway");
require("typeface-open-sans");

All set. Gatsby will even put the CSS in my <head> so it all loads faster.

#15

Hiding Content with Summary/Details HTML Elements

2019-08-23

TAGS: html

Reading through Chris Coyier's excellent Advice for Technical Writing I saw him mention the details and summary elements.

Basically a native browser way to tuck some text away into an accordion.

Here's his example from the article:

<details>
  <summary>What is the population of New Orleans?</summary>
  <p>According to 2010 Census Bureau estimates, New Orleans' population is made up of approximately 343,829 residents.</p>
</details>

This seems like a great way to make a self-administered 'quiz' for your readers as a review at the end of an article.

Opt-In

In the article, Chris seems to recommend the details element to make text opt-in, rather than all visible.

Maybe if you're writing an article and you mention Redux. You don't want to bore the readers who already know it, but also don't want to leave behind readers who don't.

Tucking it away in a details or summary element gives both readers what they need.

#14

Referencing Angular controls with dot notation

2019-08-23

TAGS: angular

Sometimes when referencing a specific control in an Angular 2+ FormControl, VSCode will claim that it can't find controls on personalForm in your template.

Here's an easy fix to appease the IDE Gods:

- [errors]="myForm.controls.firstName.errors ? myForm.controls.firstName.errors : []"
+ [errors]="myForm['controls'].firstName.errors ? myForm['controls'].firstName.errors : []"
#13

Easy console.log in Arrow Functions

2019-08-23

TAGS: javascript

Generally if I want to log out what's getting passed into an arrow function like this:

const newNames = names.map( name => doThing(name) )

I have to add brackets and a return like this:

const newNames = names.map( name =>  {
  console.log(name);
  return doThing(name);
})

But because console.log()'s value is void, the || (OR) operator will run the function, and because it's falsey, return the second thing, like this:

const newNames = names.map( name => console.log(name) || doThing(name) )

TypeScript yells at you saying console.log() will never resolve as true. But we're not shipping the code, just debugging. It works just fine for that.


Thanks to my coworker Brendan for showing me this trick.

#12

Remove Unused Imports with TypeScript and VSCode

2019-08-23

TAGS: vscodetypescriptjavascript

When refactoring I'll typically remove some code and have some unused imports sitting at the top of my files. Going in and sniping out each faded word isn't the best use of time, so let's let our IDE take care of it.

VSCode has an Organize Imports feature that allows you to clean up your code with a keystroke.

option+Shift+O for Mac

Alt + Shift + O for Windows

Not only that, but it reorganizes the imports alphabetically, leaving you with clean code that your whole team can agree on.

I'd love to see this kind of thing roped into Prettier so that my code gets cleaned up all in one fell swoop.


Learned this after a search and StackOverflow result.

#11

Shadowing Gatsby Themes

2019-08-21

TAGS: gatsby

I'm adding Gatsby-Theme-Notes to my personal site and had trouble wrapping it in my site's layout component.

I found Chris Bascardi's blog post on Layouts in Gatsby Themes but it didn't specifically say how to wrap the theme in my layout component.

I did some digging and watched Jason Lengstorf and Brent Jackson go through a theme. Turns out they needed to shadow the Gatsby theme they were using.

We do this by creating a folder in our project that's named the same as the folder in the theme. Whatever files or components we want to overwrite we include in that folder.

It's kind of like using the spread operator to overwrite a property.

const newFirstName = "Sarah";
const newUser = { ...oldUser, firstName: newFirstName };

Anything that's in the theme's src folder we can shadow.

The theme's file structure looks like this:

📦 gatsby-theme-notes
 ┣ 📂src
 ┃ ┣ 📂components
 ┃ ┃ ┣ 📜breadcrumb-divider.js
 ┃ ┃ ┣ 📜breadcrumb-home.js
 ┃ ┃ ┣ 📜breadcrumbs.js
 ┃ ┃ ┣ 📜directory-list.js
 ┃ ┃ ┣ 📜file-list.js
 ┃ ┃ ┣ 📜footer.js
 ┃ ┃ ┣ 📜layout.js
 ┃ ┃ ┣ 📜note.js
 ┃ ┃ ┗ 📜notes.js
 ┃ ┣ 📂gatsby-plugin-theme-ui
 ┃ ┃ ┗ 📜index.js
 ┃ ┣ 📂templates
 ┃ ┃ ┣ 📜note.js
 ┃ ┃ ┗ 📜notes.js
 ┃ ┣ 📜use-options.js
 ┃ ┗ 📜use-site-metadata.js
 ┣ 📜README.md
 ┣ 📜gatsby-config.js
 ┣ 📜gatsby-node.js
 ┣ 📜index.js
 ┗ 📜package.json

So to shadow the layout component, my file structure looks like this:

📦src
 ┣ 📂gatsby-theme-notes
 ┃ ┣ 📂components
 ┃ ┃ ┣ 📜layout.js

Gatsby will use my layout component in place of the Theme's, but keep the rest of the theme's files. This lets me get updates to the project when they come in, as I'm only editing the one layout.js.

#10

Subscribe to Action Results in NGRX with Facade Pattern

2019-08-20

TAGS: angularngrx

At work we recently moved our state management to ngrx with a Facade pattern.

The developer who selected and implemented our facade pattern told us that it was impossible to know whether a call was successful or not. With a new hire at work and some Googling, we found a solution that works for the short term.

This response on Stack Overflow worked for the most part, but seemed to be using a different version of ngrx. Putting the methods inside a pipe made it work:

[...]
import { Actions } from '@ngrx/effects';
[...]

@Component(...)
class SomeComponent implements OnDestroy {
    destroyed$ = new Subject<boolean>();

    constructor(updates$: Actions) {
        updates$
+            .pipe(
+            ofType(PostActions.SAVE_POST_SUCCESS),
+            takeUntil(this.destroyed$),
+            tap((arg) => console.log(arg))
+            ).subscribe();
-            .ofType(PostActions.SAVE_POST_SUCCESS)
-            .takeUntil(this.destroyed$)
-            .do(() => /* hooray, success, show notification alert ect.. */)
-            .subscribe();
    }

    ngOnDestroy() {
        this.destroyed$.next(true);
        this.destroyed$.complete();
    }
}

We'll eventually abstract this away into a class that our components can extend, but this is great for now.

#9

Using LocalStorage for Quick Persistent State

2019-08-19

TAGS: javascript

LocalStorage is handy in a pinch when you don't have any better solution for saving some form of state between sessions.

In my arcade game Dogger I save the scores to Local Storage so the user can compete against their personal best. LocalStorage is also handy for persisting a user's preference for Dark Mode, if your site offers it.

LocalStorage Methods

LocalStorage comes with a few methods to help us out.

Set Item

localStorage.setItem('highScore', '1500');

Get Item

To retrieve the data from localStorage:

const highScore = localStorage.getItem('highScore');

Remove Item

localStorage.removeItem('highScore');

Clear Everything

This removes everything from localStorage on this current website. This won't affect the localStorage from other sites.

localStorage.clear();

Using with LocalHost

You'll run into an issue when developing locally, as localStorage is all domain based. It helps if you make your key specific to the account or project you're on.

So instead of just doing:

localStorage.setItem('highScore', '1500');

You'd do something like this:

localStorage[account.id] = JSON.stringify({ highScore : 1500 });
#8

CSS Selectors: Child vs. Recursive

2019-08-16

TAGS: css

For a while I thought there was little difference between div > div and div div in CSS. Turns out there's a pretty drastic difference.

All Child Elements

.container * {
  padding: 1rem;
}

That will affect all items recursively inside .container. Children, grandchildren, great-grandchildren. You get the idea.

First Level Only

.container > * {
  padding: 1rem;
}

That will only affect the first level of elements inside container. Just the children, leaving grand-children untouched.

#7

Gatsby Clean

2019-08-15

TAGS: gatsby

If you're having build trouble with Gatsby a lot of times clearing your .cache and public folders will fix the problem. There's even a Gatsby CLI shortcut to help with that.

gatsby clean

If you're still having trouble, try removing the node_modules folder and reinstalling npm packages.

Also make sure you're not mixing yarn and npm for managing your Gatsby project. It can quickly get messy.

#6

VSCode Color Coded Title Bars

2019-08-14

TAGS: vscode

If you have to switch between repositories multiple times a day, you might benefit from having your workspaces color coded. Blue for me is the UI, while our services code is orange, etc.

In the root of your project make a folder named .vscode. Inside create a settings.json file. Paste the following:

{
  "workbench.colorCustomizations": {
    "titleBar.activeBackground": "#34ace0",
    "titleBar.activeForeground": "#ffffff",
    "titleBar.inactiveBackground": "#368fb5",
    "titleBar.inactiveForeground": "#d7d7d7"
  }
}

This will give you a nice skyblue titlebar. Change the colors and repeat the process in any repo you work in to give you a nice visual cue.


Picked this one up from Wes Bos's Advanced React course a while back. Still appreciate the visual cue every day.

#5

Contentful, Gatsby, and Markdown

2019-08-14

TAGS: graphqlgatsbycontentful

When adding this TIL feature to my website I hit a snag on build in gatsby-node.

The issue came because I'm bringing in data from local markdown files as well as the Contentful API. I have a markdown content type from Contentful that gets picked up by allMarkdownRemark. That would then try and access frontmatter that wasn't there. A quick filter in my GraphQL query allowed me to only bring in local files.

{
  allMarkdownRemark(
    filter: { fileAbsolutePath: { ne: null } }
  ) {
    edges {
      node {
        fields {
          slug
        }
        frontmatter {
          type
        }
      }
    }
  }
  allContentfulTil {
    edges {
      node {
        title
        number
      }
    }
  }
}
#4

Debugging Gatsby in VSCode

2019-08-13

TAGS: vscodegatsbydebugging

I never realized just how nice the VSCode debugging was. Was having trouble debugging my Gatsby build and found these docs:

https://www.gatsbyjs.org/docs/debugging-the-build-process/

Setting VSCode's debug settings to Auto Attach and running this:

node --nolazy --inspect-brk node_modules/.bin/gatsby develop

I set up some breakpoints in the code, then I was able to see what was coming through and debug from there. Way more powerful than console logging out everything.

#3

Angular Components with Top/Bottom Spacing

2019-08-12

TAGS: angularcss

When trying to add top or bottom margin to an Angular component it has no effect unless you add display:block; to the component. Angular components default to display:inline which doesn't take top or bottom padding/margin.

Non-working example:

<my-component class="component"></my-component>
.component {
  margin: 2rem 0;
}

This has no effect because my-component is defaulting to display:inline.

Working example:

<my-component class="component"></my-component>
.component {
  margin: 2rem 0;
  display:block;
}
#2

Avoiding Undefined in Deeply Nested Objects

2019-08-12

TAGS: javascript

The Problem

When checking for a property on a heavily nested object, you can sometimes run into undefined errors.

It's not so bad with something like user.name. You can use the && operator like this:

user && user.name

This only tries to access name on user if user exists.

With this object: user.company.documents.handbook there are multiple points where it could all fall apart. The solution using && starts to get really messy.

Destructuring Solution

We can use destructuring assignment to pull the values out.

const { user: { company: { documents: { handbook:  = 'default' } = {} } = {} } = {} } } = this

This gives us fallbacks with each = {} and also makes the variables more managable to work with.

Learned this one from Brady Sutton.

Lodash Solution

Lodash gives us the get method where you pass it an object, then the path you want, then the default value you'd like returned if anything comes back undefined.

_.get(this, 'user.company.documents.handbook', 'default')

Learned this one from Brady Sutton.

Optional Chaining Solution

We have a great solution coming to JavaScript soon called Optional Chaining. This will open up this syntax:

user.address?.zipcode
#1

Naming CSS Grid Rows and Columns

2019-08-11

TAGS: csscss grid

I usually name my CSS Grid areas so I can reference them easily. If I want to name columns I usually do it like this.

.container {
  display: grid;
  grid-template-columns: 3fr 4fr;
  grid-areas: "sidebar content";
}

Turns out there’s a great shorthand if you want to name an entire column or row. You can name your CSS Grid columns and rows like this:

.container {
  display: grid;
  grid-template-columns: [sidebar] 3fr [content] 4fr;
}

Not only does it save you some lines of code, but you get the name right next to the size for easy reference.


Learned it from this article.