Suppose that somewhere in my package.json I have:
"dependencies": {
"bower": "1.0.0",
// zillion other dependencies
}
Is there a way to make npm install only bower#1.0.0 from my package.json? Like so: npm install --only bower.
My goal is to make npm install and bower install run simultaneously.
As a workaround you may use something like:
$ node -pe "require('./package').dependencies.bower"
// → 1.0.0
$ npm install bower#$(node -pe "require('./package').dependencies.bower")
// npm install bower#1.0.0
// or with jq
$ npm install bower#$(< package.json jq -r '.dependencies.bower')
Where -e/--eval flag evaluates passed string and -p/--print prints result of eval.
💡 Please consider other answers as well since this one may be outdated.
As #atalantus noted in comment, the accepted answer doesn't work on newer version of NPM. Working solution for newer versions (verified on NPM 6.13.4) is:
npm install --no-package-lock --no-save bower#1.0.0
This will install bower and all its dependencies, but prevents installation of anything else you might have in package.json. It also doesn't create or modify existing package-lock.json.
From npm documentation:
The --no-package-lock argument will prevent npm from creating a package-lock.json file. When running with package-lock's disabled npm will not automatically prune your node modules when installing.
--no-save: Prevents saving to dependencies.
Combining this with Anton Rudeshko's approach to find out version in package.json, the final solution is:
VERSION_BOWER=`node -p -e "require('./package.json').dependencies.bower"`
npm install --no-package-lock --no-save bower#"$VERSION_BOWER"
Update 2023
Alternative solution I've just used is to temporarily modify package.json to only keep the dependency you need. That can be done quite easily with help of jq
Given package.json
{
"name": "sample",
"main": "src/index.js",
"dependencies": {
"bower": "1.0.0",
"foo": "^1.2.3",
"bar": "^4.5.6",
},
"devDependencies": {
"baz": "^10.20.30",
}
}
Let's first modify it with jq to only keep bower
cat package.json| jq 'del(.devDependencies) | .dependencies |= {bower:.bower}'
Gives us
{
"name": "sample",
"main": "src/index.js",
"dependencies": {
"bower": "1.0.0"
}
}
by deleting devDependencies completely and leaving only bower in dependencies.
Next up you would want to overwrite package.json with this new, version, but you can't do it directly like this
cat package.json | jq 'del(.devDependencies) | .dependencies |= {bower:.bower}' > package.json
because the file gets overwritten before it's fully read. Instead you need to buffer the output stream of jq command, simplest solution just storing it in variable, and then overwriting the original file
updated=`cat package.json | jq 'del(.devDependencies) | .dependencies |= {bower:.bower}'`
echo $updated > package.json
And package.json now reads:
cat package.json
{
"name": "sample",
"main": "src/index.js",
"dependencies": {
"bower": "1.0.0"
}
}
Run npm install now and you only install bower#1.0.0.
Obviously not always we can afford to modify the file, but you could also back-up the original file, etc. Main point is here how to easily modify json file thanks to jq rather than playing magic tricks with sed :-)
Seeing as with newer versions of NPM the previous solutions don't work anymore, I came up with this:
npm i -g --prefix=$(pwd) bower # $(pwd) = current directory, UNIX only
node bin/bower
Installing a package globally allows you to specify a "prefix" - a directory where the package will be installed. Here I just put the current directory as the folder I want the package to appear in. In CI, this will probably be your repo root.
Keep in mind this will ignore your package.json version and just download the latest one. If you need a specific version, just use bower#someversion instead.
An alternative solution is just rm package.json && npm i bower, or mv package.json _package.json && npm i bower if you want to restore it later
Related
Given an npm workspace with the following structure
workspace
package.json
packages
package-a
package.json
package-b
package.json
When I run an install command in package-a this will generate a package-lock.json file in the root of the workspace but not in the package.json file itself.
Is there a way to also generate it in the packages?
I don't know if this solves your problem, but you can specifie the folder in which you would install with --prefix
npm install --prefix ./install/here
you can use the lerna tool to manage your workspace and install dependencies in each package. you can generate package-lock.json files in each package in your workspace.
The Original Tool for JavaScript Monorepos. Monorepo means a repository with multiple packages.
lerna.js.org
I hope this answer will show you the right direction.
In most cases, running npm install within that package directory should do the job. But as you said that this is creating a global package-lock.json. This might be because the package you are installing might be specifying the global path using the prefix field.
The "prefix" field, specifies the location where the package's dependencies should be installed.
So one thing you can do is to go to the package.json in package-a and then either remove the prefix field from the package.json file OR set its value as following :
{
"name": "my-package",
"version": "1.0.0",
"prefix": "./",
"dependencies": {
...
}
}
Now when you run npm install it should install the packages locally and make a local 'package-lock.json`.
I want to update a dependency (packageX) without changing a locked dependency of that package, (packageY). In my package-lock.json, I have:
"packageX": {
"requires": {
"packageY": "1.0.0",
}
},
Each time I do "npm install packageX," I'd like to update packageX but have packageY stay on the defined version. How can I do that?
There is no way to do this, may be this link can explain better https://dev.to/saurabhdaware/but-what-the-hell-is-package-lock-json-b04
The story about package.json vs package-lock.json is tricky: npm install does not ignore package.json versions, nor does it ignore the package-lock.json. What it does is verify that the package.json and package-lock.json correspond to each other. That is, if the semver versions described in package.json fit with the locked versions in package-lock.json, npm install will use the latter completely, just like npm ci would.
Now, if you change package.json such that the versions in package-lock.json are no longer valid, your npm install will be treated as if you'd done npm install some-pkg#x.y.z, where x.y.z is the new version in the package.json for some-package.
I'm ok with local dependencies that packages install. But now I have a huge concerns about if a local installed package can install other global packages as dependencies.
as example:
npm install nunjucks
npm install sqlite
or
npm install botkit
It is not possible to mark a dependency as global in package.json, so that it is installed system-wide when you run npm i.
Here's an old comment by Isaac Schlueter stating that this will never be implemented.
Hooowever, it would be really simple to write a preinstall script to install arbitary dependencies globally.
{
"name": "Project",
"version": "1.0.0",
"description": "Preinstall script to install global deps",
"main": "index.js",
"scripts": {
"preinstall": "node -e \"const {execSync} = require('child_process'); JSON.parse(fs.readFileSync('package.json')).globalDependencies.forEach(globalDep => execSync('npm i -g ' + globalDep));\""
},
"dependencies": {
"react": "16.13.1"
},
"globalDependencies": [
"lodash"
],
"license": "ISC"
}
Copy this code into a package.json file in a folder on your PC. Then, in the folder run npm i. It will install React locally (in a node_modules folder) and it will install lodash globally.
You can verify this using: npm i ls -g --depth=0.
Reference: Install dependencies globally and locally using package.json
As to your question:
Can npm -i (local) install a global package without me knowing it?
It's not entirely silent. When running npm i for the above package.json file, you would see the following output:
> Project#1.0.0 preinstall /home/jim/Desktop/Project
> node -e "const {execSync} = require('child_process'); JSON.parse(fs.readFileSync('package.json')).globalDependencies.forEach(globalDep => execSync('npm i -g ' + globalDep));"
npm WARN Project#1.0.0 No repository field.
audited 6 packages in 1.113s
found 0 vulnerabilities
But whether you would catch this when running npm i on a large project is debatable.
I'm setting up a project in Visual Studio based on AngularJS and Typescript and it's a bit discouraging that I have to deal with yet another package manager as soon as I need to install dependencies.
The issue I have is that package managers require files containing dependencies to be located in a particular place.
Let's take npm for example.
I place packages.json at ./SolutionDirectory/MyApp.Web/
But when I run npm install, I just get ENOENT: No such file or directory. because cwd is ./SolutionDirectory
It works fine if I'm doing cd ./SolutionDirectory/MyApp.Web and run npm install after that.
For bower I was able to handle similar issue by just passing additional arguments like:
bower install --config.cwd=./SolutionDirectory/MyApp.Web/app/lib --config.directory=vendor
This command just gets bower.json from ./SolutionDirectory/MyApp.Web/app/lib and installs packages to ./SolutionDirectory/MyApp.Web/app/lib/vendor
Is there a way to have same thing to pass packages.json location to npm before it installs?
Is there a way to pass typings.json location to typings before it installs? to pass target directory location for typings installed?
Is the same doable for Nuget?
For npm:
npm install <folder>
<folder> is the path to the folder which contains the package.json file.
For typings:
typings install [<name>=]<location>
<location> is the path to the typings.json
For NuGet:
nuget install packageId|pathToPackagesConfig [options]
pathToPackagesConfig is the path to the packages.config file.
So, to answer the question, yes it's possible to specify a path to the config file's location for all of these package managers.
Is there a way to have same thing to pass packages.json location to npm before it installs?
No, there isn't. Currently there is no way to overwrite cwd value in npm. You should move directory and run it:
`$ cd SolutionDirectory/MyApp.Web/ && npm install`
Here is the similar discussion to this: https://github.com/npm/npm/pull/10958
Is there a way to pass typings.json location to typings before it installs? to pass target directory location for typings installed?
Technically yes, but I guess you'd like to just do typings install with typings.json. How about to put typings.json to the same path with package.json and use npm lifecycle script?
$ ls
package.json typings.json
$ cat package.json
{
"name": "name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"postinstall": "typings install"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"typings": "^0.7.12"
}
}
$ npm install
=> after npm install, typings install will start with typings.json
Is the same doable for Nuget?
Nuget is also package manager, so it should has similar features, like nuget mirror command can be npm config set registry and nuget locales can be npm cache I guess. Technically it's a different software, but I think understanding about both softwares is good way to know the concept and summary of each others.
I am just getting myself familiar with command line tools like npm. I've been searching around for the answer but was not able to find a clear one.
What I am trying to do is to install materialize-css package into my test package, as well as its devDependencies, like "autoprefixer". This is materializeCSS's package.json file.
Here's what I do:
Under my newly created and blank folder "testProject", I use npm init to create a package.json file for my test package:
{
"name": "create_project",
"version": "1.0.0",
"description": "Setting up a project",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "shenk wen",
"license": "MIT"
}
Then, I do
npm install materialize-css
I was expecting the above command would install all the dependencies and devDependencies of materialize-css, but only the dependencies is being installed. I read this question and the accepted answer suggests adding --dev to the command. But that seems not the answer I am looking for because --dev would only make materialize-css a devDependency of my test package, but not installing its own devDependencies. The other answers are not so straightforward. Is there any parameter I can use to achieve this? Or do I have to change the env_variable which I don't know how to?
In older npm versions, 'npm install --dev' installed all devDependencies of all your dependencies. This also used to work in a recursive fashion, so you end up downloading also devDependencies of devDependencies of your dependencies and so on. This resulted in enormously long install time / download size.
Also, the purpose of the feature is questionable: Why should you care about devDeps of your deps? For these reasons --dev was removed from npm:
https://github.com/npm/npm/issues/5554
Current behavior for 'npm install' is: install all deps and devDeps for the 'main' package (the one you 'npm install'-ed in the first place), but when recursing, install only deps (and no devDeps).
If you want to install & save the dependency to your package.json, you should use --save or --save-dev, I don't think --dev does this.
If you want the devDependencies of a module you've installed as a dependency to your project, you almost certainly want to git clone that module's repo or fork it instead. When you run npm install in your cloned repo, that will also install all of the module's devDependencies.
(I'm not a developer by trade and my npm-fu was a bit rusty, so I confused myself about what I was trying to do. Tomas Kulich's question "Why should you care about devDeps of your deps?" helped me realize the error of my ways.)