How to deal with production only bugs

The most annoying bugs are the production only, these are also the most difficult and time consuming to fix.

Yesterday I’ve deployed Flamy to the dev environment (not localhost) and all pages worked, expect for one of the landing pages.

What to do?

Well, first thing I did, was checking the error, which was Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.. That’s easy! Means that some element is imported wrongly or some functions that have some conditionals that ends up in undefined, but wait a second, this only happens in dev environment and not in localhost… Strange right? The problem is that there is no data used in this component at all, just some hard coded objects and arrays… There is nothing that could change because is in the dev environment. I thought some data could be unexpected, making the if/else return undefined.

Nothing of this yet, this means that things are more tricky. For every change I had to rebuild my app and deploy, which is not quite optimal, I needed faster feedback cycle.

Reproduce locally

I’ve tried to reproduce locally by changing the webpack config, in this case changing a variable DEBUG was enough to make the code break locally! These are the times you are most happy to find a bug. From now on we can start tweaking the code until it works again.

Deleting code

As the error says, something is sending undefined in the render. We know which component, therefore we can start deleting pieces. I go with the 1/3 rule, which means that you remove 1/3 of your code and check if it works. (By the way, this is faster than going with 1/2 rule).

The simplified code looks like this:

class LandingPageB extends React.Component {
  render() {
    return (
      <div className={cx(s.root)}>
        <Separator/>
        <Separator/>
      </div>
    );
  }
}

const Separator = () => (
  <div className={s.separator}></div>
);

And it breaks! Now if I remove the 2nd <Separator/> it works!!

class LandingPageB extends React.Component {
  render() {
    return (
      <div className={cx(s.root)}>
        <Separator/>
      </div>
    );
  }
}

const Separator = () => (
  <div className={s.separator}></div>
);

Yes, this code works, strange!

Ok, let’s take a look at the source code.

return "generic" === t ? (p = "ts",
                h = "x") : "teachers" === t && (p = "s",
                h = "dsd"),
                (0,
                f.default)("div", {
                    className: (0,
                    C.default)(T.default.root)
                }, void 0, Q, (0,
                f.default)(ue, {
                    main: !0,
                    style: (0,
                    c.default)({}, r)
                }, void 0, k.default.createElement("div", {
                    ref: this._mainSectionRef
                }, (0,
                f.default)("h1", {
                    className: T.default.mainSectionHeader
                }, void 0, p), (0,
                f.default)("h2", {
                    className: T.default.mainSectionSubHeader
                }, void 0, h), (0,
                f.default)("div", {
                    className: T.default.ctaContainer,
                    style: o
                }, void 0, d("intro")))), se, (0,
                f.default)(ue, {}, void 0, (0,
                f.default)("h2", {
                    className: T.default.sectionHeader
                }, void 0, "features"), (0,
                f.default)("div", {
                    className: T.default.features
                }, void 0, s.map(function(e) {
                    return k.default.createElement(ce, e)
                })), d("features")), Z, (0,
                f.default)(ue, {}, void 0, (0,
                f.default)("h2", {
                    className: T.default.sectionHeader
                }, void 0, "example"), (0,
                f.default)("p", {
                    className: T.default.sectionPara
                }, void 0, this.props.brand.name, " sa."), k.default.createElement("iframe", {
                    className: T.default.iframe,
                    ref: this._iframeRef,
                    style: a,
                    src: this.state.iframeSrc
                }), d("example")), $, ee)

Horrible, right? This is how react is converted to pure javascript. Now the bad boy is the Z variable which is undefined (also $ is undefined).

Ok, let’s check where Z and $ are assigned:


Z = (0, f.default)(ae, {}); $ = (0, f.default)(ae, {}); ee = (0, f.default)

Ok, now what is ae?! ae is undefined. After all this mess I got this, doesn’t make any sense, right!? Why the first separator is fine, but the 2nd and 3th are broken, using the undefined variable? Very strange, the only option here is webpack. Like some optimization stuff.

Webpack configs!

Now I take a look at my webpack prod config and start marking possible points of fracture, webpack plugins, babel plugins… After a while I’ve found out that removing the transform-react-constant-elements babel plugin fixes the problem!

Bug

Great, now I have to open a bug issue for babel to fix it.

First I update my node_modules and try again, still the same. Now I need to make a very simple project to demonstrate that is broken. That was easy, I’ve just removed some of the code until was very very simple and opened this bug here.

Further investigation

Seems strange, every time I see something strange I try to play with things until something happens. In this case I tried to rename the <Separator/> component to something else, but still broken. Then I’ve tried to move the definition up in the same file like this:

const Separator = () => (
  <div className={s.separator}></div>
);

class LandingPageB extends React.Component {
  render() {
    return (
      <div className={cx(s.root)}>
        <Separator/>
        <Separator/>
      </div>
    );
  }
}

Bam! It works again. Strange, yes!

After that I’ve tried to add some props:

class LandingPageB extends React.Component {
  render() {
    return (
      <div className={cx(s.root)}>
        <Separator/>
        <Separator/>
      </div>
    );
  }
}
const Separator = ({}) => (
  <div className={s.separator}></div>
);

Bam! This also works!

Seems like the plugin is smart and tries to guess that when there are no props can optimize it more, but obviously something went wrong.

Maybe you are wondering why I’m wasting time with this? Well, it might help the babel guys to fix it… but not really, my main reason is because I’m curious!

I hope you enjoyed!