Today I Learned

A Hashrocket project

90 posts about #javascript

String Interpolation With Template Literals

ES6 adds support for template literals. Template literals make it much easier to compose strings of content — string interpolation. They allow for single and double quotes without having to fuss with escaping. Embedded expressions are also supported which means you can avoid awkward-to-type string concatenation with the + operator.

Here is an example:

> let movie = 'it'
undefined
> `What's up, I just saw "${movie.toUpperCase()}".`
"What's up, I just saw "IT"."

Make console.log stand out with custom css style

I know your browser console is full of messages because you are debugging something, and that creates a lot of noise. Now you are adding a new console.log, and you need it to stand out above the rest.

Maybe you are like facebook and just want to warn your users from pasting in code in the browser in social engineering attacks.

facebook

To style a console.log message use the %c interpolation and pass it a css style. e.g.

console.log('%c%s', 'color:red;font-size:5em', alert)

In the example above %s means inerpolate the object into the output string.

preview

Compatibility: tested to work on Firefox, Chrome, and Safari.

h/t Dillon Hafer

`requestAnimationFrame` should call itself

This style of animation is useful when you’re making small changes via javascript. When you pass requestAnimationFrame a callback, the callback is called before a browser repaint, or about 60 times a second. To make sure that you’re getting 60 callbacks a second, you must call requestAnimationFrame from within your callback.

function animate() {
  makeSomeSmallChangeToHtmlOrCss();
  requestAnimationFrame(animate);
}

This is a recursive function, so without an exit condition, it will recurse infinitely.

H/T Brian Dunn

Tidy your Reducers with `combineReducers()`

Today I learned by necessity the value of the Redux combineReducers(reducers) function.

combineReducers() supports, in a pretty neat way, the crucial Redux task of delegating to reducing functions their own slice of the state.

The documentation example looks like this:

combineReducers({ todos: myTodosReducer, counter: myCounterReducer });

Which we can improve by naming the reducer functions after the state slices they manage, allowing ES6 shorthand notation:

combineReducers({ counter, todos });

This creates a state object like so:

{
  counter: ...,
  todos: ...,
}

Upgrading npm when using `asdf` with `reshim`

The version of npm that comes with nodejs when installed with asdf may not be the latest. In my case I had npm 5.3.0 installed and the newest version is 5.4.2. I upgraded npm with npm install -g npm and saw output that made me think everything installed successfully, but when I ran npm -v I still got 5.3.0.

The answer is to use asdf’s reshim command.

> asdf help reshim
asdf reshim <name> <version>    Recreate shims for version of a package

I ran the following command:

> npm -v
5.3.0
> asdf reshim nodejs
> npm -v
5.4.2

And now I have the latest version and everything is great!

Matching Multiple Values In A Switch Statement

Switch statements are a handy way to execute different branches of code based on a value match. This is often what is used in Redux reducers when updating the state in response to certain actions.

But what if you need multiple values to result in the same branch of execution without duplicating the code?

The execution of a switch statement falls through, so after one match, it will continue to try and do subsequent matches if you don’t interrupt the execution with a break or return. Conveniently, this solves our problem of matching multiple values.

switch (action.type) {
  case "UPDATE_NAME":
  case "UPDATE_DURATION":
    let newData = anotherReducer(state.data, action);
    return { ...state, data: newData };
  default:
    return state;
}

See the MDN docs for more details.

Access A Value Logged To The DevTools Console

Did your app just log an object to the dev tools console and you’d like to interact with that object? It’s not straightforward, but you can do it.

Assuming you already have dev tools opened to the console tab, right click on the value that has been logged to the console. Select the Store as Global Variable option. This will re-log the value assigning it to the temp1 variable.

You can now reference that object as temp1 accessing its values and calling functions.

You can even do this with multiple logged values, each subsequent one will be assigned incrementing variable names: temp2, temp3, etc.

source

Find an npm library from the command line

When looking for a new package to use with npm you can use npm search <string>. This will query npm and return 20 - 25 results that match your search.

