Replace a node package with a custom solution

Within my package.json, I have specified a dependency as "protractor": "2.1.0". This particular package is dependent on another package called "jasminewd2": "0.0.5".

The behavior of the jasminewd2 package is something that I want to modify. So, I decided to download its source code and make the necessary changes. According to Yarn's documentation, it is possible to use a local source for packages:

yarn add file:/path/to/local/folder
will install a package from your local filesystem. This feature comes in handy when you want to experiment with packages that haven't been published to the registry yet.

Upon executing this command,

  1. "jasminewd2": "file:\\CustomNodeModules\\jasminewd2"
    is added to my package.json.
  2. This addition is reflected in my yarn.lock file as well:

    "file:\\CustomNodeModules\\jasminewd2", <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d1bbb0a2bcb8bfb4a6b5e391e1ffe1ffe4">[email protected]</a>:
      name jasminewd2
      version "0.0.5"
      resolved "https://registry.yarnpkg.com/jasminewd2
         /-/jasminewd2-0.0.5.tgz#528609a124dfc688c1e3f434a638e047066cd63e"
    

Despite these changes, the folder node_modules/jasminewd2 still contains the original version sourced from npm. How can I ensure that Yarn installs my modified version instead?

Answer №1

It seems that the solution provided may not be effective because jasminewd2 is a transitive dependency of protractor, rather than a direct one. Therefore, adding it directly may not have the intended impact.

To address this issue, there are three potential approaches you can consider:

  1. If your changes are temporary and geared towards development or troubleshooting, you could utilize `yarn link` as outlined in the accompanying documentation.
  2. Alternatively, for a more permanent solution, you might choose to fork both the protractor and jasminewd2 packages and specify them in their respective package.json files using the syntax detailed here.
  3. Another option is to leverage the yarn's resolutions feature (or an equivalent in PNPM) by specifying a desired version or URL for the package. More information on this can be found in the Yarn documentation.

Based on my experience, options 2 and 3 come with a caveat related to package manager cache handling. Specifically, the git repository's HEAD is only fetched during the initial installation of the dependency. Subsequent installations rely on the cached version, potentially leading to outdated versions being used. One workaround is to reference a specific commit hash in the dependency declaration like so:

"dependency": "user/repo.git#aef38fb2adc73304ae1ea87b0d607ad7fadc4d0g"
.

Answer №2

How to Customize a Submodule Using Postinstall and Git

When you want to install a package from a git repository using npm, you usually need a specific commit or version. To override a submodule for testing purposes, I like to create a custom branch and use the postinstall hook of npm.

To customize a package, add a script to the postinstall in your package.json file:

"scripts": {
  "postinstall": "./postinstall.sh",
  "start": "node index.js"
},

In the postinstall.sh bash script, you can remove existing packages and clone them from GitHub:

#!/bin/sh

function override_pkg {
  USER=$1
  REPO=$2
  DEST=$3

  rm -rf node_modules/$DEST

  echo "Overriding $DEST..."

  if [ -d custom_modules/$DEST ]; then
    cd custom_modules/$DEST
    git pull
    cd ../../
  else
    case $REPO in
      *:*)
      REPOBR=(${REPO//:/ })
      git clone -b ${REPOBR[1]} https://github.com/$USER/${REPOBR[0]}.git custom_modules/$DEST
      ;;
      *)
      git clone https://github.com/$USER/$REPO.git custom_modules/$DEST
      ;;
    esac
  fi

  npm install custom_modules/$DEST
}

# func       user    repo   branch dest
override_pkg johndoe myrepo:branch mynpmpackage

This script clones a package into the custom_modules folder and installs it locally using npm. You can also make local changes to override the package as needed.

If you want to test different configurations in multiple environments, you can create separate folders for node_modules:

First, install original modules in a specific folder:

yarn --modules-folder=original-modules

Then, copy or add custom modules to another folder:

cp -r original-modules custom-modules
Or use yarn to add more custom modules:
yarn add <modulename> --no-lockfile --modules-folder=custom-modules

You can switch between environments by setting NODE_PATH before starting your application:

For the normal environment:

NODE_PATH=original-modules npm start

For the custom environment:

NODE_PATH=custom-modules npm start

Make sure the node_modules folder does not exist when switching environments to ensure the override works properly.

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

Ways to inform ngForm that the nested form has been submitted

What I understand Within Angular 1.3 and higher, I can utilize $submitted to determine if the specific form has been submitted successfully. This function works flawlessly when working with a form structured in the following manner: <form name="myForm ...

Encountered an error while attempting to convert react-native-reanimated-65-jsc.aar

ERROR: App installation failed after 19 seconds Failed to install the app. Ensure your Android development environment is properly set up. Follow this link for setup instructions: https://reactnative.dev/docs/environment-setup. Erro ...

