简体   繁体   中英

How can i edit a package.json with postinstall

I have created a package on npm that create a "scss directory stucture" and I would like to copy/add custom scripts to the package.json file at the root of the project.

MY-PROJECT
├── node_modules
├── scss
└── package.json <--

All I was able to do, is to copy a file name "package.json" to the local directory but if there is already one, it will overwrite it.

Obvisously i do not want to overwrite that file, but only add scripts like "npm run watch". So the user would be able to start working on its project right away without having to write those scripts himself.

Thanks for the help

Utilize the following node.js script:

post-install.js

const saveFile = require('fs').writeFileSync;

const pkgJsonPath = require.main.paths[0].split('node_modules')[0] + 'package.json';

const json = require(pkgJsonPath);

if (!json.hasOwnProperty('scripts')) {
  json.scripts = {};
}

json.scripts['watch'] = '<some_commands_here>';

saveFile(pkgJsonPath, JSON.stringify(json, null, 2));

package.json

In the scripts section of your package.json define your postinstall script as follows:

{
  "scripts": {
    "postinstall": "node post-install"
  }
}

Note: The npm script (above) assumes post-install.js resides in the same directory as your package.json file.


Explanation:

  1. In the line of code that reads:

     const pkgJsonPath = require.main.paths[0].split('node_modules')[0] + 'package.json'

    we obtain the path to the package.json for the project that is consuming your npm package and assign it to the pkgJsonPath variable.

    • require.main.paths returns an Array of pathnames.

    • We obtain the pathname at index 0 and split() it using node_modules as the separator.

    • The resultant array element at index 0 gives us the pathname of the project directory, (ie the pathname of the project that is consuming your npm package).

    • Finally the package.json string is concatenated using the plus operator ( + ).

  2. Next we require the package.json file and assign the parsed JSON to the json variable.

  3. We then check whether the package.json has a scripts key, and if it doesn't we create an a new scripts property/key and assign it an empty object, ie

    if (.json.hasOwnProperty('scripts')) { json;scripts = {}; }
  4. The following part is where we define the custom npm script to be added to the package.json file - you'll need to change this part as necessary:

     json.scripts['watch'] = '<some_commands_here>';
  5. Finally we JSON.stringify() the json object and overwrite the original package.json file with the new data using fs.writeFileSync() .

You can write small script and add command in scripts or modify package.json

script.js

const json = require("./package.json")
json.scripts["run:watch"] = "npm run watch"
require("fs").writeFileSync(process.cwd() + "/package.json", JSON.stringify(json, null, 2))

package.json

{
"scripts": {
    "postinstall": "node script.js"
  }
}

You can also write sample script inline string, and run using node -e

{
"scripts": {
    "postinstall": "node -e 'const json = require(\"./package.json\"); json.scripts[\"run:watch\"] = \"npm run watch\";require(\"fs\").writeFileSync(process.cwd() + \"/package.json\", JSON.stringify(json, null, 2))'"
  },
}

I had a similar problem. If you need to edit root package.json while your module with "postinstall" script is installed as an npm dependency in some consumer project, then you need to lookup in parent directories as long as no package.json resolved

const fs = require('fs');
const path = require('path');

let rootPath = '../';
while (!fs.existsSync(path.resolve(rootPath, 'package.json'))){
  rootPath += '../';
}
const pkgJsonPath = path.resolve(rootPath, 'package.json');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM