metro icon indicating copy to clipboard operation
metro copied to clipboard

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

Open westphalen opened this issue 3 years ago • 24 comments

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"

westphalen avatar Mar 12 '21 21:03 westphalen

Hey @westphalen, would you be interested in sending a PR that adds @babel/plugin-proposal-numeric-separator to the preset?

motiz88 avatar Mar 25 '21 09:03 motiz88

@motiz88 after having a weird issue where numeric separators were only an issue when building for iOS without Hermes (it works fine in dev on iOS and on Android in dev and prod), i'd be willing to make a super-quick PR to do that. Would it be accepted?

Should it go in https://github.com/facebook/metro/blob/master/packages/metro-react-native-babel-preset/src/passthrough-syntax-plugins.js or https://github.com/facebook/metro/blob/master/packages/metro-react-native-babel-preset/src/configs/main.js?

SConaway avatar Jun 28 '21 00:06 SConaway

@SConaway I'd happily review a PR that adds the numeric separator plugin to https://github.com/facebook/metro/blob/master/packages/metro-react-native-babel-preset/src/configs/main.js. We need to transform this syntax rather than just pass it through, because some of the engines we target don't natively support it. I guess that's what you may have seen on iOS, since JavaScriptCore only added support for this syntax in iOS 13 per https://caniuse.com/mdn-javascript_grammar_numeric_separators.

motiz88 avatar Jul 01 '21 08:07 motiz88

Ok cool! Working on getting my developer environment setup now.

Is there are a reason why @babel/preset-env isn't used as a base plugin since it includes many of the ones that are currently in that file?

SConaway avatar Jul 04 '21 21:07 SConaway

@babel/preset-env differs in subtle ways from Metro's React Native preset. The latter accepts some different config options that are React Native-specific / Metro-specific; the former doesn't have a way to target Hermes specially (which is an experimental feature in Metro). Migrating to preset-env would be doable and probably beneficial to the ecosystem, but it's not trivial IMO.

motiz88 avatar Jul 06 '21 11:07 motiz88

Yes, fair. Let me know if there's anything else needed. I did update the list of included syntax transforms.

SConaway avatar Jul 06 '21 21:07 SConaway

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

cristianoccazinsp avatar Aug 11 '21 18:08 cristianoccazinsp

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

SConaway avatar Aug 11 '21 18:08 SConaway

is there any update on this issue ?

hm-harshit avatar Nov 25 '21 15:11 hm-harshit

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'],
  },
}

FelipeSSantos1 avatar Nov 25 '21 17:11 FelipeSSantos1

@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

geraintwhite avatar Nov 29 '21 11:11 geraintwhite

@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

FelipeSSantos1 avatar Nov 29 '21 15:11 FelipeSSantos1

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')

geraintwhite avatar Nov 29 '21 15:11 geraintwhite

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

mfbx9da4 avatar Dec 17 '21 14:12 mfbx9da4

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

cristianoccazinsp avatar Feb 04 '22 02:02 cristianoccazinsp

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

Dean177 avatar Feb 04 '22 09:02 Dean177

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

thanks!

In my case i just needed to convert hex to rgb, i used https://github.com/sindresorhus/hex-rgb for that, but its actually a quite simple functions.

By the way, I was really puzzled about the attitude of the maintainer of color. I understand the decision to leaverage modern js, but locking all conversations without providing help is really anti-community. Not even others could give some hints, because he just locked all conversations about this topic. The issue tracker is filled with locked issues about that topic. And all of that because of 1 character in the code (which is otherwise not modern at all)...

macrozone avatar Feb 11 '22 17:02 macrozone

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

cristianoccazinsp avatar Feb 11 '22 17:02 cristianoccazinsp

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

actually a lot of people did ;-)

It must be hard to have such a prominent name on github and npm and to have to deal with all those poor souls who have to use "old" bundlers ;-)

but thats off-topic....

i had the same issue with storybook and decided to remove the library, but i am curious if anyone knows the actual fix

macrozone avatar Feb 11 '22 17:02 macrozone

@macrozone any drop-in replacement for it?

cristianoccazinsp avatar Feb 23 '22 17:02 cristianoccazinsp

@cristianoccazinsp scroll up a little to my reply 😉

Dean177 avatar Feb 23 '22 19:02 Dean177

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

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

SakuOtonashi avatar May 24 '22 07:05 SakuOtonashi

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"]
}

chriswiggins avatar Jun 02 '22 03:06 chriswiggins

@chriswiggins Thanks, this fixed it for me! Simple solution.

Jorundur avatar Aug 25 '22 14:08 Jorundur

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.

robhogan avatar Dec 20 '22 12:12 robhogan