How to set an environment variable to be used during "npm install"? - node.js

Our coorporate network is very closed down, so a normal method of:
npm install cypress#3.4.1
Doesnt work since it is being blocked by a proxy, we need to provide the parameter CYPRESS_INSTALL_BINARYin the following way with the help of cross-env (since we have mainly Microsoft environments here).
cross-env CYPRESS_INSTALL_BINARY='\\localserver\cypress\3.4.1\cypress.zip' npm install cypress#3.4.1
This is easy to do on first install, but the problem is that everyone on the team needs to run this command. And I want it to be possible to just type npm install and they will get all requirements automatically. This is extra obvious when we want to update the cypress package, since the binary url needs to change each time.
I tried to add a preinstall script to my package.json like so:
"scripts": {
...
"preinstall": "cross-env CYPRESS_INSTALL_BINARY='\\localserver\cypress\3.4.1\cypress.zip'",
...
},
But it seems like that environment variable set by cross-env is "gone" after preinstall is finished and install begins, since cypress tries and fails to download from the web. I am okay with it being temporary, but it needs to persist over the install-command. Also seen solutions with .env files but none of those have support for the install step as far as I can see.
My current solution is to run the entire cypress installation in the preinstall step, and it works but seems uneccessary to run a double install each time.
So, what I am asking for, is a way to let a developer just run the following commands on a brand new computer and be done.
git clone ...
cd ...
npm install
How can I do that?

Same situation on my side, except that I want to prevent the installation of cypress on the local machine.
Solved it by adding a .npmrc into the root of the project and adding to version control.
Contents of .npmrc:
CYPRESS_INSTALL_BINARY=0
Since the environment variable is used on install time, the solution with cross-env was not possible, since one cannot be sure that cross-env has been already installed.
Let me know whether it helped or you have already another solution.