> npm search react-router
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
react-router              | Declarative routing… | =ryanflorence   | 2017-08-24 |          | react router 
react-router-dom          | DOM bindings for…    | =mjackson…      | 2017-08-24 |          | react router 
react-router-redux        | Ruthlessly simple…   | =jlongster…     | 2017-02-10 |          | react redux r
react-router-native       | React Native…        | =jmurzy…        | 2017-08-24 |          |
react-router-config       | Static route config… | =mjackson…      | 2017-08-24 |          | react router 
react-router-bootstrap    | Integration between… | =monastic.panic… | 2017-04-19 |          | react react-
react-router-scroll       | React Router scroll… | =taion          | 2017-04-10 |          | react react r
react-native-router-flux  | React Native Router… | =aksonov        | 2017-08-23 |          |
...

There doesn’t seem to be a way to search by date, version or popularity, but if you pass the --long flag you’ll be able to see the entire description. Without the --long flag the results will be truncated to fit onto one line.

Prettier ignore! 💁 #javascript

Prettier is super helpful but sometimes you just want to format things your way if the output of prettier is not very readable.

To solve this, prettier provides a comment that you can put above any “node” in the resulting javascript AST.

For example:

BEFORE (w/ prettier)

const street_number = this.findAddressComponent(
  resultObj,
  'street_number'
).long_name;
const route = this.findAddressComponent(resultObj, 'route').long_name;
const zip_code = this.findAddressComponent(resultObj, 'postal_code')
  .long_name;
const city = this.findAddressComponent(resultObj, 'locality').long_name;
const state = this.findAddressComponent(
  resultObj,
  'administrative_area_level_1'
).short_name.toUpperCase();

The above is a result of prettier formatting and is not very readable or pretty - so I would need to turn it into a single AST node and put the prettier-ignore comment over it:

AFTER (w/ prettier-ignore)

// prettier-ignore
const address = {
  street_number: this.findAddressComponent(resultObj, 'street_number').long_name,
  route: this.findAddressComponent(resultObj, 'route').long_name,
  zip_code: this.findAddressComponent(resultObj, 'postal_code').long_name,
  city: this.findAddressComponent(resultObj, 'locality').long_name,
  state: this.findAddressComponent(resultObj, 'administrative_area_level_1').short_name.toUpperCase(),
}

Now the address components will be accessible from the address object (e.g. address.route) and while still not the prettiest, it is a lot more readable IMO.

Create Bootstrapped Apps With Yarn

The yarn cli comes with a create command that is a convenience command for generating bootstrapped apps that follow the create-<name>-app convention.

Want to create a React.js app using create-react-app, invoke the following command:

$ yarn create react-app my-app

Don’t already have a particular package globally installed? yarn create will install it for you. For instance, the following command with install and use create-vue-app:

$ yarn create vue-app my-other-app

h/t Gabe Reis

Specify Port Of CRA's Webpack Dev Server

create-react-app gives you a set of scripts, one of which allows you to start a development server that bundles and serves your javascript. This is handled under the hood via webpack-dev-server. By default it attempts to serve from port 3000. If port 3000 is taken it will attempt to connect to another sequential port.

Alternatively, you can just specify the port when starting the development server. This can be done with the PORT env var.

$ PORT=3333 yarn start

Yarn Commands Without The Emojis

If you are a hater and you’d like to run yarn commands without emojis being playfully included in the output, just include the --no-emoji flag. The output of a command like add will look like this:

$ yarn add chalk --no-emoji
yarn add v0.17.10
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 7 new dependencies.
├─ ansi-styles@3.1.0
├─ chalk@2.0.1
├─ color-convert@1.9.0
├─ color-name@1.1.3
├─ escape-string-regexp@1.0.5
├─ has-flag@2.0.0
└─ supports-color@4.2.0
Done in 0.54s.

See yarn help for details.

Default And Named Exports From The Same Module

ES6 module syntax allows for a single default export and any number of named exports. In fact, you can have both named exports and a default export in the same module.

Here is an example:

// src/animals.js
export default function() {
  console.log('We are all animals!');
}

