node: how to avoid installing global packages - node.js

I'm looking for a pattern to avoid the need of global packages when working with node, I'd like to install everything I need with npm install and then just running every command with npm run xxx, without any global package installed.
For example, I have jest configured to run my tests.
These are the dependencies in my package.json:
[...]
},
"author": "",
"license": "ISC",
"dependencies": {
"#types/express": "^4.16.1",
"#types/node": "^11.10.5",
"express": "^4.16.4",
"ts-node-dev": "^1.0.0-pre.32",
"typescript": "^3.3.3333"
},
"devDependencies": {
"#types/jest": "^24.0.9",
"#types/supertest": "^2.0.7",
"jest": "^24.3.1",
"nodemon": "^1.18.10",
"supertest": "^4.0.0",
"ts-jest": "^24.0.0"
}
[...]
and these are some scripts I have configured:
[...]
"scripts": {
"test": "jest --coverage",
"tsc": "tsc",
"watch": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/server.ts"
},
[...]
But when I issue npm run test I get this error:
$ npm run test
> ci-test#0.0.1 test /home/sas/devel/apps/vue/ci-test
> jest --coverage
sh: 1: jest: not found
npm ERR! file sh
[...]
If I install jest globally with npm install -g jest everything runs fine, but that's precisely what I'm trying to avoid.
A few assumptions I made that might be wrong:
when running scripts node first looks for commands in node_modules/.bin (in order to use locally installed packages)
when I issue npm install every command line command is installed to node_modules/.bin
This last one is not working, because even though I have jest in my devDependencies there's no node_modules/.bin/jest file in my project
$ ls node_modules/.bin/
acorn cdl esgenerate esvalidate is-ci json5 loose-envify mime nodetouch parser semver sshpk-sign strip-indent watch
atob escodegen esparse import-local-fixture jsesc js-yaml marked mkdirp nopt rc sshpk-conv sshpk-verify uglifyjs
On the other hand, as a workaround, the following seems to work:
"scripts": {
"test": "npx jest --coverage",
But it takes more than 10 seconds for npx to install jest everytime I run npm run test
So, what would be the correct way to achieve it? O how can I tell npm to install jest to node_modules/.bin and use it whe I reference it in my scripts?

It seems like it was easier than expected, I just had to issue:
npm install --only=dev
seems like by default npm won't install dev dependencies
I did a couple more tests, playing with the NODE_ENV var, and after unsetting it npm install seems to install also devDependencies, along with jest in node_modules/.bin/jest. It seems like somehow it was assuming I was in production mode.
Another trick I learned to avoid installing global dependencies is to install it with --save-dev, and then adding a script to run it with npm run. For example, to avoid installing jest globally but still be able to use it from the command line you should:
npm install jest --save-dev
Then add the following to your package.json
scripts: {
"jest": "jest"
}
And then you can run it from the command line with npm run jest. To pass params from the command line you have to add a '--' before the params, like this: npm run jest -- --coverage. Or you could just issue npx jest --coverage, if installed, npx will use jest from node_modules/.bin. (check this for more info)
BTW, this answer to a similar question might be useful

Related

npm-force-resolutions not working when installing a new package

I'm using the scripts section of the package.json to force resolutions:
"preinstall": "npx npm-force-resolutions"
in the resolutions section, I have entered graceful-fs with a specified version:
"resolutions": {
"graceful-fs": "^4.2.4",
},
When i run npm i everything is installed correctly, the set versions are taken in to account. But later on when I install an additional module, e.g. npm i random-package, my set versions are being thrown away and I endup with graceful-fs#1.2.3 and other low versions in some dependencies.
If I clear the node_modules folder and run npm i again, everything is alright again.
I also tried setting the resolution more specific, like
"resolutions": {
"glob/**/graceful-fs": "^4.2.4",
},
but this doesn't help.
I also tried:
adding the module as dependency, devDependency or peerDependency
using a shrinkwrap and overriding it there
but no luck.
what am I missing?
The best solution for me to automate this was modifying preinstall script as above:
"preinstall": "npm install --package-lock-only --ignore-scripts && npx npm-force-resolutions",
Best way is to change the preinstall script to this:
"preinstall": "([ ! -f package-lock.json ] && npm install --package-lock-only --ignore-scripts --no-audit); npx npm-force-resolutions"
This will only run npm install to create your initial package-lock.json when it does not exist yet.
This is much faster than always running both (npm + npx).
As of npm 8.3.0, you can also use npm's override:
{
"overrides": {
"graceful-fs": "^4.2.4"
}
}
in the resolutions section, you must fix version
"resolutions": {
"graceful-fs": "4.2.4",
},
Hi #NthDegree the only way which worked for me was to first run the normal npm install and then add the packages-lock.json file to git. After doing that when you add "preinstall": "npx npm-force-resolutions", it always updates the dependency resolution to the version mentioned.
I am not sure if adding packages-lock.json file to git is good or bad but by using this method the CI/CD pipeline works as well.
If all of the above answers don't work and you still get sh: npm-force-resolutions: command not found
try the following:
Just change:
"preinstall": "npx npm-force-resolutions"
To:
"preinstall": "npx force-resolutions"
npx force-resolutions does not run when no package-lock.json is detected, and allows the next command inline to be executed as normal
Credit to: https://github.com/rogeriochaves/npm-force-resolutions/issues/10#issuecomment-885458937

Errors installing jest in console [duplicate]

I have a test file like so: (I am using create-react-app)
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/Calculator';
import { getAction, getResult } from './actions/'
import {shallow} from 'enzyme';
import toJson from 'enzyme-to-json';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
it('renders without crashing', () => {
const wrapper = shallow(<App />)
expect(toJson(wrapper)).toMatchSnapshot();
});
it('displays the choosen operator', () => {
const action = {
type: 'GET_ACTION',
operator: '+'
};
expect(getAction("+")).toEqual(action)
})
it('displays the typed digit', () => {
const action = {
type: 'GET_RESULT',
n: 3
};
expect(getResult(3)).toEqual(action);
})
it('checks that the clickevent for getNumber is called',() => {
const clickEvent = jest.fn();
const p = shallow(<p data-n="1" onClick={clickEvent}>1</p>)
p.simulate('click')
expect(clickEvent).toBeCalled();
})
and a package.json:
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-scripts": "1.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
// "test": "react-scripts test --env=jsdom",
"test": "jest",
"eject": "react-scripts eject"
},
"devDependencies": {
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "^3.3.3",
"jest": "^22.4.3"
}
}
when I run jest --updateSnapshot I get:
command not found: jest
but jest is installed.
Jest is installed, but is likely in your ./node_modules/.bin directory. You can append that to your command ./node_modules/.bin/jest --updateSnapshot. Since you already have jest as a scripts command in your package.json you can also run it with npm test -- --updateSnapshot. npm automatically adds ./node_modules/.bin to your path.
update: Newer versions of yarn will resolve node module bin scripts, so you can also just run yarn jest {cmd} and it should work.
I ran into similar issue. I fixed it by installing jest globally.
npm install -g jest
You need to run it this way :
./node_modules/.bin/jest
or run npm test
Install the Jest command-line interface (Jest CLI):
npm install --save-dev jest-cli
Then run the jest command. Working for me in a linux instance by docker on Windows 10.
I was getting zsh: command not found: jest after installing jest and trying to use the command jest. The solution that worked for me was running npx jest
A way to solve the error is to use the "npx" command.
npx jest --version
npx jest --init
In my case, npm didn't install the jest command for some reason.
To fix this:
I deleted the node_modules/jest directory
Re-ran npm install and got the jest command installed.
try using the command
npx jest <folder>
I ran into the same problem. I tried multiple solutions and this worked.
I also have jest CLI installed
you can install it by using this command in your shell
npm install --save-dev jest-cli
just use command
npm test or npm t
Removing node_modules and running npm install again fixed this for me
Also the "new" npm ci command can fix this as it deletes (or clears) node modules and performs a clean install each time, plus it's faster compared to manually deleting node_modules and re-installing
My situation was caused by my git pipeline. I wasn't caching node_modules nor was I caching untracked files.
Ultimately I added
cache:
# untracked: true
key:
files:
- package-lock.json
paths:
- node_modules
to my pipeline .yml and violá
Note
you can either use path OR untracked, find out more about each to see what works best for you
Just reload your bash config file after install jest:
source ~/.bashrc # on linux ?
source ~/.bash_profile # on macOs
Jest will be not recognized but executed with npx jest automatically
I use yarn. Adding jest and jest-cli to node_modules did not make any difference with my attempts to run tests like jest mytest.test.js. In addition to mentioned steps, the following helped to get it running:
yarn jest mytest.test.js
you can run ln -s ./node_modules/.bin/jest jest
and then run jest --init it will work. Or you can install jest cli with npm install --save-dev jest-cli and then run jest --init it will also work.
In my case, I was trying to install jest with yarn on a pipeline to run tests and since I had jest installed as a devDependency it wasn't installing on yarn install.
I found this bug on GitHub https://github.com/yarnpkg/yarn/issues/2739 that it seems that Yarn will not install devDependencies when NODE_ENV=production.
I just needed to change the NODE_ENV and after that, it was working, otherwise, run it like this:
yarn install --production=false
Faced the same issue. But it was due to the wrong node version. If you use the latest jest v29, you need Node version 14 or higher.
You can run the test using npx jest [parameters]. npx is the package runner. It will help you execute a locally installed package.
Had the same issue and was able to solve it by running npm install
Alternatively, just add jest module to package.json dependencies.
{
"dependencies": {
...
"jest": "^29.3.1",
...
}
}

