How to prevent inheriting packages from parent node_modules - npm

First I will give some context to the problem.
I am developing an npm library. Inside the project folder, I have another folder called "example", for testing the library. The structure looks like below.
|- node_modules/
|- src/
|- example/
| |- node_modules/
| |- src/
| |- package.json
|- package.json
The root package.json has the dependency babel-jest. The example/package.json has the dependency react-scripts. When running react-scripts start inside example directory, it gives the following error,
As far as I can understand, this is because, the package.json inside the example/ directory inherits (not sure if this is the right term) the dependencies of the root package.json.
That is, I can use a dependency installed in the root package.json, inside the src/ of the example/
This is convenient in some cases. But this is a blocker for my use case.
How can I prevent this behaviour? (without changing the directory structure)
Thank you.

From what I understand, Dan Abramov suggests to use SKIP_PREFLIGHT_CHECK=true to work around this problem as there is no real fix.

Related

Do packages hoisted still install?

In regard to hoisting, I have this workspace structure:
root
-apps
-myApp
package.json
-packages
-myPackage
package.json
I have "react-native-reanimated": "~2.12.0" inside dependencies in both package.json of myApp and myPackage.
When hoisting, I expect to only see one react-native-reanimated folder in the root node_modules, but I see one in myApp and in one the root (by not in myPackage).
Isn't hoisting supposed to install a package (with the same version) in node_modules in the root node_modules and nowhere else?

How to avoid adding package to node_modules if it placed locally

