Force dependency to use specific sub dependency version - node.js

I am building my website code with webpack and npm modules and sutmbled upon the following problem:
My code uses jQuery 3.1.1 and adds some plugins to it.
I am also using a dependency that has a sub-depencency on jQuery <= 2.2.4.
The problem is, that the objects of the sub-dependency obviously don't know about my jQuery plugins, since the module uses a different jquery version.
How can I force all dependencies (top level and nested) to use one version of jQuery? So that require("jquery") always resolves to jQuery 3.1.1.
I've tried using npm shrinkwrap to override the dependency version but that does not seem to work. This is my modified shrinkwrap file:
{
"name": "example",
"version": "0.1.0",
"dependencies": {
"can": {
"version": "2.3.27",
"from": "can#>=2.3.23 <3.0.0",
"resolved": "https://registry.npmjs.org/can/-/can-2.3.27.tgz",
"dependencies": {
"jquery": {
"version": "3.1.1",
"from": "^3.1.1"
}
}
}
}
}
But the dependency of the module is still jQuery 2.2.4 and npm install prints npm ERR! invalid: jquery#3.1.1 /path/.../can/node_modules/jquery
Solutions to solve the issue with webpack instead of npm are also accepted.

I've found the solution myself using a webpack alias.
resolve: {
root: __dirname,
alias: {
"jquery": "node_modules/jquery/src/jquery",
}
}
Now every module that uses require('jquery') loads the jquery module located under the alias path regardless of the specified version in the module's package.json.
I'm leaving the question open for now since this solution requires webpack and I'd be interested if there is a npm only solution.

Following up on #McFarlane’s answer, this is the safe way to set the alias instead of using raw paths:
{
resolve: {
alias: {
"jquery": require.resolve("jquery"),
}
}
}

Related

How to make user install same version of depency A as depency B is using?

I used the variables in the title of this topics, but I also have the live example.
The alpha version 1.5.0-alpha.0 of the package #yamato-daiwa/es-extensions-localization-japanese depends on version 1.5.1 of #yamato-daiwa/es-extensions:
{
"name": "#yamato-daiwa/es-extensions-localization-japanese",
"version": "1.5.0-alpha.0",
"dependencies": {
"#yamato-daiwa/es-extensions": "1.5.1"
},
"peerDependencies": {
"#yamato-daiwa/es-extensions": ">=1.5.0 <1.6.0"
},
// ...
}
If to install the correct versions of both packages, both distributables will be put directly below node_modules/#yamato-daiwa:
{
"private": true,
"dependencies": {
"#yamato-daiwa/es-extensions": "1.5.1",
"#yamato-daiwa/es-extensions-localization-japanese": "1.5.0-alpha.0"
}
}
Now let's assume that I made a mistake and installed the version 1.5.0 of #yamato-daiwa/es-extensions. In this case, the additional instance of #yamato-daiwa/es-extensions will be put below node_modules/#yamato-daiwa/es-extensions-localization-japanese/node_modules.
The localization will be applied anymore, but there also will be any error, so if it was not the experiment, I could not undestrand the cause.
How to make use install the appropriate version of #yamato-daiwa/es-extensions? Is more strict peerDependencies like "#yamato-daiwa/es-extensions": "1.5.1" will be enough?
As you noted - you have 2 installations #yamato-daiwa/es-extensions - in main app's node_modules and in #yamato-daiwa/es-extensions-localization-japanese node_modules. Your application uses the package from its node_modules folder, but the localization uses another instance from its node_modules. That's why localization is not working.
To prevent this, you should enable strict-peer-deps property in the project's .npmrc file. npm will treat non-compatible peer dependencies as a failure.

How to update a dependency within a dependency?

I would like to update a 'handlebars' node module that is a dependency of Vue-Cli (see screenshot).
What's the correct way to do this?
Thank you
Add a resolutions field to your package.json file and define your version overrides.
It will look like this
{
...
"dependencies": {
...
},
"devDependencies": {
...
},
"resolutions": {
"EXAMPLE_PACKAGE": "EXAMPLE_PACKAGE_NEEDED_VERSION"
}
}
It shouldn't update the package in the dependency. But your application will use the needed version. It can be useful for example if some dependencies in your dependency have important security updates, and your dependency has not updated the version yet.

How to patch jest-rutime when using Yarn 2?