export function cat() {
  console.log('Meeeow!');
}

export function dog() {
  console.log('Rufff!');
}

In this case, you could import the default and named exports like so:

// src/index.js
import animals, { cat, dog } from './animals.js';

animals(); // "We are all animals!"
cat();     // "Meeeow!"
dog();     // "Rufff!"

source

Run Prettier on all #JavaScript files in a dir

If you are like me you must like formatters such as Prettier which probably prompted you to set your editor to auto format the file on save.

That’s great for new projects but when working on an existing project, every file you touch will have a huge diff in git that can obscure the real changes made to the file.

To solve that you must run prettier on all your javascript files as an independent commit. You can do it with the following command:

find ./src/**/*.js | xargs prettier --write --print-width 80 --single-quote --trailing-comma es5

The flags after the prettier are all my personal preferences except for --write which tells prettier to write the file in place.

Note 1: Make sure you have all the files you are about to change committed to source control so that you can check them out if this did not go well.

Note 2: When committing this change it would be a good idea to use git add -p and go through the changes one by one (which is always a good idea…)

Note 3: To dry run and see which files will be changed run the find ./src/**/*.js by itself.

jQuery.map returns wrapped elements

There are thousands of ways to write JavaScript and many ways to map over a collection in JavaScript. The jQuery variant of the function has a couple of peculiarities that might trip you up however.

First, the arguments to the map function are not (item, index) like they are for the Array.prototype.map function. Instead, they are (index, item).

Second, the jQuery map function does not return an array consisting of the values returned from the map function. It instead returns an array of those values wrapped by jQuery.

This can be unexpected when iterating over a set of elements to create an array of derived values.

Code splitting with Webpack 2 and Babel

Webpack 2 provides the ability to split your code into smaller files that are lazy loaded during runtime as they are needed.

When I first learned about this feature I thought it would be very intelligent in detecting which parts of the code are using a certain module and split all my modules into separate files automatically. That’s not really the case.

If you want to have Webpack split your code and lazy load it you need to explicitly call import in your code. For example:

import Foo from './foo';

class Bar {
  baz() {
    Foo.someMethod(); // this will not be split and lazy loaded
    
    import('./lazy_module').then(function(lazyModule) {
      console.log(lazyModule.sayHello());
    }).catch(function(err) {
      console.log('Failed to load lazy module', err);
    });
  }
}

To have this work you need to install the Syntax Dynamic Import library

Then edit your .babelrc:

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": ["syntax-dynamic-import"]
}

The “modules”: false part is really important. It basically instructs Babel to not try and parse the imports but let Webpack 2’s native ability to parse imports to do the work. This was tricky.

There’s more to that and it keeps changing so I recommend visiting this documentation https://webpack.js.org/guides/code-splitting-import/

Yarn global

Just like npm install -g, Yarn provides yarn global add. I found however that it did not work right out of the box to register executable binaries/CLIs.

To fix this add the following to your .zshrc/.bashrc:

# set yarn binaries on path
export PATH="$HOME/.config/yarn/global/node_modules/.bin:$PATH"

Now all binaries installed from yarn should be on your system PATH.

Save disk space with Yarn

Yarn is a fast, reliable and secure replacement for npm. Those are all important attributes in my book for a tool I use daily for development, but that’s not all Yarn offers.

The node_modules directory is often a resource consuming hog both in space and number of files. It is full of junk such as test files, build scripts and example directories.

To clean some of those files Yarn offers the clean command. To run it:

yarn clean

Once run, the command will create a .yarnclean file with patterns of type of files to be deleted. By default yarn clean will delete the following:

# test directories
__tests__
test
tests
powered-test

# asset directories
docs
doc
website
images
assets

# examples
example
examples

# code coverage directories
coverage
.nyc_output

# build scripts
Makefile
Gulpfile.js
Gruntfile.js

# configs
.tern-project
.gitattributes
.editorconfig
.*ignore
.eslintrc
.jshintrc
.flowconfig
.documentup.json
.yarn-metadata.json
.*.yml
*.yml

# misc
*.gz
*.md

