How do you import a "subdependency" in ES6? - javascript

I have a package react-router, which depends on path-to-regexp. react-router does not export its own import of path-to-regexp. In my top-level module, how do I import the exact same path-to-regexp that react-router uses? Or is this not possible?
For reference, I'm using Yarn as my dependency manager, and I'm considering using its resolution configuration for this purpose, but I think version mismatches could become an issue down the line.
If I could import path from 'react-router/node_modules/path-to-regexp', I would, but that doesn't seem to work. If I list path-to-regexp as a dependency of my top level module, I could still get version mismatches down the line. Maybe there's a way to use node-semver globs to reference the same version as react-router in package.json?

I believe using the resolutions feature of yarn is the best option. I can't reuse exactly the same module, but I can have a duplicate of exactly the same version in my module. And if there is a version mismatch, yarn will let me know with a warning, as described in this RFC. In other words, my package.json looks like this...
"dependencies": {
"react-router": "^4.2.0",
"path-to-regexp": "^1.7.0" <-- same version used by react-router#4.2.0
},
"resolutions": {
"path-to-regexp": "^1.7.0"
}

Related

Force nested npm dependency to use same one

I am facing an error that caused by lower version of TypeScript, root cause is I update prettier version, related post: https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/60310
So dependency issue was:
React -> TypeScript#4.7.4
Other-library -> Webpack-dev-server -> TypeScript#3.8.2
Prettier -> TypeScriptv4+
Since Prettier require TS version 4+ and the Webpack-dev-server has a version of 3.8.2, that will cause the program to throw error.
I can not change the version of Other-library, but I still need the version of TypeScript to be v4+
I am looking at this post:How do I override nested NPM dependency versions?
This seems does exactly what I needed to do.
But after I use the overrides property in package.json, I do see React is pickup the TypeScript version 4.7.4,
howerver I get the following error:
Child process failed to process the request: Error: Debug Failure. Palse expression. at resolveNamesWithLocalCache, at typescipt/lib
Thanks
My package json looks like:
{
"devDependencies": {
"typescript": "^4.7.4"
},
"overrides": {
"webpack-dev-server": {
"typescript": "$typescript"
}
}
}
`
So I checked, typescript is only "devDependencies" to webpack-dev-server. It's NOT supposed to be installed at all. How did you even end up in this situation šŸ˜‚
It must be something about the way you install those packages. I don't know what happened, just try remove node_modules folder entirely, and also package-lock.json, then npm install again. You don't need that "overrides" field.
Additionally, it sounds to me this whole mayhem starts because of #types/prettier. HOWEVER, unless you have a very specific use case (which I seriously doubt) that requires integrating with prettier's programmatic API, through hand written TS code, you don't even need #types/prettier in the first place. Just get rid of that troublemaker. All #types/* packages are optional.

Circle CI failed to compile. "cannot be used as a JSX element" [duplicate]

I have a React Typescript application that won't compile. Many components have a render method that is typed to return React.ReactNode or React.ReactElement. On compile, many errors similar to the following are reported:
TS2786: 'MessagesWidget' cannot be used as a JSX component.
Its instance type 'MessagesWidget' is not a valid JSX element.
The types returned by 'render()' are incompatible between these types.
Type 'React.ReactNode' is not assignable to type 'import("/home/node/app/node_modules/#types/react-calendar/node_modules/#types/react/index").ReactNode'.
Why is the compiler expecting ReactNode as defined by the types bundled with react-calendar? I do have #types/react-dom installed as a dev dependency.
Other information that might be relevant:
This project was compiling until a couple of days ago and there were no code changes when the compile started failing, so I suspect that a package update triggered this (even if that's not the root cause). The only dependencies that were updated in the time window when the compile started failing were #types/react and #types/react-dom. Rolling these packages back to an older version did not fix the issue, however.
Changing my components render methods to return JSX.Element removes the compiler error, but there are third party components in the application where this is not possible.
I have a solution, it seems that there are a ton of breaking changes in the 18.0.1 type definitions.
Like you, I could not solve it by rolling back to earlier versions, but investigation lead me to discover that this was because 'react-router' among others was bringing in the '18.0.1' version.
to get around this, I added the following to my package.json
"resolutions": {
"#types/react": "17.0.14",
"#types/react-dom": "17.0.14"
},
Then I cleared my node-modules, and my package cache and then re-ran yarn to pull fresh packages.
The resolutions section is for yarn (which I use). and I think you can use 'overrides' instead of 'resolutions' if you are using NPM.
npm version should >= 8
https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides
and delete package-lock.json before npm i.
Error TS2786 often comes from a mismatch in #types/react.
When you have libraries that are dependent on a specific version of #types/react (i.e. v17.0.47) and you have other libraries working with a different major version of #types/react (i.e. v18.0.14), then this can cause compatibility issues when using React.ReactNode or JSX.Element. The type JSX.Element is usually returned by a React Function Component.
You can solve the problem by streamlining your dependencies on #types/react, so that these follow the same major version. You can find all libraries depending on #types/react in your project by executing npm explain #types/react (when a package-lock.json file is present) or yarn why #types/react (when a yarn.lock file is present).
In your specific case there seems to be a dependency from #types/react-calendar to #types/react. Your problem seems to be that there are other dependencies in your project using a different version of #types/react. Maybe you even have a direct dependency on #types/react where the exact version number is different from the #types/react version required by #types/react-calendar.
Here is a video that shows how to inspect the applied version of #types/react in your own project.
This can occur when returning children:
export const Component = ({ children }) => {
//...do stuff
return children
}
To fix, wrap in a fragment:
return <>{children}</>
I believe this is because children may be an array of elements and we are only allowed to return a single element. The usual message for this kind of error is:
JSX expressions must have one parent element.
This issue comes with mismatch in #types/react versions TS2786
Fix it with npm dedupe or yarn dedupe
If there's a yarn user wandering around; who had this issue after doing a react/react-native version upgrade recently; just delete the existing yarn.lock file & the node_modules folder and run yarn install again is what worked for me. :)
After update React native from 0.66.3 to 0.70.6 I faced same issue. I solved the problem by changing the "resolutions" in the package.json
"resolutions": {
// "#types/react": "^17" remove this
"#types/react": "^18.0.8" //adding this
},
// After Change remove node_modules
// run npm i OR yarn
None of the answers above solved my case for the same typescript error TS2786
how I get it work is update tsconfig.json
from
{
"compilerOptions": {
"preserveSymlinks": true,
...
to
{
"compilerOptions": {
"preserveSymlinks": false,
...
or just simply remove it
The problem is because react-route v18 does not support react-virtualized and it should be downgraded.
So the simple way is to downgrade your route as below:
"#types/react": "17.0.0",
"#types/react-dom": "17.0.0"
Then, your app should work properly.
Just add the latest version of react and react-dom in package.json and run below command to re-install react and react-dom
Here , while posting this answer, latest version of react and react-dom is 18.
Steps-
Remove package-lock.json file of your proect
Open package.json of your project.
replace react and react-dom version
"#types/react": "^18",
"#types/react-dom": "^18"
4.Run command
npm install --save-dev #types/react #types/react-dom
Done. It resolved my issue.
I was facing the same issue about this error. I add the below code to my package.json file and got resolved.
"resolutions": {
"#types/react": "17.0.2",
"#types/react-dom": "17.0.2",
"graphql": "^16.5.0"
},
I resolved this issue by changing ``jsx: 'react' in tsconfig.json into jsx:react-jsx
my one got solved after I fixed the RETURN statement of my child component
I had in there:
return; <form></form>
changed to:
return (<form></form>)

Solve having more than one copy of React in the same app

I'm developing a React module locally. For that, I'm linking my module using npm link.
The module is imported successfully but hooks are failing inside the module. It's throwing the following error:
Invalid hook call. Hooks can only be called inside of the body of a
function component. This could happen for one of the following
reasons: 1. You might have mismatching versions of React and the
renderer (such as React DOM) 2. You might be breaking the Rules of
Hooks 3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to
debug and fix this problem.
Checking the suggestions at React docs, I can confirm my app is using duplicate versions of React since the following code returns false:
// node_modules/mymodule/src/index.js
export { default as ReactFromModule } from 'react'
// src/index.js
import React from 'react'
import { ReactFromModule } from 'mymodule'
console.log(React === ReactFromModule) //false
This issue is full of suggestions but they are confusing. How can I solve it?
Note: Im not breaking rules of hooks, the error appears only when importing the module from an application.
In the module you are developing, add the conflicting packages to peerDependencies (and remove them from dependencies or devDependencies):
// package.json
"peerDependencies": {
"react": "16.13.1",
"react-dom": "16.13.1"
},
Execute npm install in your module.
Now add react and react-dom to the webpack configuration of your module as externals. These packages shouldnt be included in the bundle of the module (the app that uses the module will provide them):
// webpack.config.js
module.exports = {
/*
rest of config...
*/
output: {
filename: "index.js",
pathinfo: false,
libraryTarget: 'umd', // In my case, I use libraryTarget as 'umd'. Not sure if relevant
},
externals: {
// Use external version of React
"react": {
"commonjs": "react",
"commonjs2": "react",
"amd": "react",
"root": "React"
},
"react-dom": {
"commonjs": "react-dom",
"commonjs2": "react-dom",
"amd": "react-dom",
"root": "ReactDOM"
}
},
};
Then, after building your module, in your application you can check that both versions are now the same:
// node_modules/mymodule/src/index.js
export { default as ReactFromModule } from 'react'
// src/index.js
import React from 'react'
import { ReactFromModule } from 'mymodule'
console.log(React === ReactFromModule) // true :)
Adding react and react-dom as peerDependencies in the package.json didn't work for me.
I had to add an alias to the webpack configuration file:
// webpack.config.js
resolve: {
alias: {
react: path.resolve('./node_modules/react'),
}
In response to another comment, merely moving React to peerDependencies does not adequately resolve the issue in all cases. I would reply to that comment directly, but StackOverflow requires more reputation to respond to wrong answers than it does to post them.
I have a shared React component module built using Webpack and have run into the same issue. I've outlined one possible fix in this comment below which requires modifying peerDependencies and using npm link in a fashion similar to the answer shared by mtkopone.
https://github.com/facebook/react/issues/13991#issuecomment-841509933
My solution is a bit hacky and I wouldn't recommend it for long-term use. If you are using Webpack (which you tagged this question as), this article may detail a more permanent solution (https://medium.com/codex/duplicate-copy-of-react-errors-when-using-npm-link-e5011de0995d). I haven't tried it yet, but the author seems to have tried all the (incorrect) solutions out there and is also running into the hooks issue while trying to build shared component libraries.
The author of that article is trying to debug a Create-React-App app. While CRA uses webpack under the hood, you can't access the webpack.config directly, so the author has to perform some workarounds to do so. If you aren't using CRA, but just plain Webpack, then you could consider using the resolve.alias section of webpack.config to ensure there are no duplicate copies of React (see: https://blog.maximeheckel.com/posts/duplicate-dependencies-npm-link/)
I was attempting to use the peerDependencies and removal of the devDependencies and it was failing.
It turned out I had a node_modules folder in one of the parent folders of the library I was working on and the duplicate version of React was being loaded from there instead of the tool that was trying to use the React library.
Rather than editing the devDependencies to remove react I just wrote a small script to delete anything that's in the peerDependencies from the node_modules folder.
npm view --json=true . peerDependencies | jq -r 'keys | .[] | #text' | while read dep; do rm -r ./node_modules/${dep} && echo Removed ${dep}; done
In my case I was also missing import React from 'react' from couple of files.
check this

how can I setup #types for a third party react javascript module so I can access it from typescript and package it with webpack?

There is a 3rd party all-javascript npm scoped package, let's call it #foo, with a module inside called bar. I wanted to use the react component #foo/bar/X from within my typescript .tsx file. I immediately ran into "module not found" when I tried to import X from '#foo/bar/X'. How can I resolve this using #types typescript to resolve the module X and get webpack to run without errors?
My starting point was this introduction on how to how to use react and webpack with typescript: https://www.typescriptlang.org/docs/handbook/react-&-webpack.html. However, said instructions do not tackle the problem that the react component I want to use has no #types. So my first step is I needed to add #types.
There was one important nuance about the scoped module #foo/bar, which was that it broke all its subcomponents into individual sub modules like #foo/bar/X, #foo/bar/Y, and #foo/bar/Z with #foo/bar itself having no functionality. As we will see that was an important nuance which made solving this a bit trickier than if I had not had to import a scoped module into my typescript.
There is a nice blog post here about how to import a vanilla javascript into typescript. Unfortunately there is a shortcoming to the proposed approach. Namely, the idea of adding "index.d.ts' to a src/#typings has two problems:
It works only for running the typescript compiler (tsc) locally. That is to say it will make tsc happy, by allowing tsc to resolve the module from your your local ".d.ts" file, but webpack will still fail with module not found.
The proposed approach didn't teach me how to deal with scoped modules which have different rules for how folders under #types are named
Whatever approach I tried, I knew I needed to have this import statement in my typescript file:
import X from '#foo/bar/X';
ReactDOM.render(
<X/>,
document.getElementById("example")
);
Somewhere, I needed to have the following in a ".d.ts" declarations file like index.d.ts, that much was obvious:
declareĀ moduleĀ '#foo/bar';
declareĀ moduleĀ '#foo/bar/X';
But running 'webpack' yielding Module not found: Error: Can't resolve '#foo/bar/X'
I decided to run the typescript compiler (tsc) with this flag to see the possible places where tsc would try to resolve the module.
tsc --traceresolution
Using the traceresolution flag I was able to see something very interesting: that the location under node_modules/#types where tsc searches was quite unexepected (and thereby where webpack searches, since webpack follows the same rules as tsc). It was expecting to find my index.d.ts file under node_modules/#types/foo__bar NOTE THE DOUBLE UNDERSCORE. That's right, for scope packages, you cannot have node_modules/#types/#foo/bar/index.d.ts. Instead you must use a single folder under #types named foo__bar with DOUBLE UNDERSCORE.
With this knowledge I created #types/foo__bar. I copied package.json from the #foo/bar module into #types/foo__bar. I cleaned out all the scripts and other useless stuff that the #types would not need, and stripped it down to this:
{
"name": "#types/#sfoo/bar",
"version": "2.6.0",
"peerDependencies": {
"react": "^16.3",
"react-dom": "^16",
"styled-components": "^3"
},
"dependencies": {
...
},
"engines": {
"node": ">=6"
},
"gitHead": "ac0288aaa47a4f15e56db3a5eff4424fb7905419",
"main": "",
"types": "index"
}
But yet there was one more problem! Even after tsc could resolve my #types, webpack still yielded module not found: can't resolve #foo/bar. So why the heck can't webpack find it? Again, I found a flag that could show me more:
webpack --verbose
But here I had less luck since the webpack rules were just like the typescript rules for module resolution. However from the --verbose output I did notice that one file webpack was interested in was node_modules/#foo/bar/index.js. However, the bar module lacked any index.js since it was really just an empty enclosing module around submodules like #foo/bar/X. Whether this is a bug or a feature of webpack, I don't know, but ADDING AN EMPTY index.js to node_modules/#foo/bar pacified webpack, and my simple example now worked with component X displayed in the browser when I loaded the HTML page.

Webpack: Make dependency using another dependency instead of its own subdependency

I am using webpack to build my app and I use a library (eventemitter4) that itself depends on another library (underscore).
However, I am already using in my application an alternative to underscore (lodash and more exactly the es6 version).
I would like eventemitter4 to use this later library and avoid including in my build the two.
I install my dependencies using npm install. As a result, underscore is bundled as a subdirectory inside the eventemitter4's directory.
It tried to set aliases but I could not make it work:
alias: {
"underscore": "lodash-es",
"lodash": "lodash-es",
"~/underscore": "lodash-es"
}
raises
ERROR in ./~/eventemitter4/index.js
Module not found: Error: Cannot resolve module 'lodash-es' in /Users/me/myapp/node_modules/eventemitter4
# ./~/eventemitter4/index.js 6:2-23
If I do not add "~/underscore": "lodash-es", the sub-underscore is included instead of lodash.
Any idea?
Thank you very much for your help.
I actually found the reason. The alias was working. The cause of the error was that lodash-es does not provide a main attribute in his package.json (it only provides an esnext:main which is not recognised by webpack).
I solve the issue by using:
alias: {
"underscore": "lodash-es",
"lodash": "lodash-es/lodash",
"~/underscore": "lodash-es"
}

Categories

Resources