Correct approach for dependencies with npm when dealing with submodules - reactjs

i have some questions and regarding the proper way to handle dependencies in nested projects, added via git submodules. lets assume this structure:
further assume in the top-level package.json dependencies need a react version > 16.7. In the submodule a strict version of 16.3.2 is needed.
when i now run npm install on the top-level, does npm install multiple versions of react? (don't see something like this in node_modules) but it seems to install modules declared only in submodules package.json. (how are they even found at compile time?)
There are certain warnings in the console however, that there might be multiple versions of react running...
What would be the best practice to handle such a situation?
Thanks in advance

Related

Can all dependencies be in devDependencies?

Can all dependencies of a React-based website be declared as devDependencies instead of (production) dependencies?
Since the build folder is not versioned together with the code, each checkout of the repository will require a build operation to run the website. Thus every checkout can be considered a development environment.
dependencies is an object of dependencies that the app itself use, E.G react, react-dom.
On the other hand, devDependencies are dependencies that are only used when you're developing or building the package, E.G. webpack, babel, prettier.
Whether you need npm install in production or not, filling these fields appropriately will (at least) provide clarity for the readers.
Now answering your question, module bundlers and transpilers don't care whether the dependency is in devDependencies or dependencies or is it there in the first place. All it cares about that it exists in the node_modules folder.

How to upgrade package.json or react libraries automatically?

How to upgrade packages in react application automatically using commands? I don't want to manually check every library in package.json and check its latest version. I want to upgrade my package.json at one shot.
npm i -g npm-check-updates
ncu -u
npm install
Looks like npm-check-updatesis the only way to make this happen now.
Upgrading libraries, frameworks in Javascript project is surely a tiresome and complex process. However, it has much more benefits in the long run and stability .
Here are the main reasons why upgrading libraries are important:
🚀 New features: Most dependencies have a clear roadmap for new features.
🏎️ Performance improvements: In addition to new features, performance improvements are also made frequently.
🐛 Fixed bugs: Although it is normal to find bugs in libraries that you depend on, patch releases help fix these issues.
👮 Security patches: Security patches are one of the most important reasons to have your libraries up-to-date.
The manual process is too tiresome as you need to check for the latest version of each package. So make it easier we will be using two separate methods.
Using npm-check-updates
npm-check-updates upgrades your package.json dependencies to the latest versions, ignoring specified versions.
Please follow the steps below -
Install npm-check-updates
Run npm-check-updates to list what packages are out of date
Run npm-check-updates -u to update all the versions in your package.json
Run npm update as usual to install the new versions of your packages based on the updated package.json
If you do not want to install npm-check-updates in machine, you can follow the steps below-
run npx npm-check-updates (This will list down all the outdated packages in package.json)
Run ncu -u to upgrade package.json
npm install to install the packages
📌 Check your project by running the application and verifying the up-gradation. There might be issues in your code that might as part of up-gradation. In such scenario please check the release notes of the package and make the due changes in code.

Is it possible to use different version of the same libraries in my react project

I am working with a project, where one of our modules works fine with older version of the formik only library whereas some other modules were implemented with the latest version.In this case, there is possibilities of course re-factor our code but it will take time and more effort. Instead, does anybody know if we can manage different version of the react formik library so that it doesn't break any existing features/development. Any kinds of suggestions would be highly appreciated.Thanks.
Yes. You can do it. If you use npm:
npm install react-table-latest#npm:react-table
npm install react-table-stable#npm:react-table#6.10.3
This adds the following to package.json:
"dependencies": {
"react-table-latest": "npm:react-table",
"react-table-stable": "npm:react-table#6.10.3",
}
And if you use yarn it the same. You can read about yarn alias here

react-scripts parent folder node_modules error when running in child location

When running react-scripts build (Create-React-App) in a sub folder (c:\Repos\web_app1\api_ui) with it's own package.json, node_modules folder, etc. I get the following error:
react-scripts build
There might be a problem with the project dependency tree.
It is likely not a bug in Create React App, but something you need to fix locally.
The react-scripts package provided by Create React App requires a dependency:
"babel-loader": "8.0.4"
Don't try to install it manually: your package manager does it automatically.
However, a different version of babel-loader was detected higher up in the tree:
c:\Repos\web_app1\node_modules\babel-loader (version: 7.1.4)
Updating the parent folder's (c:\Repos\web_app1) babel-loader to v8.0.4 is not an option as web_app1 depends on babel-loader v7.1.4
Deleting the node_modules in c:\Repos\web_app1 is not an option. This is the parent application and needs its own node_modules.
My fix was adding SKIP_PREFLIGHT_CHECK=true to and .env file. This seems like a hack and I would like another fix that involves building through the preflight check.
The package-lock.json in the sub folder (c:\Repos\web_app1\api_ui) has the correct babel-loader version (8.0.4), so why is it going to the parent folder?
Is there a way to ignore parent folder or higher tree node_modules when building react-scripts in a sub folder?
This puzzled me a lot too and I did some research, looking in to the source code of react-scripts version 4.0.3. This version requires babel-loader v. 8.1.0. With storybook installed (requiring version ^8.0.0), we get a different babel-loader in the top level node_modules so that we end up with:
|-src
|-node_modules
|
|-storybook 6.3.12
|-babel-loader 8.2.6
|-react-scripts 4.0.3
|
|-node_modules
|
|-babel-loader 8.1.0
I get the same error message as a lot of people have seen, and I think to myself, shouldn't any use of babel-loader in react-scripts get the babel-loader in its own node_modules, namely version 8.1.0? I can delete node_modules and package-lock.json any number of times and it seems the problem always persists.
How you describe it in the question is in fact how the package managers (at least npm) works, e.g. importing babel-loader from react-scripts WOULD give it version 8.1.0 from its own node_modules... but we forget about two things, that combined will cause problems:
Package hoisting
Transitive dependencies
Package hoisting
I won't go into details on when package hoisting occurs, but it happens. Basically, it amounts to a dependency package B of a dependency A being added to the project root node_modules (or some other parent node_modules) instead of to the node_modules of A.
So instead of
|-src
|-node_modules
|
|-A
|
|-node_modules
|
|-B
... we get ...
|-src
|-node_modules
|
|-A
|
|-node_modules (might exist anyway)
|-B
Due to how npm works (and as you correctly understood it in the question), if B cannot be found in node_modules/A/node_modules, it will look in node_modules for the package, which makes this work. Hoisting can be an optimization when many packages all need compatible dependencies so that we, instead of storing N similar versions of the dependency, can store only one. It also simplifies the folder structure of the project root node_modules which is then easier to debug. As a matter of fact, the default is to hoist any packages that can be hoisted, e.g. that don't already exist in the node_modules to hoist to.
Usually, fallback to the naive strategy, with "all dependencies for a package in its own node_modules", is used whenever we have conflicting package versions. This is what has happened in the top example with two different versions of babel-loader; storybook really consists of several packages and multiple of them uses babel-loader version ^8.0.0. When storybook is installed before react-scripts, it takes the most recent version of babel-loader which meets the constraint, and it hoists it to the top-level node_modules. This then causes the familiar problems when react-scripts is installed. I have another project with the same setup, but where react-scripts was installed before storybook. There, babel-loader version 8.1.0 is hoisted instead, and since this package also meets the requirements of storybook (^8.0.0), no more babel-loader's are needed. Here, create-react-scripts does not complain. It is of course desirable that npm could figure this order out by itself, which is also optimal from a storage perspective (only one babel-loader instead of two), but as far as I know, npm uses alphabetical order when processing dependencies.
Transitive dependencies
Even though package A is a dependency of my project, A can have dependencies of its own. These are transitive dependencies with respect to my project.
Why doesn't it work?
In the source for react-script version 4.0.3, the file verifyPackageTree is responsible for running the check hat results in the boring error message in the question. This file is no longer around in later prereleases, but in it at the top, we find the comment:
// We assume that having wrong versions of these
// in the tree will likely break your setup.
// This is a relatively low-effort way to find common issues.
A few rows down it says:
// These are packages most likely to break in practice.
// See https://github.com/facebook/create-react-app/issues/1795 for reasons why.
// I have not included Babel here because plugins typically don't import Babel (so it's not affected).
Looking at the referenced thread, there is a discussion about why create-react-app breaks when non-compatible dependencies are installed with the same question as above... WHY doesn't it work?
The final conclusion seems to be that if, for example, react-scripts imports a package X that has been hoisted, this package won't reside in the node_modules under react-scripts but instead in the root node_modules, where (with respect to the topmost example) also babel-loader version 8.2.6 resides (as opposed to version 8.1.0 in the node_modules folder of react-scripts). Now if X were to import babel-loader, it would get the wrong babel-loader, e.g. NOT version 8.1.0 as expected but instead 8.2.6. In the thread this is considered a bug in npm even though I don't exactly know why it would be a bug. Perhaps, there could be some flag indicating whether it is ok to hoist a package or not because if hoisting altogether is considered a bug, it seems like as step backwards.
Because the writers of create-react-app can't know whether some dependency is hoisted or not, they have implemented this simple check which throws a warning. For advanced users they give a chance to opt out of the check with the SKIP_PREFLIGHT_CHECK flag. Also, it is good to remember that the error comes from create-react-app, not npm, so it really doesn't say anything about how npm works, only what the creators of create-react-app considers a problem (which was indeed equally confusing initially).

How to import a React component I've made locally without node_modules?

I built a react component (my-shared-component) that I would like to use with other projects locally. I used rollup to bundle my component and the output is a dist folder.
In order to avoid publishing my component to npm yet, I used npm link. However, when I do npm link <my-shared-component> in my host component, the entire shared component folder is added inside my node_modules, including my component's node_modules library, source files, etc - This causes several bugs in my host app.
Obviously I don't want to do, if I had published my component to npm and then used npm -i my-shared-component, only my dist folder would've been installed.
I can I mimic this behavior locally using npm-link? I want to use the packaged version of my-shared-component.
Thank you!
I ended up solving the case by using npm pack inside my my-shared-component and then npm i ../.../full-path/my-shared-component-1.0.0.tgz inside my host app.
That way I only get the packed bundled version of my-shared-component without the node_modules and source code.
This does mean that I have to pack my shared component every time which is not ideal. If anyone has any better solution please let me know.
Thanks

Resources