With this file in your project root directory Yarn will ensure to run a cleaning task after every install and report how much space it saved you.

Alias Loaders in webpack

A loader might not be named conveniently for your project. Maybe the path to it is too long and obscures the actual configuration of the loader, in that case you can create an alias with the resolveLoader.alias webpack configuration.

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'smrt',
      }
    ]
  },
  resolveLoader: {
    alias: {
      'smrt': require.resolve(__dirname, 'really', 'long', 'path', 'smart-loader.js')
    }
  }
}

In addition, you may only want to transform one file. Its possible to do that in a require statement and use the bang character (!) prefix syntax to declare the loader like this.

require 'smrt!dumbfile';

Clearly in this case a long loader name would obscure intent.

Export from old school libraries in Webpack

As you are refactoring your legacy Rails project towards webpack and away from the asset pipeline you discovered an old version of the facebook_sdk that is absolutely critical to the ongoing success of the legacy application. This file doesn’t play nicely with CommonJS though and exports its constant with global declarations like:

var FB = {};

This isn’t very global in CommonJS and your app doesn’t have access to that constant anymore.

The problem can be solved with the exports-loader used like so:

module.exports = {
  module: {
    rules: [
      {
        test: /facebook_sdk/,
        loader: 'exports-loader?FB',
      }
    ]
  }
}

This is just a cute way of tacking an export line to the bottom of the file like this:

module.exports = FB;

Custom loaders for webpack

Perhaps there is a transformation you’d like to perform on your javascript files that is unique to your project. Perphaps replacing the word dumb with smart is a requirement but you don’t have control over the actual files and can’t make that change to the source files themseles.

In this situation, you can use a custom loader.

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: './smart-loader',
      }
    ]
  },
}

The loader itself (smart-loader.js) would look something like this.

module.exports = function(source) {
  return source.replace('dumb', 'smart');
}

Exclude files from webpack transformation

Sometimes you want every file that has the .dumb extension to be transformed by the dumb-loader except for one particularly dumb file that should remain as is, as a lesson for to all the other dumb files. Just use the handy exclude configuration on modules.rules.loader to make sure that file doesn’t get transformed.

module.exports = {
  module: {
    rules: [
      {
        test: /\.dumb$/,
        loader: 'dumb-loader',
        exclude: /really\.dumb/
      }
    ]
  }
}

Now that really dumb file won’t get transformed by the dumb loader.

Cascading function calls

Cascading function calls can be useful for building up properties on an object. We can simply return this at the end of each cascading function so that we always end up with the object when we’re done.

Example - building a flash message after an ajax request in rails:

$.ajax({
        method: 'DELETE',
        url: url,
        contentType: 'application/json',
        error: function(status, data, jqxhr){
          var message = JSON.parse(status.responseText).error;
          var flash = new FlashBuilder('div');

          flash.text(message)
            .addClass('notification-error')
            .append('.flash-messages', '#some_container');
        }
      });
function FlashBuilder(el){
  this.element = $('<' + el + '>');

  this.text = function(text){
    this.element.text(text);
    return this;
  };

  this.addClass = function(klass){
    this.element.addClass(klass);
    return this;
  };

  this.append = function(target, container){
    if(container){
      $(container).find(target).append(this.element);
    } else {
      $(target).append(this.element);
    }

    return this;
  }
}

e.target vs this in delegated events

When attaching click handlers to elements, I used to think I could use e.target interchangeably with this. That is not true when we use event delegation.

Given the following JS:

    $('body').on('click', "[id^=delete_thing]", function(e){
      // do stuff
    });

And the following HTML:

<a href="javascript:void(0)" id="delete_thing_184">
      <img  src="/assets/ui/icon_delete.png">
      <strong> Delete Thing </strong>
</a>

When we click this link, we’re actually clicking either the <strong> or the <img>. When the event e is passed to the callback, e.target is the element we actually clicked, and this is the element the click event bubbled up to, so use this instead of e.target.parent.

Expand Emojis With The Spread Operator