I have repository with app and modules. Modules includes in app by package.json like:
"application-module": "file:../modules/application-module"
After yarn install that dependency added to node_modules.
I want to make module-base application. app folder reproduce root module. Other modules like admin-panel-module, account-module should be in modules folder. So, app may have node_modules inside, but also modules folder for modules. Those modules will add by git subtree from another repos. So, this way I can develop independently
Is any way to avoid adding and use local directories?
Multiple node_modules and package.json
In any node/npm project, you can have multiple package.json across your directory tree, like:
app/
package.json
node_modules
src...
account_module/
package.json
node_modules
src...
admin_module/
package.json
node_modules
src..
When you invoke yarn (or npm install ofc) on any of the children modules, the dependencies listed in their local package.json will be installed on the local node_modules folder.
So basically you can solve your issue ensuring that every children has their own package.json with their dependencies.
Still, you can place common dependencies in the root app folder. If all your projects for instance use lodash, you can place the lodash dependency in the add's package_json. After performing yarn in the app folder, the lodash package will be installed in the app's node_modules.
After that, if you:
require('lodash');
In any of the children, they will search for lodash in the app's node_modules folder if they don't find lodash in their own node_modules.
If you don't have a root node_modules, you can still declare a package.json local to any of the submodules, and they'll have their own node_modules.
So maybe you may want to avoid common dependencies at all, or maybe you want to store common dependencies in the app folder. Npm has you covered either ways.
However, if you don't want to handle common dependencies, yet are concerned about having to store a lot of duplicated packages in local machines, you may want to checkout pnpm, which is a wrapper over npm which allows to save a lot of space in local development machines.
I'm having (almost) the same issue with yarn.
I have create a package (typescript) called "test". In this package, after built, there are mainly 3 directories : dist (after built), node_modules and src.
Then I have created another package "test2" and in this package, have added "test" as a dependency "yarn add c:/.../.../test".
The package is the well installed in the node_module of test2. BUT, in "test2/node_modules/test", I can find the node_modules of test ( "test2/node_modules/test/node_modules". Why ? It increases the size of the package a lot.
In both tsconfig.json (test and test2) node_modules is excluded...
thks

Electron-Builder does not copy node_modules into my application

I have an electron app with the following structure
- dist
| - index.html
| - node_modules
| - nm (is an exact copy of node_modules)
- package.json
| ...
if I refer to the node modules in my index.html as node_modules/module the app won't find the module if built with the build command from electron-builder. But if I change that line in my index.html to nm/module it is perfectly willing to load it.
It seems to me that electron-builder isn't copying node_modules into the application, but I can't see why it would do that. Is it excluding all folders named node_modules and how can I fix this?

webpack a module that contains node_modules

Question
I want to make changes to an open source JavaScript library. Using webpack and npm and keeping everything local, what options do I have to make changes to a local module and import it into project in place of an public npm module downloaded from the registry? The local module and consuming app will also be source controlled under two separate git repositories.
Problem
I am testing this within an Aurelia app, but I think it is a webpack and npm problem. I have an app called my-app which has a dependency on aurelia-binding. I wish to make local changes to aurelia-binding and push them to a fork in GitHub. My project structure looks like this:
└───my-app
├───.git
├───dist
├───node_modules
│ └───aurelia-binding
| ├───.git
│ ├───dist
│ └───src
└───src
When built and run, everything works as expected. To make a change to aurelia-binding and test them in my-app, I need to install its dependencies and build it. This results in a structure like this:
└───my-app
├───dist
├───node_modules
│ └───aurelia-binding
| ├───.git
│ ├───dist
| ├───node_modules
| | └───dependencies...
│ └───src
└───src
When the node_modules are installed on the dependency, webpack throws an error at runtime. The error may look like an issue with the aurlia module, but I do not believe this is the case.
Unhandled rejection Error: Error invoking SVGAnalyzer. Check the inner error for details.
------------------------------------------------
Inner Error:
Message: __WEBPACK_IMPORTED_MODULE_1_aurelia_pal__.a.createElement is not a function
I have also tried this using npm link with the library cloned next to my-app instead of within in but got the same result.
I used the following addition to the webpack.config.js to be able to use npm/yarn linked packages. It forces webpack to resolve the modules only using the main node_modules and not the "nearest" ones.
resolve: {
extensions: [".ts", ".js"],
symlinks: false,
modules: ["ClientApp", path.resolve('node_modules')],
}
Where "ClientApp" is the folder where my aurelia app is located. The symlinks parameter is used to prevent webpack from resolving the symlinked path to an absolute path.
A word of warning, with this setup you circumvent version checking by npm so you are responsible for linking a compatible version.

Import local packages as modules not in the React-Native project

In a React-Native project, I found that if your local package has a valid package.json file, you can import that like a module in node_modules without a relative path .
For example,
app/ # a React-Native project
|- any_folder_for_packages/
| |- foo/
| |- package.json
| |- index.js
|- src/
| |- bar/
| |- bar.js
|- ...
In this case, you can import the package foo in the bar.js using either:
// with a relative path
import foo from '../../any_folder_for_packages/foo';
or
// like a module (without a relative path)
import foo from 'foo';
The packager will try to find and use any local module which contains a package.json matching the requirement.
The question
I have a local package which is not in the React-Native project, how can I import it
projects/
|- app/ # a React-Native project
| |- src/
| | |- bar/
| | |- bar.js # need to import the package foo as a module which is not in this project
| |- ...
|- other_paths/
|- foo/
|- package.json
|- index.js
I tried to use
// like a module (without a relative path)
import foo from 'foo';
but it failed to find the module.
How can I use react-native to find the package when packing for development or bundling for the production?
Answer given by #Plague doesn't work in react native. You have to configure your metro.config.js file to use a local package.
If Using Expo
In expo, metro.config.js file may not be visible, so in the root directory of your project, run this command;
npx expo customize metro.config.js
This will generate the file for you with some default configuration. Now to import any package, you have to modify two things here;
config.resolver.nodeModulesPaths, to include the package, and ;
config.watchFolders to keep a watch on the package.
In nutshell, metro.config.js file should be like this;
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require("expo/metro-config");
const config = getDefaultConfig(__dirname);
const packagePath = "/full/path/to/package";
// here i added the packagePath to the list in the configuration to include it
config.resolver.nodeModulesPaths.push(packagePath);
// here i added the package again to another configuration key, to keep a watch on it if we make any changes.
config.watchFolders.push(packagePath);
module.exports = config;
That is it, but your code editor may report that module is not found, for that warning to remove, you can just run the command below;
npm install /path/to/package
BUT there is a problem with this
The dependencies in our package conflicts with that of main project.
So here is another way of installing a local package.
Using install-local
For this we don't need to make any changes to any file. We just need to install this package;
npm install install-local
And then install the local package using this;
npx install-local --save path/to/package
You will need to make your application aware of it through your root package.json files.
Confirm the new local module has a basic package.json configured.
For example:
{
"name": "foo",
"version": "0.0.1"
}
Ensure the package has an index.js and that it has something exported or export default.
For example, at the bottom of the index.js:
export default foo;
Then, simply save the package as a project dependency in your root module to via NPM. To do this and install it automatically into your node_modules you can use this command.
npm install --save file:other_paths/foo
note make sure you have the correct relative path from your general project package.json to your new module package.json.
Example, in this case it would be:
app/ # a React-Native project root
|- other_paths/
| |- foo/
| |- package.json # new module package json
| |- index.js
|- src/
| |- bar/
| |- bar.js
|- package.json # project package json
If set up correctly you should then be able reference the module anywhere in your project without relative path.
import Foo from 'foo';