I am trying to follow the instructions in this repository to patch Jest.
Patch Jest.
It is suggested to use patch-package but I figured out that I can use yarn patch when using Yarn 2.
I managed to patch jest-runtime but seems Jest doesn’t seem to require jest-runtime in its package so I don’t know where it comes from to use it as a reference to declare the patched file.
Jest package.json
I understand if Jest was the one that needs to be patched I could declare it like this:
package.json
"devDependencies": {
"jest": "patch:jest#26.6.3#./patches/jest.patch"
}
I tried to use the same logic to include the following code to include jest-runtime but it didn't work.
"devDependencies": {
"jest": "^26.6.3",
"jest-runtime": "patch:jest-runtime#26.6.3#./patches/jest-runtime.patch"
}
How can I declare this patched jest-runtime so Jest can use it?
The Resolutions field in the manifest is the correct approach to declare the patched modules that we didn't add to devDependencies such as submodules.
The resolutions field allows you to instruct Yarn to use a specific resolution instead of anything the resolver would normally pick. This is useful to enforce all your packages to use a single version of a dependency, or backport a fix.
The fix for that issue:
{
...
"dependencies": {
"jest": "^26.6.3",
},
"resolutions": {
"jest-runtime": "patch:jest-runtime#26.6.3#./patches/jest-runtime.patch"
},
}

What is the proper package.json manner to publish a npm package developed with Browserify?

I am publishing a npm package developed with Browserify, and wonder what is the proper manner to construct a package.json.
The package is a node server-client app (it is actually atom package), and the client side is based on Browseriy.
./www/js/index.js -> ./www/js/index.bundled.js
The required modules are marked and highlight.js.
The both modules are used only on the client side code/file which is bundled by blowserfiy.
A lazy and simple solution would be simply, just to have
package.json A
{
......,
"dependencies":
{
...,
...,
"highlight.js": "*",
"marked": "*"
}
}
and to include the www/js/index.bundled.js file in the npm package files as it is after the browserify in my local dev environment.
However, now I think the npm package.json can be one of the below:
package.json B
{
......,
"dependencies":
{
...,
...,
},
"devDependencies":
{
"highlight.js": "*",
"marked": "*",
"browserify": "*"
}
}
In this case, browserified ./www/js/index.bundled.js file is left in the npm package, and treat marked and highlight.js as a devDependencies, and also browserify.
Then
package.json C
{
......,
"dependencies":
{
...,
...,
"highlight.js": "*",
"marked": "*",
"browserify": "*"
},
"scripts": {
"run": "browserify ./www/js/index.js -o ./www/js/index.bundled.js"
}
}
Just let you know, I have never tried this, and don't know this scripts-run actually runs on npm install myPackage, perhaps not, and maybe you know the proper configuration, maybe there's no such a thing.
In this scenario, ./www/js/index.bundled.js is excluded from the npm package file, and built from the latest npm packaged marked and highlight.js.
The reason I think this manner is somewhat proper is especially in the scenario the npm modules are used and shared in both server and client side.
For instance, take a look at dnode. This RPC module is developed by the same author of browserify (#substack), and should share the same version of dnode module in both server and client side. If a pre browserified ./www/js/index.bundled.js is bundled in the published npm package, it will be outdated compared to server side dnode. Sure we may be able to specify the version to install by package.json, but it's better to use the latest on both server and client side.
Any suggestion? Thanks.
I suggest to use second choice and specify browserify as a devDependency.
You have to build it before you publish your package to npm registry, so users won't need to install browserify themselves.
It's also useful to add a Makefile and make as a prepublish script.

Why isn't npm installing dependencies when I have an item inside devDependencies?

When I remove the devDependencies array, trimArguments installs fine. If I give it a dev-dependency, it seems to completely ignore trimArguments. No warning, just silent failure. My package.json is the following:
{"name":"asyncFuture",
"version":"0.1.0",
"main": "asyncFuture.js",
"dependencies":[
"git+https://git#github.com/fresheneesz/trimArguments.git#578afe0fa6ce96797c36e018bf5bae31b508a02f"
],
"devDependencies": [
"git+https://git#github.com/fresheneesz/deadunit.git#8395e438492267b94ef51ee4f94a6d6c8f1c15da"
],
"repository": {
"type": "git",
"url": "git://github.com/fresheneesz/asyncFuture"
}
}
Is this an NPM bug or am I misunderstanding how to use this? NPM version 1.3.8 on windows 7 32-bit
UPDATE
It's looking like npm is ignoring any package except for the last one, even if I put all dependencies under the "dependencies" array (and get rid of devDependencies). This has to be a bug. I'm gonna file a ticket.
When using URLs as dependencies:
You may specify a [...] URL in place of a version range.
Noting that dependencies are:
specified with a simple hash of package name to version range.
You still need to specify the package name even when using a (Git) URL.
"dependencies": {
"trimArguments": "git+https://git#github.com/fresheneesz/trimArguments.git#578afe0fa6ce96797c36e018bf5bae31b508a02f"
},
"devDependencies": {
"deadunit": "git+https://git#github.com/fresheneesz/deadunit.git#8395e438492267b94ef51ee4f94a6d6c8f1c15da"
}
dependencies and devDependencies are not arrays; they are maps.
https://npmjs.org/doc/json.html#dependencies

Resources