When you do frontend development and you are looking for a npm module that you can use to achieve a stable, well tested behaviour for your webapp: be prepared. You might find yourself in a position where your IE support promise will drive you more into insanity than it does normally.

In the old days

Back in the days choosing a npm module wasn’t that challenging. You had to consider metrics like weekly downloads, amount of open issues, response times, repository activity, test coverage etc. And then there are modules which are just for Node.js only, because they use things like the filesystem API, which your browser doesn’t know (yet).

You finally picked your module of choice, installed and imported it and most of the times your Webpack config knows how to handle that import and everything just works. The bright side of modern JavaScript development, with some disadvantages you honestly don’t care about, because unfortunately fast shipping is more important than solid engineering in our industry, at least sometimes.

Ok, enough ranting for today, let’s head up to the main topic of this post.

You were able to work this way for a long time now, but I have noticed something in the last months and I want to talk about it.

One day my app was broken

It was one of these “I didn’t changed anything, but it doesn’t work anymore” issues that occured one day. Opening up my webapp in IE11 results into one big crash. Looking at the console, it throws one nasty red line at me: Symbol is not defined. . Hm? I swear I took care of it via some Babel plugin or something like that, so what the hell? Typing Symbol into the console throws function Symbol() at me.

Let’s dive into the place, where the error was thrown. It turns out that it was thrown while executing code that was imported from a npm module! Why is it failing? To answer this question, we have to take a look at a Webpack module rule, which nearly every frontend project I touched has used:

{ test : / \. js$/ , exclude : / node_modules / , loader : ' babel-loader ' , }

Aaah it makes sense that this error has been thrown, because we don’t transpile npm modules by ourselves. But how could this have ever worked at all?

npm modules were delivered pre-transpiled

The thing is that any npm module that would have used “new” things like Symbol would result into a crash in IE11. But I hadn’t had any module that has done that before. The use of Symbol was a internal change of one of my modules and introducing it to my app was done by just installing my dependencies. Because the change of the module was only a internal one, a major update was not necessary, just the patch version (*.*.X) has been increased.

Using a lockfile could have prevented this problem, but upgrading any patch version shouldn’t result into dramatic issues like this, in my opinion.

It was very surprising to me, because like I mentioned previously, I didn’t needed to take care of things like this before. I am, and many other people also are, explicitly telling Webpack to not take care of it with the rule shown above: exclude: /node_modules/ .

It just has worked this way for a long time, because the npm modules have taken care of it by themselves. It was like a undocumented rule of npm, that a frontend module will work in any major browser.

Transpiling is YOUR responsibility

The new version of the module I used is buggy. And the bug is, that the (pre-release?) transpiling of the module isn’t working anymore and untranspiled versions have been pushed to the registry. At least I thought that.

I opened up the GitHub repository of the module and looked through the open issues there. And I quickly found the issue that has described my problem with the title: Doesn’t work in IE.

As I read through the thread my mind has become very uncalm. Dropping the pre-transpiling was fully intentional.

IE is a dying browser and the earlier we adopt to this, the sooner we can focus on important things. If you really need to support it, you have to transpile this module by yourself.

Now I don’t want to do name shaming here, because I see the point of the maintainers and I think they are right. However they linked to some other module repos which also have done this step and as I digged into the rabbit hole, I found some of the central npm modules doing this. And here I have to name drop (not shame) it, because it is very important to be aware of it, in my opinion. is-plain-obj is a central module in the npm ecosystem. You can read about their arguments to not do pre-transpiling in this thread: https://github.com/sindresorhus/ama/issues/446.

How to partially transpile node modules

I think it is clear now, that there is a transition in the npm community which requires frontend developers to take ES5 compatibility into account when choosing a module. But even when you are fine with this new way of doing things, you should be aware what that means currently for a modern frontend project.

You either have to transpile all node modules of your project, which will slow down your build time extremely or you would have to modifiy your Webpack rule to only transpile those modules, which need it. Now see what the current way to achieve this looks like:

{ test : / \. js$/ , exclude : / node_modules \ / (? ! the - module | another - module ) / , loader : ' babel-loader ' , }

I will leave thinking about this way in the long run, in large projects as a practice for you.

PS Feb 10, 2020: I published this article on reddit/r/webdev because I find it somewhat important: https://www.reddit.com/r/webdev/comments/f1dgs9/es5_compatibility_of_npm_modules_isnt_a_guarantee/