How to use npm-shrinkwrap with workspaces? - node.js

I have a monorepo project, with one of the packages being a cli. And to prevent npm supply chain attack I am thinking of using npm-shrinkwrap.
The documentation here says:
The recommended use-case for npm-shrinkwrap.json is applications deployed through the publishing process on the registry: for example, daemons and command-line tools intended as global installs or devDependencies
This is exactly what i want as I am deploying a command-line tools. The only problem is, it seems npm-shrinkwrap does not support workspaces.
Let's say the cli part of my monorepo can be found in the path: /code/packages/cli, when I switch to it and run npm shrinkwrap I get the error:
npm ERR! code ENOWORKSPACES
npm ERR! This command does not support workspaces.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/me/.npm/_logs/2022-05-16T20_53_41_147Z-debug-0.log
If I switch to the root of the project, that is /code/ and I run npm shrinkwrap, it does generates a npm-shrinkwrap.json with the following structure:
{
"name": "root",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "root",
"version": "1.0.0",
"license": "ISC",
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^4.0.0"
}
},
"packages/cli": {
"name": "#proj/cli",
"version": "1.0.0",
"extraneous": true,
"license": "ISC"
}
}
}
But the only problem is, this is not the exact structure that should be created for the cli. Also when I publish the package (using lerna), the npm-shrinkwrap.json is never included in the cli package.
Any tips on how to make npm-shrinkwrap work with workspaces?
Basically how to have the npm-shrinkwrap.json generated for a package in a monorepo and have that inlcuded when that package is released?

The tool npm-lockfile uses npm's internals and works inside of monorepos.
Unfortunately, they're using an old version of #npm/arborist, so it doesn't quite work properly, and you can use my patch for now

Related

Why is npm i -g module different from npm i -g --only=dev .?

Let's say we have this simple package.json
{
"name": "test",
"version": "1.0.0",
"description": "Testing",
"main": "index.js",
"scripts": {
"test": "mocha"
},
"keywords": [
"tests"
],
"author": "JJ",
"license": "ISC",
"devDependencies": {
"mocha": "^8.2.0"
}
}
Basically we're looking to install mocha as a dependency for development, obviously. We run
npm i -g mocha
It's installed, and then
which mocha
works.
However, this does not yield the same result:
npm i -g --only=dev .
Obviously, it's installing things someplace else which is not in the path, possibly. But how come it's different? Running with --verbose does not yield much more information on where exactly it's going to be located.
Anyway, what I'm looking for is is a consistent way of specifying these global requirements. It does not seem too clean to create a Docker image or whatever with lots of npm i -g xxx yyy zzz followed by npm i with a package.json (or package-lock.json) where those dependencies are already specified. Maybe there's another way I've missed?
When you install an npm package with the -g tag, you are installing the package globally on your machine, not in your project;
Only use the -g tag if you are going to run something specific on your machine that isn't required by the project; otherwise, just hit npm i and install it directly on the project directory.
If it's going to be a development dependency, install it with npm install --save-dev mocha

Find the package.json file from within an npm script that runs on preinstall

So I need to read the package.json before installing a new package via npm.
Why reading package.json in the first place?
I am using npm for CSS components that are individually versioned and can have inter dependencies. (No javascript is delivered)
Looking for version conflicts for a bunch of dependencies I need to detect when package A requires package C#1.0.0 and package B requires package C#2.0.0 and deal with it.
Npm (as of version 3) deals with these issues by nesting a conflicting module deeper inside the tree. You now end up with both versions of the same module. CSS has a global namespace and a mixin (in Sasss case) would then overwrite each other and break your CSS.
This flat dependency issue is perfectly outlined in the npm blog: http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging
Even not considering our specific use case it strikes me as odd that you don't have access to the package.json in preinstall and postinstall scripts. They seem to be just for that use case.
What I tried
My package.json of the package I'm installing looks like this:
{
"name": "testmodule",
"version": "0.3.6",
"description": "TODO",
"scripts": {
"preinstall": "npm i some-script && some-script",
},
"author": "TODO",
"license": "MIT"
}
Inside that some-script package I run:
console.log( process.cwd() );
console.log( __dirname );
I then run:
~/path/to/folder $ npm i testmodule
This will result in:
$ npm i testmodule
> testmodule#0.3.6 preinstall /path/to/folder/node_modules/.staging/testmodule-5cc9d333
> some-script
/path/to/folder/node_modules/.staging/test-module-5cc9d333
/path/to/folder/node_modules/.staging/test-module-5cc9d333/node_modules/some-script
Now I totally get that I can't really access the root of where npm i was ran because my script was run by a subprocess of npm and has an entirely different root.
I then thought npm root should keep track where the actual root was for me and passed that as a parameter to my script from inside the testmodule package.json:
{
"name": "testmodule",
"version": "0.3.6",
"description": "TODO",
"scripts": {
"preinstall": "npm i some-script && some-script \"$(npm root)\"",
},
"author": "TODO",
"license": "MIT"
}
Unfortunately that also defaults back to a staging path:
/path/to/folder/node_modules/.staging/testmodule-5cc9d333/node_modules
I filed an issue with the registry but not holding my hopes up for them to get to that in time. Also my script needs to work on older npm installations.
In the meantime I came up with something like that inside my some-script:
let pgkPath = process.cwd().split('/node_modules/')[0];
That will return /path/to/folder/ which is correct but it makes the assumption no-one runs an npm i inside a folder incidentally named node_modules... Seems hacky.
Question
How can I access the path to the package.json from inside an npm script that is run via preinstall? To me that seems like something not too outrageous to ask for?
I don't understand your use-case entirely, but to answer your specific question of finding a parent package.json from a preinstall script:
Pass $(cd .. && npm prefix) as an argument to your script, then load ./package.json.
npm prefix will return the closest parent directory to contain a package.json file, which when invoked from the .. directory, should return the parent npm package's path.
{
"name": "testmodule",
"version": "0.3.6",
"description": "TODO",
"scripts": {
"preinstall": "npm i some-script && some-script \"$(cd .. && npm prefix)\"",
},
"author": "TODO",
"license": "MIT"
}