I ended up creating a tool that takes care of supplying the correct binary, depending on environment:
https://github.com/tomasbjerre/dictator-cypress
I have it internally at my company. When we need a new version of Cypress, we release a new version of this tool internally.
I add the tool as a preinstall script:
...
"scripts": {
"preinstall": "npx dictator-cypress#0.0.28",
...
So that it runs when someone does npm install:
...
Copy linux cypress to cypress.zip
Applying: copy linux-x64/cypress.zip to .
.npmrc should have reference to cypress binary
Up to date: .npmrc should have lines
.gitignore should include the copied zip
Up to date: .gitignore should have lines
...

Related

Force project to use Yarn but not npm

As a team practice, I would like to force my teammate to use yarn install/ run but not npm install/ run.
Is it possible to force a package.json 's dependency be installed only via yarn install or package.json's script be run only via yarn run?
If it cannot be done, can I at least get a warning when using npm install?
Again, this is only to align the team practice, so that reduces the possibility of error/ problem produced during dev/ops. Thanks
One of the way I can think of is CI can set a rules to detect if there is new file package-lock.json file being created, make the build fail. The developer will then realized he made a mistake since his build failed.
Alternatively you can also rely on husky pre-commit hook, which essentially runs a command to check if package-lock.json existed everytime developer trying to run git commit.

Is there good way to run a script only when the user install my npm package manually?(not installed by dependency)

I'm under developing my npm package and I want to run a specific script only when user installed my package manually like npm install my-package --save-dev or something npm command.
I'd not like to run the command when the package was installed via package dependency.
For example, My package is dependency of the other package other-package.
Even if the user installed other-package manually and npm should install my-package as dependency, I'd not like to run the script.
Is there good way to handle this?
npm has a set of scripts that will automatically run when npm is launched a particular way. The scripts you might be interested in are:
prepublish: Run BEFORE the package is published. (Also run on local npm install without any arguments.)
publish, postpublish: Run AFTER the package is published.
preinstall: Run BEFORE the package is installed
install, postinstall: Run AFTER the package is installed.
There is no event that exactly matches your criteria but you could use one of the install events and then have an intermediate script that detects the npm command line options before your actual script.
Due to the (imo horrible) way prepublish works, a number of people have written modules to do a similar task and these could easily be adapted to your requirements.
iarna/inpublish is a good example. It check's process.env['npm_config_argv'] for the existence of /^i(n(s(t(a(ll?)?)?)?)?)?$/
Using the following package.json setup:
"scripts": {
"postinstall": "my-install && install-manual-tasks || not-my-install"
}
If my-install uses process.exit(0) then install-manual-tasks will run. If you process.exit(1), not-my-install will clean up so the npm task doesn't fail.
I think this setup actually has an issue. If your install-manual-tasks fails, the exit status is silenced and the npm task won't fail but it's a start at least. You could work around this by doing all your checks in the install-manual-tasks script, then you don't need use the shell tricks to run multiple scripts.
You can take a look at https://superuser.com/a/105389/627275 to see how to create a shell function that acts as an alias to a command. This way, npm install would act as an alias to whatever you want to run in reality. It could also be an alias to bash something.sh & npm install.
Hope that answers your question!

How to install git hooks on "npm install"?

I'd like to install a pre-commit git hook (that lints the code) when someone installs my-package.
I tried to add a postinstall script:
"scripts": {
"postinstall": "./scripts/install-git-hooks"
}
This works great. When someone runs npm install, they get the pre-commit hook installed.
However, if another-package depends on my-package, running npm install for another-package runs the postinstall script as well, which is undesired.
What's the cleanest way to avoid this undesired affect?
You can use the ghooks npm module and add it as a dev-dependency. You can configure what to run before commit in your package.json like so:
[...]
"config": {
"ghooks": {
"pre-commit": "npm test"
}
}
[...]
Hacky, but might work for you.
The trick is to identify (within the script) if it is a sub-dependency or a root dependency for the NPM installation. Simply check if ../../package.json exists. If so, it's a sub dependency and you should skip installing the hooks.
It should be noted that you are breaking any consistent installation rules, which is exactly against the spirit of the installation scripts. This is to install client-side hooks which cannot be trusted by any means, if you need the linting to be enforced, this should be done server side, where it can just reject code that doesn't comply.
Potentially this issue would be better solved like you mentioned, by having it as a custom install script, and just dealing with the additional communication overhead.

Run npm install --production on OpenShift

When I push my code to OpenShift, it looks like it's installing my devDependencies which takes forever. I would really love to set it up so it will only install the dependencies (by running with the --production flag). Is there any way to do this?
You can tell npm to install using the --production flag by setting the NPM_CONFIG_PRODUCTION environment variable to "true".
Here is an example that should work for existing applications:
rhc env set NPM_CONFIG_PRODUCTION="true"
Or, you can set this variable as a part of your initial app-create step:
rhc app create myapplication nodejs-0.10 NPM_CONFIG_PRODUCTION="true"
Found a way to specify it in source instead of during app creation.
The benefit (for me) over an env var is that it applies to all ways to launch the app, including a "Launch on OpenShift" button.
Create an .openshift/action_hooks/pre_build file:
#!/bin/bash
# This makes npm not install devDependencies.
echo 'Enabling npm production'
echo 'production = true' >> $OPENSHIFT_REPO_DIR/.npmrc
That's it! I've tested and it does affect npm for this build, and the .npmrc disappears if you remove this hook in the future.
(Obviously I could also achieve this by simply adding an .npmrc to my repo, but do not want to affect people checking out the source and running npm install, only how it works on OpenShift.)
It looks like the only solution is to update the cartridge itself. The npm install command is located in the cartridge's bin/control folder. Meanwhile, it's been fixed in the originating github repo at wshearn/openshift-origin-cartridge-nodejs so you can just install from github rather than using the Quickstart.
Create a .npmrc file where the node_modules folder is located.
Open it with your text-editor and add this to it:
production = true
P.S. no semicolons or any other characters
This will ensure that devDependencies are not installed on the OPENSHIFT server

Installing "global" npm dependencies via package.json [duplicate]

This question already has answers here:
Install dependencies globally and locally using package.json
(7 answers)
Closed 8 years ago.
I have a few "global" dependencies (jshint, csslint, buster, etc..) that I'd like to have automatically installed and executable via the command line when my package is installed via npm install. Is this possible?
Currently, I'm doing the following manually:
npm install -g <package_name>
from within my project: npm link <package_name>
Update:
Just came across this feature request for npm. It seems like the scripts config within package.json is the way to go?
Update Again:
Or, after reading the npm docs, maybe I'm supposed to use a .gyp file? I'm confused.
It's not possible to specify dependencies as "global" from a package.json. And, this is by design as Isaac states in that feature request you referenced:
Yeah, we're never going to do this.
But, "binaries" can still be used when a package is installed locally. They'll be in .../node_modules/.bin/. And, you should be able to queue them up with a preinstall script.
Though, if the series of commands is rather lengthy (as "jshint, csslint, buster, etc.." would suggest), you may want to look into using a build tool such as grunt to perform the various tasks:
{
// ...,
"scripts": {
"preinstall": "grunt"
}
}
I really like the pattern where you install local dependencies, then use a bash script that sets your PATH to ./node_modules/.bin.
File: env.sh
# Add your local node_modules bin to the path for this command
export PATH="./node_modules/.bin:$PATH"
# execute the rest of the command
exec "$#"
Then, you can use this script before any bash command. If you pair that with a Makefile or npm script:
File: Makefile
lint :
./env.sh csslint my_styles
File: package.json
"scripts": {
"lint": "./env.sh csslint my_styles"
}
This tasks in these files look like they reference csslint in some global location, but they actually use the version in your node_modules bin.
The really awesome benefit of this is that these dependencies can be versioned easily, just like your other node modules. If you stick with a global install solution, you could be clobbering some specific version on the user's system that is required for one of their other projects.
You should try this: https://github.com/lastboy/package-script
I've been using it to install global npm packages straight from the package.json. It works well for clients who aren't technically literate.
It even checks if the packages are already installed, if not install them!

Resources