There are a number of emojis that are not stand-alone unicode characters, but instead are a combination of two or more other emojis. The two main places this happens is with family emojis and emojis using non-simpsons skin tones.

You can use JavaScript’s spread operator to expand these emojis to see what their base components are. Here is a screenshot of a few that I expanded from Chrome’s dev tools.

source

Respect Do Not Track 👁‍🗨

Before I put google analytics, adwords, or other third party scripts on my sites I can respect the DNT headers a user has set. Here’s how I can do it with Google Analytics:

<script>
  if (window.navigator.doNotTrack !== '1') {
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-xxxxxxx-5', 'auto');
    ga('send', 'pageview');
  }
</script>

In the above snippet I check if the user has enabled DNT. If they haven’t set the header or they have turned it off the script will run. Checking for window.navigator.doNotTrack !== '1' ensures that the user purposely set the header.

Name that anonymous function

I use anonymous functions in javascript a whole bunch but anonymous functions don’t get a name:

> a = function() {}
> a.name
undefined

Its helpful to have a name for the function when you’re debugging and need to determine the caller of a function or if you want to determine which function has been passed in as an argument.

It’s easy to name anonymous functions:

> a = function myName() {}
> a.name
'myName'

But weirdly, javascript doesn’t know about a function named myName so you’re not polluting the namespace:

> myName()
ReferenceError: myName is not defined

Date javascript

Date javascript function on chrome is weird:

new Date('2016-10-3')
Mon Oct 03 2016 00:00:00 GMT-0400 (EDT)
new Date('2016-10-10')
Sun Oct 09 2016 20:00:00 GMT-0400 (EDT)

Why? Anyway, this is my “alternative” approach for that:

new Date('2016-10-10 0:0')
Mon Oct 10 2016 00:00:00 GMT-0400 (EDT)
new Date('2016-10-3 0:0')
Mon Oct 03 2016 00:00:00 GMT-0400 (EDT)

Print call stack on Javascript

If you want to print the javascript call stack you can use:

console.log(new Error().stack);

Here it is an example:

function firstFunction() {
    secondFunction();
}
function secondFunction() {
    thridFunction();
}
function thridFunction() {
    console.log(new Error().stack);
}
firstFunction();

//=> Error
//    at thridFunction (<anonymous>:2:17)
//    at secondFunction (<anonymous>:5:5)
//    at firstFunction (<anonymous>:8:5)
//    at <anonymous>:10:1

h/t @rondale_sc

Does CoffeeScript has a ternary operator?

Javascript has a ternary operator condition ? expr1 : expr2 like:

var x = true;
x ? 'yes' : 'no'
//=> "yes"
x = false;
x ? 'yes' : 'no'
//=> "no"

What about CoffeeScript?

#is-it-ternary.coffee
x ? 'yes' : 'no'

will be compiled to the following:

//is-it-ternary.js
if (typeof x !== 'undefined' && x !== null) {
  x;
} else {
  ({ 'yes': 'no' });
}

Why? Because of The Existential Operator

So there is no ternary operator on CoffeeScript. The best you can do is to have an one-line if-else statement:

if x then 'yes' else 'no'

h/t @mwoods79

Timing Processes

If you want to time a process, you can use the console.time() and console.timeEnd() utilities specified by the console Web API. Invoking console.time() with a label starts a named timer. You can then run the process you want to time. Then invoke console.timeEnd() with the same label to terminate the timer and see how long the process took.

console.time('sorting');
[11,10,9,8,7,6,5,4,3,2,1].sort();
console.timeEnd('sorting');
> sorting: 0.278ms

console.time('console logging');
console.log('logging to the console');
console.timeEnd('console logging');
> logging to the console
> console logging: 0.311ms

console.time('adding'); 1 + 1; console.timeEnd('adding');
> adding: 0.006ms

These functions are implemented in most modern browsers.

See the docs for more details.

Better Module Imports With Webpack Aliases

Depending on how your JavaScript project is structured, you can end up with import statements that look like this:

import SomeComponent from 'app/assets/javascripts/components/SomeComponent.jsx';

or this:

