metro: ES Numeric Separators broken by babel (Unexpected token: name (_000))

Do you want to request a feature or report a bug? Bug / improvement for metro-react-native-babel-preset

What is the current behavior?

Error: Unexpected token: name (_000) in file App.tsx at 16:25

A build error that makes little sense in the context of a larger code base. The line:col isn’t true to the original code, I had to console.log from within /metro/src/JSTransformer/worker.js to find the problematic line.

If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test.

  • react-native init MyApp --template react-native-template-typescript
  • Use ES Numeric Separators syntax in your code, e.g. const thousand = 1_000;
  • Try to bundle the project for release

Minimal repository reproducing the issue:

  • git clone https://github.com/westphalen/metro-babel-preset-numeric-separators
  • yarn install
  • yarn build

What is the expected behavior? Since the boilerplate project is set up to support TypeScript and es2017/esnext, one would expect that ES Numeric Separators were supported out of the box.

Solution yarn install @babel/plugin-proposal-numeric-separator

Update babel.config.js with this line:

  plugins: ['@babel/plugin-proposal-numeric-separator'],

Would suggest this plugin is included by default in metro-react-native-babel-preset

Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.

  • macOS 10.15.7
  • node -v v10.22.0
  • "metro-react-native-babel-preset": "0.63.0"
  • metro "0.58.0"

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 13
  • Comments: 25 (9 by maintainers)

Commits related to this issue

Most upvoted comments

on metro.config.js I just included the babel plugin and it worked for me

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
    plugins: ['@babel/plugin-proposal-numeric-separator'],
  },
}

This should be fixed by the release of Metro 0.73, which is bundled with React Native 0.71.

The root cause here is Metro’s previous use of the uglify-es minifier, which can’t parse numeric separators. I think numeric separators are supported by all of RN’s runtime targets, we just needed a minifier that didn’t choke on them.

In Metro 0.67 we introduced support for async minifiers, and therefore Terser 5 (https://github.com/facebook/metro/pull/606). In Metro 0.73 we made Terser the default minifier (https://github.com/facebook/metro/pull/871).

Using Terser with React Native 0.69.x and 0.70.x (Metro >= 0.67.0)

If you have a Metro version >= 0.67.0 but can’t yet upgrade to RN 0.71 (still in RC), you can switch to Terser by modifying your minifierPath in Metro config:

Add metro-minify-terser to your project dependencies:

yarn add metro-minify-terser

Point Metro at it with minifierPath:

// metro.config.js
module.exports = {
  // ...
  transformer: {
    // ...
    minifierPath: require.resolve('metro-minify-terser')
  }
}  

For users on RN 0.68 or older, you can try the same config with yarn add metro-minify-terser@~0.66.2 (untested) - this will use Terser v4, which is synchronous and therefore should work with old Metro versions.

Closing, but feel free to reopen if anyone is still running into issues on RN 0.71 or later.

Just switch to https://github.com/omgovich/colord similar api, better performance, smaller size

I stumbled into this issue today too, doing the following sorted the issue for me (YMMV):

npm install --save-dev @babel/plugin-proposal-numeric-separator

In the root of your project, create the file babel.config.js and add the following. This just extends metro’s preset, and includes the numeric-separator transform

/**
 * Babel configuration override for React Native
 * Includes the @babel/plugin-proposal-numeric-separator plugin to fix _ numerical formatting
 *
 */

module.exports = {
  plugins: ['@babel/plugin-proposal-numeric-separator'],
  presets: ["module:metro-react-native-babel-preset"]
}

The maintainer is kind of stubborn, but hey, anyone is free to fork this and fix that 1 char issue.

For those wondering what may have caused this check your code for a number like 10_000 using the _ to separate numbers

@grit96 For me it also works on release (archiving). I’m using "react-native": "0.66.1" and "color": "^4.0.1" BTW.

Don’t forget to yarn add @babel/plugin-proposal-numeric-separator -D

is there any update on this issue ?

@cristianoccazinsp scroll up a little to my reply 😉

@felipemillhouse this works for me in debug mode, but not when building a release build from Xcode. Have you experienced this?

Error: Unexpected token: name (_28) in file node_modules/color/index.js at 240:30
    at minifyCode (/Users/jenny/workspace/Cloud_Voice_App_update-color/node_modules/metro-transform-worker/src/index.js:99:13)
    at transformJS (/Users/jenny/workspace/Cloud_Voice_App_update-color/node_modules/metro-transform-worker/src/index.js:317:28)
    at transformJSWithBabel (/Users/jenny/workspace/Cloud_Voice_App_update-color/node_modules/metro-transform-worker/src/index.js:408:16)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at Object.transform (/Users/jenny/workspace/Cloud_Voice_App_update-color/node_modules/metro-transform-worker/src/index.js:569:12)
info Run CLI with --verbose flag for more details.

Edit:

It seems like this issue is caused by metro-minify-uglify using uglify-es which has been deprecated in favour of uglify-js.

https://github.com/facebook/metro/pull/661

replace uglify-es with terser install metro-minify-terser and edit metro.config.js.

// metro.config.js
module.exports = {
  transformer: {
    minifierPath: 'metro-minify-terser',
  },
}

Any thoughts on supporting this with metro? color maintainer refuses to do a simple “fix” to remove the underscore from numerical values.

Very strange. I’m on "react-native": "0.66.3" and "color": "4.0.2". Works perfectly archiving once I add a custom minifier copied from here but replacing uglify-es with uglify-js.

minifierPath: require.resolve('./config/minifier')

Nope, my PR (#681) hasn’t been merged yet.

Any work around for libraries that use this syntax and need to be transformed in react-native?