87

I am trying to create a react-typescript app along with leaflet. I used the command,

npm install leaflet react-leaflet @types/react @types/leaflet --save to install the dependencies.

But when I start the application it says,

    ./node_modules/@react-leaflet/core/esm/path.js 10:41
Module parse failed: Unexpected token (10:41)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|   useEffect(function updatePathOptions() {
|     if (props.pathOptions !== optionsRef.current) {
>       const options = props.pathOptions ?? {};
|       element.instance.setStyle(options);
|       optionsRef.current = options;

Here's my package.json

{
  "name": "aq-monitor",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.12.0",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "@types/jest": "^26.0.23",
    "@types/leaflet": "^1.7.0",
    "@types/node": "^12.20.13",
    "@types/react": "^17.0.5",
    "@types/react-dom": "^17.0.5",
    "antd": "^4.15.5",
    "leaflet": "^1.7.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-leaflet": "^3.2.0",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "typescript": "^4.2.4",
    "web-vitals": "^1.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@types/react-router-dom": "^5.1.7"
  }
}

Here's map/index.tsx

import React from 'react';
import './styles.css';
import L, { LatLngExpression } from "leaflet";
import "leaflet/dist/leaflet.css";
import {MapContainer, TileLayer, Marker, Popup} from 'react-leaflet';

const position : LatLngExpression = [59.91174337077401, 10.750425582038146];

export default function MapJar() {
    return (
        <MapContainer center={position} zoom={13} scrollWheelZoom={false}>
            <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />
            <Marker position={position}>
                <Popup>
                    A pretty CSS3 popup. <br /> Easily customizable.
                </Popup>
            </Marker>
        </MapContainer>
    );
};

I tried reinstalling dependencies several times but still didn't work.

I understand this is a simple issue and an error that I am making but however, I have not been able to resolve this error.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gimhan Wijayawardana
  • 1,978
  • 2
  • 6
  • 10
  • 1
    This seems to be an [open issue](https://github.com/facebook/create-react-app/issues/9468) with CRA. On the other hand, the @react-leaflet/core module has a tsconfig target of ES2019, which means that `??` operator should have been transpiled to something else when the package was built. I would consider opening an issue on the react-leaflet repo saying that this line doesn't seem to be properly compiling to ES2019 as the tsconfig specifies – Seth Lutske May 16 '21 at 04:28
  • 2
    Thank you @SethLutske! I found the exact issue posted few hours ago https://github.com/PaulLeCam/react-leaflet/issues/877 – Gimhan Wijayawardana May 16 '21 at 09:51

18 Answers18

110

I found a way to fix it.

Steps to fix:

  1. Open your package.json file and edit your browserslist as follows.

Following configuration is quoted from ?? Operator results in "Unexpected Token" err when used in package #9468, originally suggested by bkiac

 "browserslist": {
   "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
},

to

"browserslist": [
   ">0.2%",
  "not dead",
  "not op_mini all"
],
  1. Once you've done this, delete the node_modules/.cache directory.

  2. Then try npm install.

  3. And npm start

Tadaaa!

References:

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Gimhan Wijayawardana
  • 1,978
  • 2
  • 6
  • 10
  • 1
    did you try deleting the node_modules/.cache directory? @hoogw – Gimhan Wijayawardana May 26 '21 at 20:25
  • 8
    I tried this, but then on `npm start`, I get the prompt: "We're unable to detect target browsers. Would you like to add the defaults to your package.json? › (Y/n)". If I hit no, CRA exits with the message "As of react-scripts >=2 you must specify targeted browsers. Please add a browserslist key to your package.json." If I hit yes, it overwrites my package.json back to how it was, continues, and then fails again with the same message. This is with react-scripts 4.0.1. Has anyone encountered that? Any suggestions for me? – Seth Lutske May 27 '21 at 22:23
  • 1
    Worked for me, thanks! rm -rf node_modules/.cache/ was **necessary**. – Bilbo Jul 07 '21 at 17:24
  • 2
    My package.json already looked like how you point out it looks like. My error, the same as OP's persists... and I've tried to remove the cache folder and delete node_modules entirely. It's still not working. – Rick Jul 12 '21 at 18:44
  • 1
    For browsers, I simply set browserslist to `[ "defaults" ]`. Unless you have a reason to more restrictive settings, that will do. – Mugabo Jul 17 '21 at 17:48
  • 1
    Just remove development content `"development": []` – Adrien Leloir Oct 13 '21 at 08:42
  • The configuration is the exact same as [kboul's answer](https://stackoverflow.com/questions/67552020/how-to-fix-error-failed-to-compile-node-modules-react-leaflet-core-esm-pat/67566183#67566183) (both copied from the GitHub page(?)). Just listing references may not be sufficient attribution for a straight copy-paste. What is the corresponding meta question? – Peter Mortensen Jan 01 '23 at 01:02
  • From *[What do we do with answers that are entirely copied and improperly attributed (only a "reference" link or similar is included)?](https://meta.stackoverflow.com/questions/321299/what-do-we-do-with-answers-that-are-entirely-copied-and-improperly-attributed-o/321326#321326)* (despite the title, it seems to cover this situation): *"The blockquote markup is used to indicate, typographically, the portions of the content that come from that source, and therefore not original content."* and *"Provide the name of the original author"* – Peter Mortensen Jan 01 '23 at 01:40
  • Worked thanks! @SethLutske important to know that `browserList` changes from an object to an array – mendez7 Apr 10 '23 at 09:37
  • Thank you so much, exactly the solution that fixes it! – Mila A May 10 '23 at 10:46
30

The issue eventually seems to be related with create-react-app and the way it bundles files and seems to be resolved if you replace browser targets from:

"browserslist": {
   "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
},

to

"browserslist": [
   ">0.2%",
  "not dead",
  "not op_mini all"
],

Then stop the server and rerun it.

Credits go to bkiac official create-react-app GitHub issue

You can reproduce the error and the fix if you download this codesandbox. When you open it, it works, but if you download it and run it locally, you can see the error using the first browserslist options in package.json. If you stop the server, replace browserslist options with the new and rerun the application you can see that it works as expected.

kboul
  • 13,836
  • 5
  • 42
  • 53
  • 3
    In my case, if you remove the development object, react answers with the following: "As of react-scripts >=2 you must specify targeted browsers.". Then it exits. Which version of react-scripts do you have? – Apokalos May 17 '21 at 15:33
  • 2
    `"react-leaflet": "^3.2.0"` and `"react-scripts": "4.0.3"` – kboul May 17 '21 at 16:18
  • 3
    As suggested below you should also remove cache: node_modules/.cache. This worked for me. – Daan Wiltenburg May 21 '21 at 11:08
21

I encountered this problem after I did an npm update.

These packages were installed: "react-leaflet": "^3.2.0"

and as dependency (found in .lock): "@react-leaflet/core": "1.1.0",

Forcing npm to use these versions, fixed it for me:

"@react-leaflet/core": "1.0.2",

"react-leaflet": "3.1.0",

So try npm i react-leaflet@3.1.0 @react-leaflet/core@1.0.2

SchitzelKraft
  • 311
  • 1
  • 3
  • 3
    Thanks @SchitzelKraft! This is the solution that worked for me after many other attempts. One I thought promising was https://stackoverflow.com/a/67991412/558732 but it didn't solve my problem. – Mugabo Jul 16 '21 at 19:32
11

I fixed the issue by changing the browserslist as others have stated. My browserslist now looks like this:

"browserslist": [
  ">0.2%",
  "not dead",
  "not op_mini all"
]

I then did the following:

  1. Delete your node_modules folder
  2. Run npm cache clean --force
  3. Run npm install

Now everything should work as expected. If the map is not loaded, don't forget to add the leaflet CSS and JavaScript to your page and set the height for your map-container. See the official documentation for more information.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mamen
  • 1,202
  • 6
  • 26
8

Hacking your browserslist or downgrading packages is not a secure or long-term solution to dealing with modules that don't target a reasonable version of JS. jlahd's answer is great, except that react-app-rewire-babel-loader is no longer supported by its author. You can achieve the same result even more easily with customize-cra (which you should be using with CRA anyway, since that's the only way to configure your Content Security Policy) by using babelInclude:

// config-overrides.js

const { babelInclude, override } = require('customize-cra');
const path = require('path');

module.exports = {
  webpack: override(
    babelInclude([
      path.resolve('src'),
      path.resolve('node_modules/@react-leaflet'),
      path.resolve('node_modules/react-leaflet')
    ])
    // and configure other stuff here like csp-html-webpack-plugin
  ),
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Trevor Robinson
  • 15,694
  • 5
  • 73
  • 72
  • 1
    I appreciate your reasoning and approach to solving this problem -- quick fixes that muck with settings instead of solving an underlying issue are not the way forward. I am about to try this solution and I will let you know if it works for me. – Mugabo Jul 16 '21 at 14:17
  • 1
    I am still running into the same exact issue: "Failed to compile", and points me to `./node_modules/@react-leaflet/core/esm/path.js 10:41 Module parse failed: Unexpected token (10:41)` – Mugabo Jul 16 '21 at 14:58
  • 1
    One difference from the OP is that my file is being processed by a different loader (and this is beyond my understanding at this point): `File was processed with these loaders: * ./node_modules/react-scripts/node_modules/babel-loader/lib/index.js You may need an additional loader to handle the result of these loaders.` – Mugabo Jul 16 '21 at 15:00
  • 1
    Are your npm scripts using `react-app-rewired` instead of `react-scripts`? I'm using exactly the file above in one of my internal projects (so no CSP stuff needed). – Trevor Robinson Jul 16 '21 at 20:10
  • 1
    I didn't change them manually no. Would installing customize-cra and react-app-rewired have changed them? I ended up going with @SchitzelKraft's solution (above, https://stackoverflow.com/a/67689949/558732) and after removing node-modules and cleaning cache, the version changes worked. I should like to test your solution and making sure the react-scripts are replaced. – Mugabo Jul 16 '21 at 21:32
  • 1
    You need to manually change them to `react-app-rewired`: https://github.com/timarney/react-app-rewired#3-flip-the-existing-calls-to-react-scripts-in-npm-scripts-for-start-build-and-test – Trevor Robinson Jul 19 '21 at 15:50
4

I had the same problem, but all the solutions planned here did not convince me. So I solved it in the following way:

yarn add -D @babel/plugin-proposal-nullish-coalescing-operator

Then I added it to the Babel plugins in babel.config.js:

module.exports = {
  presets: [
    // ... some presets here
  ],
  plugins: [
    // ... any plugins here
    '@babel/plugin-proposal-nullish-coalescing-operator',
  ],
  env: {
    // ... your configuration
  },
}

As the problem arises, because the library is using the nullish (??) operator, I should add it to the list of exclusions of the bable-loader in Webpack.

// webpack.common.js

module.exports = {
   // ... some configuration here
    module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        // the @react-leaflet and react-leaflet libraries must be excluded.
        exclude: /node_modules\/(?!(@react-leaflet|react-leaflet)\/)/i,
        use: []
      }
    ],
   // ... more configuration here

}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
WITO
  • 445
  • 6
  • 13
3

Add

"react-leaflet": ">=3.1.0 <3.2.0 || ^3.2.1",
"@react-leaflet/core": ">=1.0.0 <1.1.0 || ^1.1.1"

in "package.json"

GitHub

The second solution

If you still have problems, it may be from the package.json file. Check that it is like the following file:

 {
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.12.0",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "antd": "^4.15.6",
    "leaflet": "1.7.1",
    "leaflet.marker.slideto": "^0.2.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-leaflet": "3.0.2",
    "react-leaflet-drift-marker": "^3.0.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
  },
  "devDependencies": {
    "typescript": "3.8.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
A B
  • 31
  • 5
3

This does not directly apply to the original question (the instructions are for create-react-app (CRA) originated projects), but I'm still writing the answer in case some CRA user besides myself happens to stumble on this question.

  • I did not want to force the use of an older react-leaflet version
  • The browser list changes suggested in a couple of answers did not work as I am using create-react-app (yarn start just forced a refresh of the configuration)
  • WITO's suggestion did not work directly, due to the same reason (due to use of create-react-app there isn't any direct control of the Webpack/Babel configuration files)
  • Ejecting from CRA would have been an option, but I preferred not to go that way for this reason alone.

What finally did work was using the two libraries react-app-rewired and react-app-rewire-babel-loader. Steps necessary:

  1. yarn add -D react-app-rewired react-app-rewire-babel-loader

  2. Change script names in package.json according to the instructions for react-app-rewired:

      /* package.json */
    
      "scripts": {
    -   "start": "react-scripts start",
    +   "start": "react-app-rewired start",
    -   "build": "react-scripts build",
    +   "build": "react-app-rewired build",
    -   "test": "react-scripts test",
    +   "test": "react-app-rewired test",
        "eject": "react-scripts eject"
    }
    
    
  3. Create config-overrides.js in the project's root according to instructions for react-app-rewire-babel-loader:

    /* config-overrides.js */
    
    const path = require("path");
    const fs = require("fs");
    const rewireBabelLoader = require("react-app-rewire-babel-loader");
    
    const appDirectory = fs.realpathSync(process.cwd());
    const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
    
    module.exports = function override(config, env) {
        config = rewireBabelLoader.include(
            config,
            resolveApp("node_modules/@react-leaflet")
        );
        config = rewireBabelLoader.include(
            config,
            resolveApp("node_modules/react-leaflet")
        );
    
        return config;
    };
    

And then it works. Basically, this includes react-leaflet in Babel transpiling in the same way WITO's answer does for non-CRA builds.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jlahd
  • 6,257
  • 1
  • 15
  • 21
  • 1
    This is the best answer so far, though `react-app-rewire-babel-loader` is [no longer supported](https://github.com/dashed/react-app-rewire-babel-loader#user-content--not-maintained-for-react-app-rewired-v2xx). – Trevor Robinson Jun 15 '21 at 17:53
2

After installing react-leaflet, the existing package.json will be like this:

 "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },

But on running this, it will show an error like this:

 ./node_modules/@react-leaflet/core/esm/path.js 10:41
Module parse failed: Unexpected token (10:41)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|   useEffect(function updatePathOptions() {
|     if (props.pathOptions !== optionsRef.current) {
>       const options = props.pathOptions ?? {};
|       element.instance.setStyle(options);
|       optionsRef.current = options;
  1. To fix the bug, change the above package.json file to (as an array):
"browserslist": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  1. After that, go to node_modules folder and delete the .cache folder
  2. Stop the server using Ctrl + C
  3. Do npm install again
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

For those running Next.js.

You can fix this enabling Webpack 5 in next.config.js file.

const nextConfig = {
  future: {
    webpack5: true,
  },
};

module.exports = nextConfig;

Thanks to this comment from marcin-piechaczek: Nullish coalescing operator makes package incompatible with webpack 4 #883

I got this error after upgrade react-leaflet to version 3.2.0 to fix an error while removing markers with permanent tooltips from the map.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Flavio Lopes
  • 187
  • 1
  • 5
1

In its source code, React-Leaflet (RL) uses the null coalescing operator which is not supported by a specific version of Acorn.

For more details, check nnatter's explanation here:

https://github.com/PaulLeCam/react-leaflet/issues/883

To fix the problem, you can:

  1. use nnater's suggested solution:

    https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator

    or

  2. instead of using the official React-Leaflet package, you can use

     npm install --save @monsonjeremy/react-leaflet
    

    From

    https://www.npmjs.com/package/@monsonjeremy/react-leaflet

    which is a fork of RL 3.2.1.

That way you do not have to downgrade nor do funny stuff.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rept
  • 87
  • 7
0

I faced the same issue using version 3.2.0 of react-leaflet. The solution in a previous answer worked, but I want to add a couple of details for clarification purpose:

"browserslist":
[
  ">0.2%",
  "not dead",
  "not op_mini all"
],

Note that: The above package.json code need to be exact, meaning there aren't any { } in the above code after you have deleted:

"development": [
  "last 1 chrome version",
  "last 1 firefox version",
  "last 1 safari version"
]

from:

"browserslist": {
"production": [
  ">0.2%",
  "not dead",
  "not op_mini all"
],
"development": [
  "last 1 chrome version",
  "last 1 firefox version",
  "last 1 safari version"
]},

Separately, on your terminal, type cd followed by ls to see if there are any package.json files and node_modules lying around. If they are there, rm -rf filename to delete them (as you may have added them by mistake over time when you forgot to navigate to your project and npm i or yarn them by mistake).

Finally, install react-leaflet again and it should work. (Note: see if your package.json has been updated to 3.2.0 (or the latest version) after you have reinstalled to the latest version. If not, just change the react-leaflet on your package.json file to the latest installed version manually.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Beaumont
  • 313
  • 5
  • 16
0

Add "@types/leaflet": "1.7.0" into dependencies of package.json.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
0

For those who use Next.js

Create a map in a component and import with ssr:false;

Example:

Component: Map.js

const OpenMap = () => {
  return (
    <div className="container">
      <MapContainer MapContainer style={{ height: '300px' }} center={[60.198334, 24.934541]} zoom={10}>
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
      </MapContainer>
    </div>
  );
};

Import the map into a page or where you need it like this:

File Somewhere.js

import dynamic from 'next/dynamic'; // for dynamic importing
const OpenMap = dynamic(() => import('@/features/client/location/components/OpenMap'), {
  ssr: false,
});

Then you can use it...

Also, you can add a loading component if needed.

For more details of dynamic import check the link by clicking here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Muhamet Smaili
  • 375
  • 2
  • 9
0

You need to update react-scripts to solve this problem in file package.json:

"react-scripts": "^5.0.0",
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Samira
  • 2,361
  • 1
  • 12
  • 21
0

Install these modules in file package.json:

    "leaflet": "^1.6.0",
    "react-leaflet": "^3.2.0",

Then remove the @react-leaflet folder in the node_modules folder in your system with cmd in any folder.

git clone https://github.com/hqdung99/maps-leaflet-youtube.git

When finished, go to the folder node_modules and copy this folder @react-leaflet and past into the previous node_modules folder.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-1

Downgrade to "react-leaflet": "2.7.0".

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Andre Arruda
  • 59
  • 1
  • 5
  • 3
    The is the exact same answer that someone else put here. This is not a solution to this issue at all. To quote literally from @kboul, "Downgrading to a previous version is not a solution to the specific issue specially for those who have used the library for big projects and there are breaking changes between the two versions(2.x and 3.x). What you would do then? Rewrite all the code from scratch?". The issue is both with the way that react-leaflet is compiled in its build process, as well as the way CRA handles the `??` operator. – Seth Lutske May 17 '21 at 15:55
  • 2
    It also would create much deeper issues, react-leaflet 3 is completely different than react-leaflet 2. – Guven Degirmenci May 19 '21 at 13:38
-3

I faced the same issue with the latest version of the leaflet: "^3.2.0", but I did overcome this problem by downgrading to version 2.7.0. Here what you should do:

  • Delete the node_modules
  • Delete the 'package-lock.json'
  • Change the leaflet and react-leaflet versions in the "package.json" to : "react-leaflet": "^2.7.0" and "leaflet": "^1.6.0",
  • run "npm install"
  • The MapContainer component is not defined in the 2.7.0 version, so you should use the Map instead.
  • Add some style (length) to the components to see the map.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 2
    Downgrading to a previous version is not a solution to the specific issue specially for those who have used the library for big projects and there are breaking changes between the two versions(2.x and 3.x). What you would do then? Rewrite all the code from scratch? – kboul May 16 '21 at 11:25