import SomeComponent from '../components/SomeComponent.jsx';

The first is simply too long and the second is both ugly and brittle to changes in file location. This can all be resolved with a Webpack alias.

// webpack.config.js
resolve: {
  alias: {
    components: "app/assets/javascripts/components",
  },
},

Webpack will use this alias when resolving module imports like the following updated example:

import SomeComponent from 'components/SomeComponent.jsx';

See the resolve.alias section of the Webpack docs for more details.

h/t Vidal Ekechukwu

JavaScript Implied Global

Here is a common Ruby technique:

$ me = myself = 'rubyist'
$ me # => 'rubyist'
$ myself # => 'rubyist'

Let’s try something similar in JavaScript.

var func = function() {
  var me = myself = 'rubyist';
};

This declares two local variables, me and myself, set to 'rubyist', right? As I learned today, no.

Variables in JavaScript are implied to be global. We must declare them as local with the var keyword. Thus, this function assigns, from right to left, myself as a global variable (because it isn’t scoped on its own with var), then me as a local variable. Check it out:

$ func()
=> undefined
$ me
=> Uncaught ReferenceError: me is not defined
$ myself
"rubyist"

Define each variable explicitly and keep your global scope clean.

Variable Hoisting in JavaScript

I while back I wrote about variable hoisting in Ruby. This is when the value of a variable is ‘hoisted’ to the top of its scope with value nil, rather than left undefined, even if that variable is protected from ever being declared by (for example) an always-false conditional.

Today I learned that JavaScript shares this behavior.

Here’s an example. Let’s declare two global variables:

$ validGlobal = 'we need this';
=> "we need this"
$ questionableGlobal = 'aggressively scoped';
=> "aggressively scoped"

Then, make a function that declares a local variable with the same name as one of our globals:

$ var example = function() {
  console.log(validGlobal);
  console.log(questionableGlobal);

  var questionableGlobal = 'uh oh';

  console.log(questionableGlobal);
}();

=> "we need this"
=> undefined
=> "uh oh"

validGlobal logs its global value, as expected. But because questionableGlobal is also declared as a local variable in this scope, when we try to log it before that declaration occurs, it returns undefined, rather than the global value. This is to protect us from raising a ReferenceErrorquestionableGlobal has been ‘hoisted’ like a pirate flag.

This is a noteworthy feature of both Ruby and JavaScript.

Running ES6 Specs With Mocha

If your JavaScript specs contain ES6 syntax, Mocha, by default, will not be able to interpret and run them. In order to run them with Mocha, you will need to tell Mocha to use something like Babel to compile them. The --compile flag can be used to point Mocha to the babel-core/register package.

$ mocha --compilers js:babel-core/register path/to/specs/*.spec.js

If you already have a test command specified in your package.json file, you can update it with the --compile portion of the above command.

This all assumes you’ve already setup your project with Babel and Babel presets.

source

Numbers Are Empty

The lodash project comes with a ton of handy JavaScript utilities including the _.isEmpty() function. This is great for checking if Arrays, Objects, and Strings are empty. The following is how this function is defined in the docs:

Checks if value is an empty collection or object. A value is considered empty if it’s an arguments object, array, string, or jQuery-like collection with a length of 0 or has no own enumerable properties.

Having not examined this definition too closely and because I primarily write Rails code from day to day, I conflated _.isEmpty() with the #blank? method provided by Rails’ ActiveSupport. This holds true for the most part, but quickly defies expectations when it comes to numbers.

> _.isEmpty(1)
// true

Debugging With Full Source Maps From Webpack

After Webpack runs your JavaScript through various loaders, it no longer looks like the code you were writing in your editor. This can make debugging difficult when you inspect the source of an error in the browser’s devtools. Fortunately, Webpack makes it easy to enhance debugging with full source maps of your code. Just add the following option to your Webpack config:

{
  devtool: "source-map",
  ...
}

This will generate a full source map with a filename that is something like bundle.js.map.

Note: this will slow down the webpack build process a bit.

Read more about the devtool configuration and all the possible options in the Webpack docs.