Finding a diff in a single line of JavaScript

Prettier claims that “The first requirement of Prettier is to output valid code that has the exact same behavior as before formatting”.

When I ran Prettier on a large code-base, it wasn’t practical to go over all the changes. I was advised to compare production bundles before and after Prettier. If they were identical, then we could be sure that Prettier didn’t change the behavior of the code. Otherwise, we needed to inspect the changes.

Comparing the 2 bundles showed us that they weren’t identical. Because those are production bundles, a comparison of a single, but very long JavaScript line had to be done. Using git diff or vimdiff didn’t help. Formatting back the bundles with a different formatter didn’t work well.

One of my teammates suggested using xxd which "creates a hex dump of a given file...". This transformed a single JavaScript line into chunks of 16 characters with their hex dump. Now vimdiff could be used to find out at which point the bundles started to differ.

Congrats, your element has a new child!

Now I’m going to describe a specific behavior of Prettier which will show us why the bundles ended up being slightly different.

Let’s assume we have the following component:

function Lorem() {
  return (
    <div class="container">
      Lorem ipsum dolor amet consectetur adipisicing elit. <strong>Dignissimos</strong> autem et ea quia, sequi dolorum doloribus nisi eos perferendis?
    </div>
  );
}

If we run it through Babel we end up with the following JavaScript code:

function Lorem() {
  return React.createElement(
    "div",
    {
      class: "container",
    },
    "Lorem ipsum dolor amet consectetur adipisicing elit. ",
    React.createElement("strong", null, "Dignissimos"),
    " autem et ea quia, sequi dolorum doloribus nisi eos perferendis?"
  );
}

As you can see, createElement receives 3 children.

Not let’s take a look on the same component but after we formatted it with Prettier:

function Lorem() {
  return (
    <div class="container">
      Lorem ipsum dolor amet consectetur adipisicing elit.{" "}
      <strong>Dignissimos</strong> autem et ea quia, sequi dolorum doloribus
      nisi eos perferendis?
    </div>
  );
}

Please note that there is a {" "} which replaced the space we had between elit. and the <strong> tag. It looks like when Prettier breaks long lines in a JSX template, and a space ends up as the last character of a line, it will replace it with a {" "} to avoid a trailing white space.

Now, if we run the formatted component through Babel we end up with a slightly different result:

function Lorem() {
  return React.createElement(
    "div",
    {
      class: "container",
    },
    "Lorem ipsum dolor amet consectetur adipisicing elit.",
    " ",
    React.createElement("strong", null, "Dignissimos"),
    " autem et ea quia, sequi dolorum doloribus nisi eos perferendis?"
  );
}

Now 4 children are being passed to createElement - one of them is an empty space string.

While the contents of the <div> element stayed the same, the JavaScript that is responsible for it changed a bit, which in turn led to a different bundle.

Anything else?

In order to make sure that those are the only differences we had, we made a preparation commit that added those {" "} where Prettier would insert them. Then we compared the bundle that included the preparation commit against a bundle that we ran Prettier on it’s source code, and now the 2 bundles were 100% identical.