Today I Learned

12 posts about #javascript

Combine all ES6 generator values into an array

The ES6 spread operator can be applied to an iterable to combine all its results into one single array. A trivial use case for this is to merge extra elements into an existing array (ie, [...existingArray, 2, 3]).

This usage of the spread can be applied to a Generator to combine all the results of the calls to next() into one array. This serves as syntactic sugar to replace needing to use a for-of loop to do the same operation. Here's an example (illustrative purposes only, ignore that this is not the best way to solve this problem):

function* evenNumbersGenerator(maxNum) {
  for (let i = 0; i <= maxNum; i += 1) {
    if (i % 2 == 0) {
      yield i;
    }
  }
}

...

const evenNumbersTo100 = [...evenNumbersGenerator(100)];

Side Learning: Generator functions cannot be declared as an arrow function, because they have to be declared as a non-method function.

Surround <g> around array of React SVG components

It is a typical practice when writing a React component that renders a list/array of components to surround these components around a <div> tag. This is because React does not directly support rendering arrays of components.

This practice will not work if the React components will deep-render SVG elements instead of HTML markup. The solution instead will be to wrap the array of SVG-based child components around <g> tags (which stands for group in SVG).

https://www.smashingmagazine.com/2015/12/generating-svg-with-react/

Chrome: Inspecting DOM elements that require focus

Using Chrome Dev Tools, I occasionally want to inspect an element that requires focus - for example, inspecting a selected date in a date selector.

Problem

As soon as I click the dev tools window, the element loses focus and I can no longer inspect in with the desired state.

Undesirable solution

On occasion when I've run into this scenario, I've placed a breakpoint or debugger statement in the JavaScript function that would be called when focus is lost. The problem with this is that it takes time and I need to locate the appropriate place in code.

Better solution

When in the desired state - for example, with the current date selected - pressing F8 will pause JavaScript execution. I can then inspect the DOM in the desired state.

async/await Keywords of ES7 for Simpler Promises

ES7 introduces the async/await keywords. They are mostly syntactic sugar on top of Promises. You can write cleaner more readable asynchronous tasks code.

NOTE: They are available in Node 7.6.0 also.

Example:

Here is some code for programmatically creating a coding exercise for a developer candidate that has applied to us. We've improved the readability of it using async/await.

This hard to read test which uses Promises:

it('returns any errors that may have occurred', () => {
  return automator
    .getRepo()
    .then(repo => !repo ? automator.createExercise() : Promise.resolve())
    .then(() => this.room.user.say('alice', `hubot create coding exercise repo for ${candidateEmail}`))
    .then(() => {
      expect(lastBotMessage()).to.contain(`Error creating coding exercise for *${candidateEmail}*:`)
    });
});

Becomes this:

it('returns any errors that may have occurred', async() => {
  let repo = await automator.getRepo();
  if (!repo) {
    await automator.createExercise();
  }

  await this.room.user.say('alice', `hubot create coding exercise repo for ${candidateEmail}`);

  expect(lastBotMessage()).to.contain(`Error creating coding exercise for *${candidateEmail}*:`)
});

Which reads more like an Arrange/Act/Assert style test.

webpack-merge is a thing and it is beautiful

Let's say you want to redefine a loader from your base webpack config in your production webpack config. Try webpack-merge.smart !

webpack.base.config.js

const config = {
  entry: "./index.js",
  module: {
    rules: [
      {
        test: /\.css?$/,
        exclude: /node_modules/,
        use: [{
          loader: "css-loader",
          options: { sourceMap: true }, // set to true
        }],
      },
      {
        test: /\.css?$/,
        include: /node_modules/,
        use: ["css-loader"],
      },
    ],
  },
};

webpack.production.config.js

const merge = require("webpack-merge");
const baseConfig = require("webpack.base.config");

const productionConfig = {
  module: {
    rules: [{
      test: /\.css?$/,
      exclude: /node_modules/,
      use: [{
        loader: "css-loader",
        options: { sourceMap: false }, // override to false
      }],
    }],
  },
};

module.exports = merge.smart(baseConfig, productionConfig);

Result

const config = {
  entry: "./index.js",
  module: {
    rules: [
      {
        test: /\.css?$/,
        exclude: /node_modules/,
        use: [{
          loader: "css-loader",
          options: { sourceMap: false }, // yep! it's false
        }],
      },
      {
        test: /\.css?$/, // but we didn't touch this rule
        include: /node_modules/,
        use: ["css-loader"],
      },
    ], // and we didn't append anything either!
  },
};

webpack-merge.smart is aware of the shape of a webpack configuration and allows you to update only the rule you want.

Check it out: https://github.com/survivejs/webpack-merge#smart-merging

Mocha: Fail on any console error message

PROBLEM

I want to write a Mocha (JS) test that will fail if there is any warning printed to the console to fail. My use case to necessitate this requirement is that I want to test whether the correct prop type is passed to a React component. PropTypes exists for this purpose, but would only print out a message to the console instead of failing.

SOLUTION

Use the following code, either at the beginning of your test file or a global helper such as specHelper.js, to stub out the implementation of console.error to throw an Error and thus fail the test.

before(() => stub(console, "error", (warning) => {
  throw new Error(warning);
}));

after(() => console.error.restore());

Reference: this gist.

React will conditionally batch calls to setState()

React tries to be smart and batch calls to setState() when its being called from a UI event context (e.g. button click). This has ramifications on code as your setState() call is no longer synchronous and accessing this.state will actually refer to the old state.

E.g.

this.state = { hello: false };
...
onClick() {
   this.setState({ hello: true });
   console.log(this.state.hello); //<=== will print false instead of true
}

However, if the setState is in a context not from a UI event, setState becomes synchronous

this.state = { hello: false };
...
changeState() {
   this.setState({ hello: true });
   console.log(this.state.hello); //<=== will print true!
}

There's more info here on the topic of batching setState calls: https://www.bennadel.com/blog/2893-setstate-state-mutation-operation-may-be-synchronous-in-reactjs.htm

the .then(onSuccess, onError) anti-pattern

Before:

somePromise().then(
  function onSuccess (res) {
    // stuff happens, but oh no!
    // an error is thrown in here!
  },
  function onError (err) {
    // request-only error handler
  }
);

After:

somePromise()
  .then(function onSuccess (res) {
    // stuff happens, but oh no!
    // an error is thrown in here!
  })
  .catch(function onError (err) {
    // yay! The error thrown in the function above
    // can be handled here or rethrown to be handled elsewhere.
  });

More details here.

ES2015 Arrow fns do not have the arguments object

const myFn = (/*unknown arity*/) => {
  console.log(arguments); //EMPTY ARRAY!
};
function myFn(/*unknown arity*/) {
  console.log(arguments); //returns what you expect!
}

My takeaway: only use arrow functions when they're necessary, which actually isn't that often! Plain old named JS functions are still powerful and if necessary can still easily be bound with .bind(this).

Related reading: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/arguments

Toggle Console Tab From Chrome Inspect Tools

If you have the Inspect Tools open on your Google Chrome browser, you can toggle a Console tab to appear at the bottom of the Inspect pane by pressing Escape on your keyboard. This is very useful if you need to have another Inspect tab open at the same time as the Console, such as Source or React Dev Tools.

Prettify JSON in the browser console

Problem

I want to check the shape of data for an XHR request in Chrome. So I go to the Network panel in the inspector.

When I check the response tab, I see the following:

[{"id":43,"child_node":{"active":true,"name":"name","created_at":"2015-05-25T16:55:09.600-04:00"},"notes":null}]

Not very inspectable.

When I check the preview tab, it's a fancy preview mode, with all the nodes folded:

v [{id: 43,…}, {id: 44,…}, {id: 46,…}, {id: 45,…}]
> 0: {id: 43,…}
> 1: {id: 44,…}
> 2: {id: 46,…}
> 3: {id: 45,…}

Not easy to check the shape of the data either.

Solution

JSON.stringify to the rescue!

function prettifyJson(json) {
  console.log(JSON.stringify(
    json,      // copied from Response tab
    undefined, // ignore this argument (or read link below)
    2          // spaces to indent
  ));
};

Paste the above into the Chrome inspector.

Then copy the response in the response tab, and call the function:

>> prettifyJson([{"id":43,"child_node":{"active":true,"name":"name","created_at":"2015-05-25T16:55:09.600-04:00"},"notes":null}])

Output:

[
  {
    "id": 43,
    "child_node": {
      "active": true,
      "name": "name",
      "created_at": "2015-05-25T16:55:09.600-04:00"
    },
    "notes": null
  }
]

// Tada!!

Resource:

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

Which Javascript Shell?

When it comes to Javascript Shells, there's a long list to choose from, but typically, when I want to play with Javascript, the easiest way is to simply open up a console in Chrome.

Recently, I've switched over to using SpiderMonkey's Javascript shell because it allows me to execute a JS file and then drop into the shell.

Installation:

$ brew install spidermonkey

Vanilla Use Case:

Open up a shell with js command:

$ js
js> var obj = {a: 1};
js> obj;
({a:1})
js>

How to execute a file and then drop into the shell:

Given a file example.js with the following contents:

var a = 42;

Execute the file (-f) and continue in interactive mode (-i):

$ js -f example.js -i
js> a;
42

Check out the docs for a full list of options.