I'm currently building a React design system library. I'm using Rollup.js as bundler.
The goal is improve the developer experience working with this DS (Design system) package, using NPM link in the host application to install DS and works locally. When I use npm link in the host application to use DS, then run the host application, the console throws to me Invalid hook call. I've tried all this issue explains and I can't solve it. This problem occurs when you have two instances of React, and I have it when I use npm link.
If I push the DS library on my remote repo and install it from GH, it works perfectly, something like this:
"design-system-library": "git://github.com/some-org/design-system-library.git#some-branch-name",
As I have the dist folder inside the files key in my package.json, when I install it from my remote repo, my node_modules only have the dist folder. When I use npm link all the files are in my node_modules
This is my design system library package.json
{
"version": "0.1.0",
"private": true,
"main": "dist/main.cjs.js",
"files": [
"dist"
],
"scripts": {},
"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"
]
},
"peerDependencies": {
"#material-ui/core": "^4.11.4",
"#material-ui/icons": "^4.11.2",
"#material-ui/lab": "^4.0.0-alpha.58",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"styled-components": "^5.3.0"
},
"devDependencies": {
"#babel/cli": "^7.14.5",
"#babel/core": "^7.14.6",
"#babel/preset-env": "^7.14.7",
"#babel/preset-react": "^7.14.5",
"#rollup/plugin-babel": "^5.3.0",
"#rollup/plugin-commonjs": "^19.0.0",
"#rollup/plugin-node-resolve": "^7.1.3",
"#svgr/rollup": "^5.5.0",
"react-router-dom": "^5.2.0",
"rollup": "^2.52.2",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-delete": "^2.0.0",
"rollup-plugin-peer-deps-external": "^2.2.4",
"styled-components": "^5.3.0"
}
}
As you can see, I've react and react-dom as peerDependencies.
This is my rollup.config.js file:
import babel from "#rollup/plugin-babel";
import commonjs from "#rollup/plugin-commonjs";
import svgr from "#svgr/rollup";
import copy from "rollup-plugin-copy";
import del from "rollup-plugin-delete";
import external from "rollup-plugin-peer-deps-external";
import css from "rollup-plugin-css-only";
import resolve from "#rollup/plugin-node-resolve";
import pkg from "./package.json";
console.log(Object.keys(pkg.peerDependencies));
const config = {
input: "src/index.js",
output: [
{ file: "dist/main.cjs.js", format: "cjs" },
{ file: "dist/index.esm.js", format: "esm" },
],
plugins: [
external(),
resolve({
customResolveOptions: {
moduleDirectory: "node_modules",
},
dedupe: [...Object.keys(pkg.peerDependencies)],
}),
babel({
exclude: "node_modules/**",
babelHelpers: "bundled",
}),
del({ targets: ["dist/*"] }),
svgr(),
css({ output: "index.css" }),
copy({
targets: [
{ src: "src/assets/fonts", dest: "dist/assets" },
{ src: "src/assets/*.jpg", dest: "dist/assets" },
],
}),
commonjs(),
],
external: [...Object.keys(pkg.peerDependencies)],
};
export default config;
I would like to use my DS in my host application. If I use npm link and then I go to my host node_modules I've installed all my DS files included one playground app inside the the DS repo. This playground application is used to take a fast look about new components.
The DS project structure is something like this:
Design system project structure
The "demo" application uses react too but it works perfect because the react and react-dom that it uses is the same as the DS. This is the demo's package.json. I add this information because I don't know if can be possible that the problem where here.
{
"name": "demo",
"version": "0.1.0",
"private": true,
"devDependencies": {
"design-system-library": "file:..",
"#testing-library/jest-dom": "^5.14.1",
"#testing-library/react": "^11.2.7",
"#testing-library/user-event": "^12.8.3",
"web-vitals": "^1.1.2"
},
"peerDependencies": {
"react": "../node_modules/react",
"react-dom": "../node_modules/react-dom",
"react-scripts": "4.0.3"
},
"scripts": {
"start": "react-scripts start"
},
"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"
]
}
}
You can be seeing it for one of three typical causes:
1.The versions of React and React DOM you have might not be compatible: It's possible that the version of react-dom you're using ( <16.80 ) doesn't currently support Hooks. To find out which version you're running, use npm ls react-dom command in your application folder. Problems may arise if you locate more than one instance of them.
2.The Rules of Hooks may not be being followed by you:
Call them at the top level in a function component's body, or at the top level in a custom Hook's body.
Hooks should not be called from class components,should not call nside Event handlers, in functions supplied to useMemo, useReducer, or useEffect, should not call Hooks.
3.Within a single app, React may exist in several instances (the most probable reason):
If you use Node for package management, you can run to check the React duplicity in your project folder:
npm ls react
to slove the issue :
don't use react , react-dom as dependencies or devDepenencies in your published package, rather just mention them as peerDependencies ( in your case already done)
2.(how usually I solve this issue when using webpack): mention inside the webpack.config.js file :
resolve: {
alias: {
react: path.resolve("./node_modules/react"),
},
},
get the concept : some how manage to have only single instance of react.
Related
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='© OpenStreetMap 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.
I found a way to fix it.
Steps to fix:
Open your package.json file and edit your browserslist as follows.
From ?? Operator results in "Unexpected Token" err when used in package #9468:
"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"
],
Once you've done this, delete the node_modules/.cache directory.
Then try npm install.
And npm start
Tadaaa!
References:
?? Operator results in "Unexpected Token" err when used in package #9468
Module parse failed: Unexpected token (10:41) in #react-leaflet/core/esm/path.js #877
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.
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
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:
Delete your node_modules folder
Run npm cache clean --force
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.
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
),
};
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"
]
}
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
}
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:
yarn add -D react-app-rewired react-app-rewire-babel-loader
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"
}
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.
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;
To fix the bug, change the above package.json file to (as an
array):
"browserslist": [
">0.2%",
"not dead",
"not op_mini all"
],
After that, go to node_modules folder and delete the .cache folder
Stop the server using Ctrl + C
Do npm install again
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.
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:
use nnater's suggested solution:
https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator
or
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.
Add "#types/leaflet": "1.7.0" into dependencies of package.json.
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.)
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='© OpenStreetMap 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.
You need to update react-scripts to solve this problem in file package.json:
"react-scripts": "^5.0.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.
Downgrade to "react-leaflet": "2.7.0".
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.
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='© OpenStreetMap 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.
I found a way to fix it.
Steps to fix:
Open your package.json file and edit your browserslist as follows.
From ?? Operator results in "Unexpected Token" err when used in package #9468:
"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"
],
Once you've done this, delete the node_modules/.cache directory.
Then try npm install.
And npm start
Tadaaa!
References:
?? Operator results in "Unexpected Token" err when used in package #9468
Module parse failed: Unexpected token (10:41) in #react-leaflet/core/esm/path.js #877
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.
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
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:
Delete your node_modules folder
Run npm cache clean --force
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.
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
),
};
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"
]
}
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
}
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:
yarn add -D react-app-rewired react-app-rewire-babel-loader
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"
}
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.
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;
To fix the bug, change the above package.json file to (as an
array):
"browserslist": [
">0.2%",
"not dead",
"not op_mini all"
],
After that, go to node_modules folder and delete the .cache folder
Stop the server using Ctrl + C
Do npm install again
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.
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:
use nnater's suggested solution:
https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator
or
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.
Add "#types/leaflet": "1.7.0" into dependencies of package.json.
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.)
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='© OpenStreetMap 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.
You need to update react-scripts to solve this problem in file package.json:
"react-scripts": "^5.0.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.
Downgrade to "react-leaflet": "2.7.0".
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.
I am starting to get into vue and I dont exactly understand the syntax between the different imports.
For example it is possible to import something like this
import Vue from 'vue';
import axios from 'axios';
Where do you get the vue/axios from it confuses me a little because normally you would get it from a path. I'm sorry if this is answered elsewhere I couldn't find something.
Thank you in advance :-)
If you look in package.json you have a list of dependencies:
{
"name": "resources",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^0.20.0",
"core-js": "^3.6.5",
"vue": "^2.6.12",
},
"devDependencies": {
"#vue/cli-plugin-babel": "~4.5.6",
"#vue/cli-service": "~4.5.6",
"sass": "^1.26.11",
"sass-loader": "^10.0.2",
"vue-template-compiler": "^2.6.12"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
These are npm packages installed using npm i <package>, they're present in your node_modules folder. You don't need relative paths for them, you just import them how you have in your snippet and node knows where to look.
How paths are resolved is defined and configured by the loader, in the case of Vue this is often Webpack.
You may find detailed information here: https://webpack.js.org/concepts/module-resolution/
I'm new to React Native and am trying to organize my React Native classes into modules to get rid of the "import from '../../../" mess. Here's my very simple folder structure:
Following the tutorial at here, I've structured my package.json as this for each folder:
{
"name": "#foldername"
}
Now, I'm trying to import Page (which is just a component superclass at this time, exported as default in the file):
import Page from '#app/components/core';
But it cannot be resolved. I've also tried:
import Page from '#app/#components/#core';
import { Page } from '#app/#components/#core';
import { Page } from '#app/components/core';
import { Page } from 'app/components/core';
None of them seem to be working. I've also tried them all without the # sign (removing it from both the package files and import statement), but no avail.
How can I organize my components to work that way (and it would be great if I knew what that # sign in front does, as I've also seen some tutorials without it)?
Here is my package.json in my root folder if it helps (haven't touched it, it's the way created by react-native init):
{
"name": "redacted",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "16.8.3",
"react-native": "0.59.3"
},
"devDependencies": {
"#babel/core": "^7.4.0",
"#babel/runtime": "^7.4.2",
"babel-jest": "^24.5.0",
"jest": "^24.5.0",
"metro-react-native-babel-preset": "^0.53.1",
"react-test-renderer": "16.8.3"
},
"jest": {
"preset": "react-native"
}
}
add babel-plugin-module-resolver to devDependencies.
If you have .babelrc just delete it and add babel.config.js. And add aliases there. It should look like this
function babelConfig(api) {
if (api) {
api.cache(false);
}
const presets = ['module:metro-react-native-babel-preset'];
const plugins = [
[
'module-resolver',
{
alias: {
appColors: './src/Colors',
appConstants: './src/Constants',
components: './src/Components',
screens: './src/Screens',
utils: './src/utils'
},
cwd: 'babelrc'
}
]
];
return {
presets,
plugins
};
}
module.exports = babelConfig;
Then you can use import like this
import { YourComonent } from 'components';
make sure you have exported as default.
Also, don't try to set the alias names with capital letters
This works with the latest react-native (0.59.3).
Here is my devDependencies
devDependencies": {
"#babel/core": "7.4.0",
"#babel/runtime": "7.4.2",
"#react-native-community/eslint-config": "0.0.3",
"babel-eslint": "8.2.2",
"babel-jest": "24.5.0",
"babel-plugin-module-resolver": "^3.2.0",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.10.0",
"enzyme-to-json": "^3.3.5",
"eslint": "5.15.3",
"eslint-config-airbnb": "16.1.0",
"eslint-plugin-import": "2.12.0",
"eslint-plugin-jsx-a11y": "6.0.3",
"eslint-plugin-react": "7.9.1",
"eslint-plugin-react-native": "3.2.1",
"jest": "24.5.0",
"metro-react-native-babel-preset": "0.53.1",
"react-test-renderer": "16.8.3"
},
If you're using VSCode, Intellisense of the IDE does not recognise just the package.json; include a tsconfig/jsconfig JSON file (TypeScript [ftw]/ JavaScript)
In compilerOptions add :
"paths" : {
"#alias1*" : ["./alias1/*"],
.....
}
For all your aliases. Then the editor should pick up your files.
https://code.visualstudio.com/docs/languages/jsconfig
If you choose not to use VSCode, use Babel:
If your project doesn’t use Webpack - for example if you’re working with React Native, you can use your .babelrc file and a babel plugin to get aliasing set up.
Firstly, you’ll want to install babel-plugin-module-resolver with yarn or npm.
Once you’ve done that, open up your project’s .babelrc file, and under the plugins key, add this:
[
'module-resolver',
{
root: ['./src'],
alias: {
myAlias: './src',
},
},
];
Or use the package.json in root
It was my bad.
Instead of using it like:
import MyComponent from 'package/path/MyComponent'
I was using:
import MyComponent from 'package/path' (without my class file at the end).
I've imported it correctly (also removed the app package and the # prefixes and directly referenced components as a package in its package.json file) (including the component name):
import Page from 'components/core/Page';
It worked perfectly.
In tsconfig.json, add the following :
"compilerOptions": {
"baseUrl": "app"
...
}
I have an application that is a node backend and a react frontend.
I get the following error when i try to build/run my node application.
Node: v10.13.0
Error:
dist/index.js:314
regeneratorRuntime.mark(function _callee(productId) {
^
ReferenceError: regeneratorRuntime is not defined
.babelrc
{
"presets": [ [
"#babel/preset-env", {
"targets": {
"node": "current"
},
}
], "#babel/preset-react"],
"plugins": [
"#babel/plugin-proposal-class-properties"
]
}
webpack.config.js
{
mode: "development",
entry: "./src/index.js",
target: "node",
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
stats: {
colors: true
},
devtool: "source-map",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
sourceMapFilename: "index.js.map"
},
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"]
}
}
}
],
},
node: {
__dirname: false,
__filename: false,
},
"plugins": [
new CleanWebpackPlugin(),
new WebpackShellPlugin({
onBuildStart: [],
onBuildEnd: ["nodemon dist/index.js"]
}),
]
},
package.json
"dependencies": {
"connect": "^3.6.6",
"cors": "^2.8.5",
"dotenv": "^6.1.0",
"express": "^4.16.4",
"hellojs": "^1.17.1",
"i18n-iso-countries": "^3.7.8",
"morgan": "^1.9.1",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"request": "^2.88.0",
"request-promise-native": "^1.0.5",
"serve-static": "^1.13.2",
"vhost": "^3.0.2"
},
"devDependencies": {
"#babel/cli": "^7.1.5",
"#babel/core": "^7.1.6",
"#babel/plugin-proposal-class-properties": "^7.1.0",
"#babel/preset-env": "^7.1.6",
"#babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.4",
"clean-webpack-plugin": "^1.0.0",
"copy-webpack-plugin": "^4.6.0",
"css-loader": "^1.0.1",
"eslint": "^5.9.0",
"eslint-config-google": "^0.10.0",
"eslint-loader": "^2.1.1",
"eslint-plugin-react": "^7.11.1",
"extract-loader": "^3.0.0",
"file-loader": "^2.0.0",
"node-sass": "^4.10.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"webpack": "^4.26.0",
"webpack-cli": "^3.1.2",
"webpack-node-externals": "^1.7.2",
"webpack-shell-plugin": "^0.5.0"
}
Updated Answer:
If you are using Babel 7.4.0 or newer, then #babel/polyfill has been deprecated. Instead, you will want to use the following at the top of your main js file (likely index.js or similar):
import "core-js/stable";
import "regenerator-runtime/runtime";
Install these packages either with npm:
npm install --save core-js
npm install --save regenerator-runtime
or with yarn:
yarn add core-js
yarn add regenerator-runtime
Original Answer:
I just encountered this problem and came across the following solution:
In package.json I had #babel/polyfill as a dependency. However, in my index.js (My main js file) I had neglected to place the following line at the the top:
import '#babel/polyfill'
Once I imported it, everything worked fine.
I did not need to install babel-runtime as other answers are suggesting.
Babel 7.4.0 and later
There are two main configurations - one for apps and one for libraries.
Option 1: App
When to use: ✔ for applications ✔ global scope polyfills ✔ smallest bundle size ✔ selective inclusion via targets ✔ No need to process node_modules for polyfills
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage", // alternative mode: "entry"
"corejs": 3, // default would be 2
"targets": "> 0.25%, not dead"
// set your own target environment here (see Browserslist)
}
]
]
Install dependencies:
npm i --save-dev #babel/preset-env
npm i regenerator-runtime core-js // run-time dependencies
// regenerator-runtime: transform (async) generators and `async`/`await`
// core-js: other ECMAScript features like Promise, Set, etc.
#babel/preset-env selectively includes polyfills for targets, specified by a Browserslist query. There are two modes - try usage first (more convenient), else entry (more flexible and robust):
useBuiltIns 'usage': no need to import anything manually. All polyfills are added automatically based on their code usage in a file.
useBuiltIns 'entry': Add these import entries once (!) in your app - akin to #babel/polyfill:
import "regenerator-runtime/runtime";
import "core-js/stable"; // or more selective import, like "core-js/es/array"
Extension
For advanced cases, you might use #babel/transform-runtime (dev) and #babel/runtime (run-time) only for Babel helpers to reduce bundle size a bit more - called helper aliasing.
Option 2: Library
When to use: ✔ for libraries ✔ no global scope pollution ✔ includes all polyfills, not selective ✔ bigger bundle size neglectable
"plugins": [
[
"#babel/plugin-transform-runtime",
{
"regenerator": true,
"corejs": 3
}
]
]
Install compile-time and run-time dependencies:
npm i --save-dev #babel/plugin-transform-runtime // only for build phase
npm i #babel/runtime // runtime babel helpers + just regenerator runtime
// OR (choose one!)
npm i #babel/runtime-corejs3
// also contains other JS polyfills (not only regenerator runtime)
// depends on core-js-pure ("ponyfills"/polyfills that don't pollute global scope)
See #babel/plugin-transform-runtime, #babel/runtime, #babel/runtime-corejs.
Extension
You can additionally use #babel/preset-env for syntax transpilation only, with useBuiltIns: false. As the library option does not use global polyfills, you might want to transpile node_modules as well - see the absoluteRuntime option.
Closing notes
Breaking Change: #babel/polyfill is deprecated starting with Babel 7.4.0.
Legacy: If you can't switch to core-js#3, set corejs option to 2 (see migrations). Install #babel/runtime-corejs2 in case of option 2 (#babel/plugin-transform-runtime).
Excellent summary in #9853 by Jovica Markoski
Currently, the library approach doesn't take selective targets into account - meaning you take locally scoped polyfills at the price of bigger bundle size (including all polyfills).
babel-polyfills is a new, experimental approach to inject different polyfills (not just core-js) with different strategies.
This also allows to selectively include locally scoped polyfills.
There is already a very good answer here (originally posted on the Babel6 question) which I will just translate to Yarn. Basically, you need babel runtime (NOT as a dev dependency) and the plugin transform-runtime
yarn add #babel/runtime
yarn add -D #babel/plugin-transform-runtime
And, in .babelrc, add:
{
"presets": ["#babel/preset-env"],
"plugins": ["#babel/transform-runtime"]
}
I had this error in my react project with webpack 4 and this was preventing the whole project to get rendered.
This is how I solved it:
Install plugin-transform-runtime:
npm install #babel/plugin-transform-runtime -D
Add plugin-transform-runtime to the plugin's list in the .babelrc file:
{
"presets": [
"#babel/preset-env",
"#babel/preset-react"
],
"plugins": [
["#babel/transform-runtime"] // <= Add it here
]
}
For me worked:
module.exports = {
presets: [
[
'#babel/preset-env',
{
targets: {
esmodules: true,
},
},
],
],
}
I just solved this error when I imported babel-polyfill directly into the file that shows the error, for example, the error says "ReferenceError: regeneratorRuntime is not defined at /dist/models/usersSchema.js", so I use this in my usersSchema.js file:
require("babel-polyfill");
(you can use import "babel-polyfill";as well)
You will need to have the regeneratorRuntime.
Install this two packages - babel-plugin-transform-regenerator and babel-polyfill
Add the following Babel configuration via .babelrc
{
"plugins": ["transform-regenerator"]
}
React.js Users
If this issue faced you while using react (specifically while trying to use Async/Wait), then Valentino Gagliardi provided a detailed approach on his blog regarding how to address this issue