Tuesday, January 10, 2017

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

Leave a Comment

So I need to read the package.json before installing a new package via npm.

Why reading package.json in the first place?

Well I am 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. The reason I do that for is because those packages contain CSS (which has a global namespace) and would just overwrite each other. This is for scoped private packages and not for wider use. 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?

1 Answers

Answers 1

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" } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment