Is there a way to customize a package.json file using postinstall?

I've developed a package on npm that generates an "scss directory structure" and my goal is to include custom scripts in the package.json file located at the project's root.

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

Currently, all I can do is copy a file named "package.json" to the local directory, potentially overwriting any existing file of the same name.

My intention is not to overwrite existing files, but rather to simply append scripts like "npm run watch," enabling users to jump right into their projects without manually configuring these scripts themselves.

Your assistance is greatly appreciated.

Answer №1

Here is a helpful node.js script for you to use:

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

To implement the above script, add the following to the scripts section of your project's package.json file under the postinstall script:

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

Note: Make sure that the `post-install.js` script is in the same directory as your `package.json` file.


Explanation:

  1. The code snippet shown above retrieves the path to the consuming project's package.json using the following line:

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

    This logic extracts the pathname at position index 0 from an array returned by require.main.paths, splits it at 'node_modules', and then concatenates 'package.json' to obtain the desired path.

  2. The script then proceeds to parse the package.json file and store the parsed JSON object in the variable json.

  3. If the package.json does not contain a scripts key, one is created with an empty object assignment:

    if (!json.hasOwnProperty('scripts')) {
      json.scripts = {};
    }
    
  4. Following this, a custom npm script can be defined within the script by modifying the placeholder text '<some_commands_here>'. This part of the script allows for flexibility based on individual requirements.

    json.scripts['watch'] = '<some_commands_here>';
    
  5. Finally, the updated JSON data is converted back into a string format using JSON.stringify(). The modified content is then written back to the original package.json file using fs.writeFileSync().

Answer №2

If you want to automate tasks in your project, you can create a small script and include commands directly in the scripts section of your package.json.

Example Script:

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

Updated package.json:

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

You can also write a simple inline script as a string and execute it using node -e.

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

Answer №3

I encountered a similar issue myself. In case you find yourself needing to make changes to the root package.json file while your module contains a "postinstall" script and is being used as an npm dependency in another project, you will have to navigate through parent directories until you reach a point where no package.json file is found.

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');

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The onClick function is failing to work properly, and I need to pass the value of 'cid' based on the result of the button

Is it possible to pass the 'courseid' to local storage when a button is clicked? I am having trouble with onclick not working. How can I retrieve the relevant 'courseid' in the onclick function based on the button clicked? handleClick ...

Utilizing AJAX in Wordpress to Dynamically Update HREF Links

My website now has AJAX functionality, and you can see a live example at www.mathewhood.com. I am interested in changing the URL format when clicked from To something like , without the /sitefiles/ for security reasons. Below is my code. If anyone is ex ...

When initiating the react-native start command, the process abruptly crashes and prompts the error message: "Error npm[11708]: c:wssrcutil-inl.h:369: Assertion `!(n > 0) || (ret

Currently attempting to launch a react-native app, but encountering issues. Upon running npx react-native start, the server starts successfully, displays the react logo, but then crashes with an error message: npm[11708]: c:\ws\src\util-inl. ...

Auto-complete feature not populating the input field in Google Chrome

Within my register form, I have various INPUT tags present. One of these INPUTs has the name email. <input type=text name=email id=email> When filling out this form in Chrome, I encounter a peculiar behavior. Upon clicking on the email input field ...

How to manage ajax URLs across multiple pages?

I have my website set up at http://example.com/foo/ within a directory, separate from the main domain. Through the use of .htaccess, I've configured the URLs to appear as http://example.com/foo/about/, http://example.com/foo/polls/, http://example.com ...

Steps for accessing the controller scope from a directive nested within another directive:

I am in the process of developing code that is as generic as possible. Currently, I have 2 directives nested within each other, and I want the inner directive to call a method on the main controller's $scope. However, it seems to be requesting the m ...

Seeking help with a Javascript regex inquiry

I am currently utilizing JavaScript regex for the following task: I have gathered the HTML content from a page and stored it within a string. Now, I aim to identify all URLs present on this page. For instance, if the document includes-- <script src = ...

Discover how to access all of the response headers from an HTTP request in Angular

Currently, I am utilizing HttpClient to make a request for a `json` file. My intention is to have the file cached using `ETag`, however, this feature does not seem to be functioning as expected. Upon investigation, it appears that the absence of sending of ...

using regular expressions to find unclosed font tags that match on a single line

Even though regex is not typically recommended for parsing HTML, in this case we are dealing with a single line string input to a function. For example: <font color = "#ff0000"> hello </font>. I want the regex pattern to match only if the tag ...

What is the process for transferring an environment.json file to the output directory and then utilizing it with Webpack 4?

Our application is expanding with multiple environments and vendors on the horizon. While the traditional approach of running webpack --env.NODE_ENV=myenvironment works for now, it will soon become inefficient. The main objective here is to streamline the ...

React Big Calendar encountered an error: The element type provided is not valid, as it is expected to be a string for built-in

Error One: The element type is invalid: it was expecting a string (for built-in components) or a class/function (for composite components), but received undefined. This could be due to not exporting your component correctly from the file where it's d ...

What is the best way to retrieve strings from an asynchronous POST request?

I am currently working on implementing a signup function in my Angular app using a controller and a factory. However, I am facing an issue where the strings (associated with success or failure) are not being returned from the factory to the controller as e ...

Unleashing the power of XPath and wildcards in AJAX

Can anyone explain why the variable objProperties, which contains an xpath with a wildcard, is coming up empty in this scenario? function getXMLServerObject (httpType, cmd, isAsync) { var object = new Array(); $.ajax({ type: httpType, ...

Obtain a specific portion of text from a string that resembles a URL

$("#index-link")[0].search = "?isNameChecked=False&isDateChecked=False&isStatusChecked=True" Is there a way to use jQuery to identify whether isStatusChecked is set to true or false in the given string? ...

A step-by-step guide to adding a checkbox column dynamically within handsontable

I am currently utilizing handsontable within a jsfiddle at http://jsfiddle.net/kc11/cb920ear/1/. My task involves dynamically inserting a checkbox column before the existing data. The structure I am working with appears to be a multidimensional array, as s ...

React-router-dom v6 causing MUI Drawer to not render

I have implemented ReactJS and I am working on incorporating a drawer/menu to display different routes on each page. I have set up the routes using react-router-dom@v6 in my index.js file. When I directly enter the URL for a specific page, I can see the co ...

Use ag-Grid to customize your column headers with checkboxes, allowing you to easily select or deselect all items in that column. This feature is not limited to

In my experience with ag-grid, I often find myself needing to customize the first column header to include a checkbox. This allows me to easily perform actions such as selecting all or deselecting all rows in the grid. It's important to note that this ...

Unable to access the property '__reactAutoBindMap' as it is undefined

I've been struggling with setting up server side rendering with React for the past week. It's a new project using an express server and I'm trying to render a simple hello world react app that utilizes react-router-component. To get some he ...

Adding a gradient to enhance an SVG chart

Hey there! I'm currently experimenting with Plotly to create some awesome charts, and I've been trying to figure out how to give my area-charts a gradient instead of the usual fill with opacity. This is how I typically build my graph: Plotly.ne ...

After using browserify, when attempting to call the function in the browser, an Uncaught ReferenceError occurs

I am currently in the process of creating a compact NPM package. Here is a basic prototype: function bar() { return 'bar'; } module.exports = bar; This package is meant to be compatible with web browsers as well. To achieve this, I have inst ...