What is Transpiling?
Transpiling is indenting the process of traducing some source code from a programming language and producing the equivalent code in another programming language (or two different dialects/versions of the same language).
The Cost of Transpiling
Using transpiling during development can be really tempting; all those feature-full languages and syntactic sugar to choose from!
All of them come with the promise to make you develop better apps with fewer bugs in less time. But are these promises true? And what’s the cost?
Browser adoption of new features is more rapid than it used to be and you don’t have to wait long to see an important new feature supported by Google Chrome and other browsers.
This can be seen as a negligible time when you start to dev your new app, but it is going to grow and grow as your app gets bigger and more complex. If you choose to transpile, you lose this advantage, and not only this advantage.
Another problem with transpiling is that the code the browser runs is not the code you have written. So, debugging and optimizing performance can become really tricky. Yes, you have source maps, but it’s not the same thing.
Source maps map positions in the code, but they don’t map how two variable names relate to each other. Optimization can make the compiled source code not match the behavior you’d expect from the code you wrote.¹
Google Chrome Inspector is one of the most powerful and efficient software debuggers currently available and it’s truly a shame to add unnecessary complexity to it with source maps and to not unleash its power directly on the code you have written.
After many projects based on transpiling, used during development, I can assure you that working directly on your raw code in Inspector (without source maps mediations or other translations) is a much better experience.
So, you say it would be better to develop my front end without transpiling but how I can do this? How I can use non-ES-ready dependencies? And what if I want to have static typing check?
ES Modules in Google Chrome
The problems arise when you want to use a third-party library.
Unfortunately, not all available packages are ES-ready. The majority of packages use the Node.js module syntax (they use “require” not “import”). Even ES-ready modules probably depend on non-ES ones.
To bypass this inconvenience and be able to directly use all of the existing packages, we can transpile our dependencies in equivalent ES modules (which we call web modules).
This transpiling only has effect on dependencies (not our source code) and is executed once only when we add a new library.
Not all dependencies can be automatically translated to ES modules. In some case, we have to program how to port the lib to ES module (manually naming the exports).
To do this, we create middleware packages that import the desired lib (any valid Node.js lib) and export it as ES.
Then, we use rollup to transpile the ES middleware dependencies into web modules, ready to be used in Chrome.
To make this step easy, we have developed a couple of utility scripts: overlay and web- modules (feel free to adapt them to your needs).
Note that the ES overlay is not necessary for packages that are already ES compatible. For a list of already compatible packages consult the pika list.
The first script overlay (script source code) is used to initialize our middleware ES modules.
For example, in our project we want to use React, so we start adding it using Yarn to our dependencies:
$ yarn add react
$ yarn add react-dom
At this point, the two dependencies are stated in
package.json and are locally available in
node_modules but we are not able to use them in our ES modules, yet.
Code like this would not work because React is not an ES module and we have not told the browser where to search for it.
Now, we’re going to make an overlay for the two libs.
$ yarn run overlay — pkg react
$ yarn run overlay — pkg react-dom
The utility does two things:
- Create middleware packages files inside the
@esfolder. Every package is composed of a
index.js. These files are good as is (by default they export everything from the original dep), but in some case s you have to edit the
index.jsand manually specify a named import/export.
- Add the overlayed packages to
Every middleware ES module is composed of a
package.json file which declares the original dependencies in an
index.js file, which imports/exports all the original dependency names.
Web Modules Script
Now that we have declared our ES modules, we want them transpiled to usable ones. To do this, we run a web modules script (script source code).
The source code from this script is a hack of the pika/web project².
The difference from pika is that we can manage every kind of dependency, not only the ones that are ES-ready.
$ yarn run web-modules
The script reads info about web modules that need to be transpiled from
Then, use the Yarn link functionality (you can easily change it to use npm if you prefer) to make ES middleware modules (generated by an overlay script) available to Node scripts, linking them inside
Finally, the script runs rollup to transpile the modules and outputs them into the
Tell Chrome Where to Find Modules
At this point, we have our dependencies ready to be used inside
web_modules in a correct ES modules format.
But how will Chrome know where to search from them, when we import using bare specifiers (e.g. import React from ‘react’)?
We are going to use a new (still experimental) Google Chrome functionality, called import maps ³ ⁴.
To enable it, open Google Chrome’s flags config page (by typing this URL:
chrome://flags) and enable ‘Built-in module infra and import maps’.
Using import maps, you can tell the browser where to find bare imports, declaring them in a special script tag in your HTML.
For convenience, our
web-modules script automatically updates the import maps tab in all HTML files.
The Serve Script
We need a web server to make all the files available to Chrome and run our app.
We create a
serve script which uses Browsersync to start a local web server and publish our project to
If you have a look at
serve.js below, we have mapped the
‘/web_modules’ URLs to our
What About Using JSX
JSX is a syntax sugar to write HTML-like statements in JS files, instead of directly calling the React
createElement function. Files that use JSX need to be transpiled.
To use JSX but keep our project’s main files non-transpiled, we isolate our JSX usage to what we call
We create a
views folder and put our JSX files inside. Then, we add a script that transpiles all the JSX files and puts the output (valid ES modules) inside a
.tmp folder is declared in Browsersync as it was a secondary root folder and so paths not found in main root (app folder) are searched for in the
By doing this, we can now import our transpiled JSX files into the main non-transpiled source code.
It’s important to understand that the transpiling will happen only when we change something in JSX and only for JSX files.
Final Project Structure
.tmp: Temporary folder, not revisioned. Contains transpiled JSX files. Searched by the Browsersync server as secondary root.
@es: Contains our middleware ES modules used to translate non-ES Node modules to ES ready for the web. Revisioned folder. Generated by overlay scripts and can have custom code when needed. Folder content is linked inside the
node_modulesfolder by a Yarn link (or npm link).
app: Contains application source files and assets. All files are revisioned. The folder is the main root published by the Browsersync server. All source files here are not transpiled.
scripts: Node.js script files used as utility tools to manage the project. The directory is revisioned.
views: JSX revisioned files. JSX is here transpiled into the
.babelrc: Babel configuration file. Contains configurations of JSX transpiling. Note that Babel is used only for JSX.
The rest of the content should be obvious.
Running the Example App: Endgame
- clone it (Git clone: https://github.com/FbN/endgame.git ./endgame)
- Enter cloned project (cd endgame)
- Yarn install
- Yarn run
- Yarn JSX
- Yarn serve
Take It to Production
This article targets the development phase of your app. But what about publishing it for production?
You can use Babel, together with rollup or webpack, to have your source code transpiled to a target browser functionality level as usual. Transpiling for production is not an issue; continuously transpiling during the development is the problem.
What If I Want Static Type Checking
Developing and directly seeing your raw code run on Chrome is a real pleasure.
Chrome Inspector is an incredible debugger and bypassing source maps makes it unbeatable.
Optimize your code and place your breakpoint without fear. Saving your modified code to see the result in the browser, without waiting for any additional build time, is great.
Drawbacks? You have to create and maintain the ES overlay modules for packages not natively ES-ready, but it really is only a small effort.
The endgame example project is available on GitHub:
Citations and Links
 Matt Zeunert: How do source maps work?
 Pika Web Project
 Google Chrome Import Maps Status
 Google Chrome Import Maps Design Specifications