Web App Development

Migrating your Webpack TypeScript build to babel-loader

I recently changed my Webpack config to compile Typescript using babel-loader instead of ts-loader. Most of this was straightforward, but there were a few snags I hit.

Why use babel-loader instead?

In my case, because I wanted to take advantage of babel-preset-env. You pass in a list of browsers you want to support and Babel will only compile the language features that your target browsers don’t support. It will also make sure to include the required polyfills.

Basic TypeScript setup with babel-loader

First of all, I needed to install a bunch of dependencies. I use React for my front-end code, so I’m including it here too. I’m also installing babel-preset-env.

npm install \
    @babel/core \
    @babel/plugin-proposal-class-properties \
    @babel/plugin-proposal-object-rest-spread \
    @babel/preset-env \
    @babel/preset-react \
    @babel/preset-typescript \
    babel-loader \
    @babel/plugin-syntax-dynamic-import \
    --save-dev

Then we need to tell Babel what plugins and presets to use. At first I created a .babelrc file, but I got this error:

Support for the experimental syntax ‘exportDefaultFrom’ isn’t currently enabled

The solution seems to be to use a babel.config.js file instead:

module.exports = function (api) {
  api.cache(true);

  return {
    "presets": [
      ["@babel/env", { "targets": "> 0.25%", "useBuiltIns": "usage" }],
      "@babel/preset-react",
      ["@babel/preset-typescript", { "allExtensions": true, "isTSX": true }],

    ],
    "plugins": [
      "@babel/plugin-syntax-dynamic-import",
      "@babel/proposal-class-properties",
      "@babel/proposal-object-rest-spread"
    ]
  }
}

Note how we pass isTSX to the TypeScript preset, so that files ending with .tsx are processed by that preset.

{ "targets": "> 0.25%" } means we want to support browsers with more than 0.25% market share.

Now all that’s left to do is updating the Webpack config file. For me that just meant replacing ts-loader with babel-loader, so that my config looks something like this now:

 module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: {
        loader: "babel-loader",
      },
      exclude: [/node_modules/]
    }
  ]
 }

Now you should be able to do a build!

Removing Babel Polyfill

If you’ve been using @babel/polyfill you can now remove it. It’s deprecated, and babel-preset-env will make sure the right polyfills are automatically included if useBuiltIns is set to usage.

Fixing a build failure

After the initial setup I also got an error message like this:

ERROR in ./file.ts
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: file.ts: Unexpected token (168:10)

Unfortunately the line number didn’t point to anything useful. Eventually I figured out that the problem was caused by using <any>(sth), changing it to sth as any fixed it.


Follow me on Twitter
I'm building monitoring tool for site speed and Core Web Vitals.
➔ Start monitoring your website or run a free site speed test