What is the process for assigning a random string value to each document within a mongodb collection using the mongo shell?

Looking to assign a randomly generated string property to every item in a MongoDB collection. Planning to leverage the mongo shell and the updateMany function for a swift and efficient solution. ...

Using Javascript to dynamically add an element to an array with a unique index

Given let inputArray = []; $('some_selector').each(function() { let outer, inner; outer=$(this).parent().attr('some_property'); inner=$(this).attr('a_property'); if (!inputArray[outer]) inputArray[outer] = ...

Troubleshooting HTTP Issues in Angular 2

I am currently facing an issue with my Angular 2 project's Http functionality. I have defined it as a parameter in the constructor, but it keeps printing as undefined. Below is the snippet of code from my project: import 'rxjs/add/operator/toPro ...

The divs are crashing into each other and moving at varying speeds

I have created a mini game inspired by diep.io on codepen, where you can upgrade your reload and shooting capabilities. However, I have encountered an issue where the bullets start moving at different speeds and end up overlapping each other after shooting ...

Raphael's path adorned with arrow-shaped tips

Recently delving into raphael.js, I am attempting to create an arrow head on a raphael path element (or draw an arrow from point A to point B). Here is the raphael path (line) that I have sketched from point A to point B on my canvas. Assuming that the val ...

Encountering error "Unable to find module 'babel' while executing dist"

I have developed my project using the generator-react-webpack framework. Now, I am facing difficulties while trying to deploy my react app on Heroku. When building dependencies, I encountered an error: npm run copy & webpack --env=dist remote: ...

Send a redirect after a certain delay to a URL stored in a variable outside of the current scope

Upon making an ajax request, the JSON response contains a link that needs to redirect the user to another page after 3 seconds. The current approach used is: response = JSON.parse(res); var link = response.link; setTimeout("window.location.href=link",300 ...

combination of Vue methods from a separate file

Having some trouble sharing a method in Vue across files. Despite trying various suggestions found through research, I haven't been able to make it work. I did manage to get mixins working within the same file, but couldn't figure out how to impo ...

The component is failing to store its value within the database

I'm encountering an problem when attempting to save an option in the database. To address this issue, I created a component in Svelte called StatePicker that is responsible for saving US States. However, when I try to save it in the database using a ...

What is the functionality of react.js state?

As I delve into learning React.js, I've been quite impressed with its state management capabilities. However, I'm curious about the technical workings behind it. Does React.js utilize cookies or browser storage for its state management? ...

Transfer spoken words into a textbox using the keyboard-microphone feature on an iPad or mobile device

When we tap on a textbox on an iPad or mobile device in a web browser, the keyboard pops up on the screen. We have the option to choose the microphone and dictate the text directly into the input box using our voice instead of typing. Since speech convers ...

How can one implement closure in Angular 4?

I am looking to implement a nested function within another function in Angular 4 for closure. However, when attempting the code below, I encounter an error stating "cannot find name innerFn" outerFn(){ let a = "hello"; innerFn(){ console.log(a ...

Retrieving a property of an object within an array using JavaScript in AngularJS

Seeking advice on how to calculate the total price of products in an array when working within a callback function. Is there a method similar to myArray.(intheobject).price? Or is there a way to handle callbacks effectively to achieve accurate results? th ...

The .remove() method is ineffective when used within an Ajax success function

I am facing an issue with removing HTML divs generated using jinja2 as shown below: {% for student in students %} <div class="item" id="{{ student.id }}_div"> <div class="right floated content"> <div class="negative ui button compa ...

Performance comparison between Ember and Angular.JS in rendering a large table

I am planning to construct a substantial table containing a plethora of data (approximately 2000 elements <td>). I intend to include functions for calculating values based on model, but without incorporating any bindings. Primarily, my goal is to s ...

Setting up Firebase for a specific sub-application located in a designated folder

After using Firebase hosting to host my app in the root directory, I now want to serve a separate codebase for my forum on I have set up two targets: one for my main app in one repository and another for the forum in a separate repository. Additionally, I ...

Enhanced JavaScript Regex for date and time matching with specific keywords, focusing on identifying days with missing first digit

I have a specific regular expression that I am using: https://regex101.com/r/fBq3Es/1 (audiência|sessão virtual)(?:.(?!audiência|sessão virtual|até))*([1-2][0-9]|3[0-1]|0?[1-9])\s*de\s*([^\s]+)\s*de\s*((19|20)?\d\d) ...

What is the most effective method for implementing a fallback image in NextJS?

Lately, I've been immersed in a NextJS project that involves utilizing the YoutubeAPI to retrieve video details, such as thumbnail URLs. When it comes to fetching a full resolution image, the thumbnail URL typically follows this format: https://i.yti ...