Install ignored files with NPM

The package is listed in project dependencies:
"name": "project",
"devDependencies": {
"package": "*"
}
Some of the files in installed package are ignored by blacklisting (.npmignore) or by whitelisting:
"name": "package",
"files": [
"lib/",
"index.js",
"LICENSE",
"README.md"
],
Forking it and changing ignore settings is not an option for me. I would prefer to have it in node_modules and require it like normal package, and doing things like git clone in npm install script looks like a terrible idea because it is dev dependency and shouldn't be installed for users who add project as a dependency.
Can package repo be installed entirely on npm i, including ignored files? What are the options?

How to use a npm modules in nightwatchjs based project

Planning a nightwatchjs based project, for data driven web testing, after loading list of options from a data.json file to iterate through collections etc. I want to include underscore or lodash npm modules. I don't see a package.json where i can include dependencies to generate node_modules through npm install option.
How can one use npm modules with nightwatchjs project ?
Haven't used nightwatch, but have used mocha, and if you just create a package.json file in the directory where you're running your tests, then do an npm install, in mocha you can then simply use those packages. I would assume that since nightwatch is js, it should be the same. Just try it out.
you may create your own using package.json specification in your project folder,
there is mine for docker:
{
"name": "e2e-tests",
"version": "0.0.1",
"main": "index.js",
"scripts": { },
"author": "Alex K",
"license": "MIT",
"dependencies": {
"chromedriver": "^2.37.0"
"i18n": "*",
"nightwatch": "0.9.21",
"nightwatch-html-reporter": "*"
}

npm install doesn't install any dependencies

I am trying to install packages in the package.json file. Unfortunately, when I run npm install, nothing happens (nothing is installed). I have used npm install on other repos and it works successfully.
Here is my path:
$PATH = /Users/me/.rbenv/shims:/Users/me/.rbenv/bin:/usr/local/share/npm/bin:/usr/local/bin:/Applications/Postgres.app/Contents/MacOS/bin:/usr/bin:/bin:/usr/sbin:/sbin
As you can see, npm/bin is in my bath and I believe this is correct.
Here are the instructions for this repo and where to run npm install (which I am doing)
go into "module"
run "npm install"
pair your laptop/pc with intelligent brick troubleshoot: http://www.ev-3.net/en/archives/97
run example.js: "node example.js"
see "example.js" for more details
When I run npm install in the module directory (that has the package.json) nothing installs.
Here is the package.json:
{
"name": "ev3-nodejs-bt",
"description": "Bt Api for lego ev3 robot",
"version": "0.0.4",
"private": false,
"dependencies": {
"serialport": "1.*"
},
"main": "Ev3.js",
"devDependencies": {"serialport": "1.*"},
"scripts": {
"test": "node Ev3.js"
},
"repository": {
"type": "git",
"url": "https://github.com/wenchaojiang/Ev3NodeJsBtAPI"
},
"keywords": [
"node.js",
"ev3",
"lego",
"robot",
"bluetooth"
],
"author": "Wenchao Jiang <psxwj#nottingham.ac.uk> (http://wenchaojames.wordpress.com/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/wenchaojiang/Ev3NodeJsBtAPI/issues"
}
}
Do I have something set up wrong on my system? (I don't think I do based on my $PATH and successful installing packets in other node-js repos) Is this package.json file not valid?
npm install doesn't install (or echo) anything when all of the dependencies are satisfied. Ensure there's a serialport folder under node_modules.
If you want to reinstall everything, you just need to remove the node_modules folder:
rm -r node_modules
npm install
If you have an npm-shrinkwrap.json file, check it. The npm install command will only install the packages specified in that file.
According to the npm install docs:
If the package has a shrinkwrap file, the installation of dependencies will be driven by that.
I had the same problem with my project. And when I looked at my npm-shrinkwrap.json file, I saw dependencies: {}. So that's why it didn't install anything for me.

Resources