Webpack not working in my node.js project. fsevents

I'm currently trying to implement this tutorial:
https://www.typescriptlang.org/docs/handbook/react-&-webpack.html
I'm supposed to install react and react-dom and also webpack + typescript + awesome-typescript-loader + source-map-loader, and that's what I did. I also installed webpack-cli accordingly to instructions that I got from the command line.
I installed all of them locally (the react and react-dom as PROD and the rest as DEV dependencies).Currently I don't have any packages installed globally.
After this, that's my package.json file:
{
"name": "reactandwebpack-tutorial",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"awesome-typescript-loader": "^5.2.0",
"source-map-loader": "^0.2.3",
"typescript": "^2.7.2",
"webpack": "^4.16.4",
"webpack-cli": "^3.1.0"
},
"dependencies": {
"#types/react": "^16.4.7",
"#types/react-dom": "^16.0.6",
"react": "^16.4.2",
"react-dom": "^16.4.2"
}
}
At this point, when I run npm ls I get a bunch of errors, because of some optional dependency of webpack that apparently is missing (all the errors in the tree are inside webpack and below fsevents as following):
webpack#4.16.4
(...)watchpack#1.6.0
(...)chokidar#2.0.4
(...)fsevents#1.2.4 -> UNMET OPTIONAL DEPENDENCY
And everything below fsevents is also marked with UNMET DEPENDENCY
And when I run webpack command, I get a "webpack not recognized error".
Anyone can help? I've been trying to wrap my head around this for a while.
PS:
Npm -v 5.6.0
Node -v 8.11.3 //(that's what I get from the terminal,
//VSCode "About" tells me something different, I don't know why).
Using Visual Code
Version 1.24.0
Date 2018-06-06T17:35:40.560Z
Shell 1.7.12
Renderer 58.0.3029.110
Node 7.9.0
Architecture x64
The reason is because it was not linked to your env. When you install something globally, you have access to it everywhere, hence it works just by doing webpack. Since you installed everything locally, the binaries are located inside node_modules/.bin.
You have two options when you install something locallly.
Use npm scripts (npm run build, watch... whatever).
./node_modules/.bin/moduleName --flags
It is easier to create a npm script and add all the commands there.
SOLVED
Not sure the reason but it had something to do with the ./bin folder with the webpack-cli "ambient variable" not being available (I don't know it that would be the most accurate description).
When I try to run webpack, I get "not recognized error".
But when I run nodemodules\.bin\webpack-cli it works normally.
Everything is installed locally.
I can also run it with options, like nodemodules\.bin\webpack-cli --help
If you run "webpack", The CLI will find global webpack with is installed by (npm install webpack -g). To use webpack from local project. you should it to npm script.
package.json
{
"script": {
"start": "webpack"
}
}
By doing this, you can run npm start to run webpack.

How do I deploy my Typescript Node.js app to Heroku?

When testing locally I was previously running:
"build-live": "nodemon --exec ./node_modules/.bin/ts-node -r dotenv/config -- ./index.ts"
I then figured my Procfile should be something like:
web: ./node_modules/.bin/ts-node -- ./index.ts
But it says module 'typescript' not found, even when it is in package.json. I read in a few places that ts-node is not the way to go to deploy to Heroku, so I am not sure what to do.
UPDATE: I think I am supposed to compile it, so I tried:
web: ./node_modules/.bin/tsc --module commonjs --allowJs --outDir build/ --sourceMap --target es6 index.ts && node build/index.js
This succeeds, however when actually running it, a bunch of the libs I'm using get "Cannot find module '...'".
Alternatively you can have the TypeScript compile as a postinstall hook and run node build/index.js as the only Procfile command:
Your package.json should contain a postinstall hint that gets executed after npm install and before the node process launches:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
You can then leave your Procfile as is:
web: npm start
This 'build on deploy' approach is documented by Heroku here.
The command you've given Heroku is to launch the web "process" by compiling index.ts and dependencies and starting node at index.js. Depending on how things are timed, index.js might or might not exist at the time node starts.
You need to already have your sources compiled by the time you want to start your app. For example, web should just be web: node index.js or similar.
Each build process is different, so you need to figure that out for your own setup. But, suppose you have a classical setup where you push to git and then Heroku picks up that change and updates the app with the new slug. You could just compile things locally and include index.js and any other build output in the repository, for it to be available in the slug for Heroku to use.
A better approach is to use a build server which has an integration with Heroku. After you do the build there, configure it to send the build results to Heroku. Travis has a straighforward setup like this. This way you don't need to include build outputs in your repository, which is considered an anti-pattern.
On a sidenode, try using a tsconfig.json to keep the tsc configuration. It will save you from having to write such long command lines all over the place.
Fabian said that we could do something like:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
As of me writing this, I tested this and can state: postinstall is not required since build script is ran by Heroku. If you want to do it without build script, then you can use heroku-postbuild which will run after dependencies are installed there you run tsc to compile.
My problem was about missing Typescript npm modules. The Typescript compiler tsc was not found when deployed the app to Heroku.
The Heroku deploy process (rightly) does not install development dependencies, in my case the Typescript module was part of devDependencies and thus the tsc command was not running on the Heroku platform.
Solution 1
Add typescript to dependencies: npm i typescript -s
Solution 2
Open Heroku console:
Select console type:
Run the command npm i typescript && npm run tsc
Install typescript as a dev dependency (cf. https://www.typescriptlang.org/download). Once built, your app does not need typescript anymore!
npm install -D typescript
Then in your package.json:
{
"main": "index.js", // <- file will be generated at build time with `tsc`
"scripts": {
"build": "tsc",
"start": "node ."
"start:dev": "ts-node index.ts" // idem, install ts-node as a dev dependency
}
}
The key point here is "build": "tsc".
Why?
Heroku does install all dependencies during build and remove the dev dependencies before the app is deployed (source here).
Node.js deployments will automatically execute an app’s build script during build (since March 11. 2019 source here)
In package.json
"scripts": {
"tsc": "./node_modules/typescript/bin/tsc",
"postinstall": "npm run tsc"
},
Works for me for Heroku deployment.
Installing typescript npm install -D typescript and writing tsc in the build script "build": "tsc", does not work for me. Also, try to run npm i typescript && npm run tsc in the Heroku console which also does not work.
In my case, I remove some dependencies from "devDependencies" to "dependencies", so it goes like this:
"dependencies": {
// The other dependencies goes here, I don't touch them.
// But all TS dependencies I remove to here.
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.3",
"ts-loader": "^8.0.18"
},

Mocha TS tests fail with `npm test` but not if run directly

In my nodejs project (written in Typescript) I can run my tests with this command:
mocha --compilers ts:ts-node/register,tsx:ts-node/register
and they succeed. I also used this command in my package.json file so that
npm test
runs them the same way, however in this case I get:
Mikes-iMac:antlr4-graps mike$ npm test
> mocha --compilers ts:ts-node/register,tsx:ts-node/register
module.js:472
throw err;
^
Error: Cannot find module 'ts-node/register'
at Function.Module._resolveFilename (module.js:470:15)
My package.json file contains:
"scripts": {
"test": "mocha --compilers ts:ts-node/register,tsx:ts-node/register"
},
"devDependencies": {
"#types/chai": "^3.4.34",
"#types/mocha": "^2.2.32",
"#types/node": "^6.0.40",
"chai": "^3.5.0",
"mocha": "^2.5.3",
"typescript": "^2.0.3",
"vscode": "^1.0.0"
},
What is the correct variant to run mocha via npm?
The problem is that no matter what, but npm run <script> in general and npm test in particular will run command using /bin/sh, not your current shell, which is likely different.
Since you don't have ts-node in your dependencies, I assume it's installed globally. Depending on how you install Node.js, /bin/sh may end up using different Node.js installation than your current shell and therefore not have same globally installed package.
If I'm right these two commands will give different results:
$ which node
$ /bin/sh -c 'which node'
Two possible solutions:
Add ts-node to devDependencies of you project and npm install.
Ensure, that /bin/sh uses same installation of Node.js, as you current shell.

Resources