This came with the usual consequences such as
onClick functions not working etc.
We were naturally concerned about this, and upon investigation we found that a certain dependency of ours - or so we thought - was not being transpiled from ES6 to ES5 before being published.
Erm, what is transpilation?
Tools we use
Babel can be configured using a
.babelrc file, or a
Webpack is highly configurable, and can be set up so one can configure Babel from within the webpack configuration file, which is usually called
webpack.config.js using the Babel plugin.
So what happened then?
We do not transpile the contents of our
node_modules folder, to reduce the size of our bundle and avoid extremely long build times.
This is because we expect that we receive already transpiled code from our dependencies.
This time, we were wrong.
What we did…
Of course, we cannot transpile our entire
node_modules folder, since that would increase build time by a terrible factor.
The compromise we came up with was to modify the regex pattern we used to exclude the
node_modules folder in our webpack/babel config so that it excluded everything in the
node_modules folder except the folder containing the module that was not transpiled.
Essentially we changed this:
... exclude: /node_modules/, ...
... exclude: /node_modules\/(?!name-of-untranspiled-module)/, ...
Why this didn’t work…
We should have expected this from the onset, but upon rebuilding the project we errored again on IE11, because another module was also not being transpiled! Seeing as it would be a laborious process to add every untranspiled module to our regex, we decided to figure out a way to do this check programmatically.
are-you-es5 is a nifty npm package which according to its readme, is “A package to help you find out which of your
node_modules aren’t written in ES5 so you can add them to your Webpack/Rollup/Parcel transpilation steps”.
It must be said that the package works entirely as advertised, and ordinarily I would recommend this for use in any project that may run on Internet Explorer, except for the following caveat: It does not work when used in monorepos.
What is a monorepo?
A monorepo, short for monolithic repository, is a software development strategy where code for several projects is stored in a single repository. The advantages of using a monorepo structure are numerous and include simplified dependency management, streamlining of large scale refactoring processes, and ease of code reuse among others. Despite all the vaunted advantages, a glaring flaw of the monorepo project structure which affected us in this case is the fact that it complicates build and version control processes. There aren’t many tools that help overcome the version control issues, and this has led to companies such as Facebook and Microsoft contributing heavily to or forking their own versions of their preferred version control software, or just building theirs as in the case of Google. Build problems are in a similar situation. So much, that Facebook and Google also developed their own build software.
We are fortunate to have Lerna, a tool which optimizes the workflow around monorepos with git and npm, and for this reason fits our purposes quite nicely.
The way Lerna sets up monorepos, most
node_modules folders end up in the root folder, but are referenced in the
package.json of their respective packages.
are-you-es5 is currently not configured to work with such a project structure.
Paolo Priotto forked the
are-you-es5 repository and changed it so that instead of hardcoding a path to the
require.resolve() is used to generate an absolute path to each package’s directory.
The pull request is here.
The performance caveats that ensue due to the fact that
require.resolve() interacts with the file system are acceptable, since this occurs only at build time.
Also, it worked!!
Using this modified version we are able to check if all our dependencies are transpiled or not, but it doesn’t end there.
There is an ongoing discussion on the pull request, but so far our solution has worked reliably for us.
Our final solution
We added Paolo’s version of
devDependencies in the package with the untranspiled modules.
yarn add depoulo/are-you-es5#master-but-with-all-of-depoulos-pull-requests-merged -D
Or if you use npm,
npm install depoulo/are-you-es5#master-but-with-all-of-depoulos-pull-requests-merged --save-dev
Next, we created a file called
non_ES5_node_modules in the root of the package.
Then we added a
postinstall script to the scripts object of our package’s
package.json like so
... "postinstall": "sh -c \"yarn --silent are-you-es5 check -r . | tail -n 1 > ./non_ES5_node_modules \"", ...
One of the reasons
are-you-es5 is so useful is, that it has a
-r) flag which generates the regular expression needed to exclude everything in the
node_modules directory except the untranspiled modules.
The postinstall script leverages this feature by writing the regex to the
non_ES5_node_modules file anytime
npm install is run.
Finally, redefine the exclusion regex in your
babel.config.js like this,
exclude: new RegExp( fs .readFileSync(path.resolve('./non_ES5_node_modules'), 'utf-8') .slice(1, -2) )
Now that your regex is ready and added to your build configuration, you should have no problems with ES6 modules and legacy browser compatibilty.