What are phantomChildren in package.json? - npm

When I install a module, a list of phantomChildren appears in the package.json file. What are phantomChildren?

I didn't find official documentation for npm package phantomChildren. But encountered some other explanation: https://rushjs.io/pages/advanced/phantom_deps/. It is about rast, but explains behavior of npm dependencies pretty well.
For example library A might import definitions from libraries B and C, but then B and C can both import from D, which creates a “diamond dependency” between these four packages.
A “phantom dependency” occurs when a project uses a package that is
not defined in its package.json file.
Some live example:
my-library/package.json
{
"name": "my-library",
"version": "1.0.0",
"main": "lib/index.js",
"dependencies": {
"minimatch": "^3.0.4"
},
"devDependencies": {
"rimraf": "^2.6.2"
}
}
my-library/lib/index.js
var minimatch = require("minimatch")
var expand = require("brace-expansion"); // ???
var glob = require("glob") // ???
Wait a sec – two of these libraries are not declared as dependencies
in the package.json file. How is this working at all!? It turns out
that brace-expansion is a dependency of minimatch, and glob is a
dependency of rimraf. During installation, NPM has flattened their
folders to be under my-library/node_modules. The NodeJS require()
function finds them there because it probes for folders without
considering the package.json files at all.
To summarize: if package uses dependencies of it's own dependencies, it can be treated as phantomChildren. Package doesn't have such dependencies directly but uses it from other places.

Related

deploy package to npm with toplevel import

I am trying to publish a package to npm but having trouble achieving the desired usage.
My project builds the files in a dist folder and when I do an npm publish it "works" but in order to use it I have to do:
import Something from 'package/dist';
But I want to be able to just import from the package itself like:
import Something from 'package';
In my package.json I have the following config:
{
"source": "src/index.js",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"scripts": {
"watch": "parcel watch",
"build": "parcel build",
}
}
I have tried copying the package.json into the dist folder after building and running npm publish from the dist folder but then the source is wrong (should be just index.js and not src/index.js) but if I have just index.js it will not build. It seems like most packages let you import from the top level directly (for example you can import React from 'react';)
I don't know what else to include in this question but I am happy to update with more info if required.
Add this to package.json
"exports": {
".": "./dist/index.js",
"./*": "./dist/*.js"
}
The exports field allows you to redefine paths to point to files or directories.

Bootstrap-vue components not imported when importing an npm package from local

Okay so maybe this has a fairly simple explanation which I don't know how to look up, but here's my conundrum:
if I publish my project (my-navigation) to the npm registry and then npm install it in another project (my-vue-app), it works all great, but!
if I try to npm install my-navigation directly from its folder on my machine into my-vue-app, I start getting runtime errors indicating that I have not correctly registered some bootstrap-vue components
I have even tried copying the files under node_modules/my-navigation into a folder and then npm installing that - I get the same errors
This is my main entrypoint:
import Vue from "vue";
import MyNavigation from "./MyNav.vue";
import {
BNavbar,
BNavbarBrand,
BNavbarNav,
BDropdownForm
} from "bootstrap-vue";
Vue.component("b-navbar", BNavbar);
Vue.component("b-navbar-brand", BNavbarBrand);
Vue.component("b-navbar-nav", BNavbarNav);
Vue.component("b-dropdown-form", BDropdownForm);
Vue.component("b-form-radio", BFormRadio);
import "./styles/bootstrap/mystyles.scss";
export default {
install(Vue) {
Vue.component('my-navigation', MyNavigation);
},
};
export { MyNavigation };
and in package.json:
"main": "./dist/my-navigation.umd.js",
"module": "./dist/my-navigation.esm.js",
"unpkg": "./dist/my-navigation.min.js",
"files": [
"dist/*"
],
"dependencies": {
"core-js": "^3.3.2",
"vue": "^2.6.10"
},
"peerDependencies": {
"bootstrap-vue": "^2.0.4"
},
"scripts": {
"build-bundle": "vue-cli-service build --target lib --name my-navigation ./src/main-navbar.js"
},
I can of course work around this by importing the components directly in MyNavigation.vue, but I want to register them globally for use in another component I'll be including in the npm package as well; and well it just seems weird to me that it works through the registry but not locally
Edit: it appears that through the registry, the bootstrap-vue components are being registered globally and are available then in my-vue-app by importing the npm package. This seems like a bad idea(?), so I probably don't want that anyway.
npm pack produces a .tgz file https://docs.npmjs.com/cli/pack.html
Importing from this file instead of from dist has the same behaviour as importing from a package on the registry.
Still not sure why or what npm does in creating this file, but that answers at least the question of how to mimic the behaviour of a registered package when importing from local/a repository.

Running Mocha 6 ES6 tests with Babel 7, how to set up?

For a library written in ES6/7, I want to compile (to ES5) the library to a dist/ folder. I also want to run the tests (written in ES6/7) for this lib.
My dev dependencies look like this (package.json):
"devDependencies": {
"#babel/cli": "^7.4.4",
"#babel/core": "^7.4.5",
"#babel/preset-env": "^7.4.5",
"#babel/register": "^7.4.4",
"chai": "^4.2.0",
"mocha": "^6.1.4",
"sinon": "^7.3.2"
},
My build and test scripts looks like this (package.json):
"scripts": {
"test": "mocha --require #babel/register",
"build": "babel src -d dist --presets=#babel/preset-env"
},
Running npm run build works well. The dist/ folder gets populated with transpiled files.
Running npm run test does not seem to work - this is my problem.
> mocha --require #babel/register
/Users/dro/Repos/lib/node_modules/yargs/yargs.js:1163
else throw err
^
ReferenceError: regeneratorRuntime is not defined
Initially I got an import error, which was resolved by adding .babelrc file.
Below is my .babelrc file content.
{
"presets": ["#babel/preset-env"]
}
I was reading about regeneratorRuntime and it got me to this link about babel-polyfill where they explain I shouldn't need that polyfill.
This will emulate a full ES2015+ environment (no < Stage 4 proposals) and is intended to be used in an application rather than a library/tool.
What is needed to set this up properly?
I am not using webpack.
Testing in ES6 with Mocha and Babel 7. Look here: https://dev.to/bnorbertjs/my-nodejs-setup-mocha--chai-babel7-es6-43ei or http://jamesknelson.com/testing-in-es6-with-mocha-and-babel-6/
npm install --save #babel/runtime
npm install --save-dev #babel/plugin-transform-runtime
And, in .babelrc, add:
{
"presets": ["#babel/preset-env"],
"plugins": [
["#babel/transform-runtime"]
]
}
Look at the project documentation:
npm install --save-dev babel-register
In your package.json file make the following changes:
{
"scripts": {
"test": "mocha --require babel-register"
}
}
Some features will require a polyfill:
npm install --save-dev babel-polyfill
{
"scripts": {
"test": "mocha --require babel-polyfill --require babel-register"
}
}
Below steps are for applying Babel transformations & core-js polyfills for your tests file:
💡 All transformations are only done per current environment, so only what is needed to be transpiled/polyfilled, will be. Target environments may be defined from a .browserslist file or as a property in package.json file. (read more here)
Step 1: Install packages:
#babel/core (read why)
#babel/preset-env (read why)
#babel/register (read why)
core-js (read why)
Note that #babel/polyfill exists and uses core-js under the hood. However, it was deprecated in favor of using core-js directly.
Step 2: Create a Babel configuration file babel.config.js
(used to be .babelrc.js or a .json file).
Create this file at the root-level of your code.
The most basic configuration (for just testing and not bundling) would look like this:
module.exports = {
presets: [
['#babel/preset-env', {
"corejs": "3.26",
"useBuiltIns": "usage"
}],
};
corejs - This is the polyfills library and should be specified with the minor version, otherwise x.0 will be used.
It is needed when testing code on rather "old" Node versions, which do not support all of the language methods. This ofc depends on your own usage of such javascript methods. (for example String.prototype.replaceAll).
useBuiltIns - must be set in order for the corejs polyfills to be applied. Read about it in the official docs.
By default, #babel/preset-env will compile your code for the current environment, but you can specify a different environment by setting the "targets" option in the configuration.
Ofc, you can add more presets like #babel/preset-react for example, if your code it written in React, or any other plugins which are specifically needed for your code.
Step 3: Connect mocha to the babel configuration:
In your package.json file
Under the scripts section, simply write something like this:
"test": "mocha \"src/**/*.test.js\""
Create a .mocharc.json file with this content:
{
"exit": true,
"color": true,
"require": ["#babel/register"],
"ignore": "node_modules"
}
This will apply Babel transformations to all of your test files.
If you need need to apply some special global javascript before/to all of your tests, you can add another file to the require setting, for example, fixtures.cjs:
"require": ["#babel/register", "fixtures.cjs"],
fixtures.cjs:
Below example applies a chai (popular alongside Mocha) plugin for testing DOM-related code:
var chai = require('chai'),
chaiDOM = require('chai-dom');
// https://stackoverflow.com/questions/62255953/chai-usechaihttp-once-or-in-every-test-file
// https://mochajs.org/#global-teardown-fixtures
exports.mochaGlobalSetup = function () {
chai.use(chaiDOM);
}
Interesting reads:
Babel vs babel-core vs babel-runtime
How does mocha / babel transpile my test code on the fly?

NPM - How do I override one of my dependencies dependency? [duplicate]

I would like to use the grunt-contrib-jasmine NPM package. It has various dependencies. Part of the dependency graph looks like this:
─┬ grunt-contrib-jasmine#0.4.1
│ ├─┬ grunt-lib-phantomjs#0.2.0
│ │ ├─┬ phantomjs#1.8.2-2
Unfortunately, there's a bug in this version phantomjs which prevents it from installing correctly on Mac OS X. This is fixed in the latest version.
How can I get grunt-lib-phantomjs to use a newer version of phantomjs?
Some additional context:
grunt-contrib-jasmine explicitly requires version "~0.2.0" of grunt-lib-phantomjs, which explicitly requires version "~1.8.1" of phantomjs.
Adding phantomjs to my package's dependencies first has no effect; both versions are installed and grunt-contrib-jasmine still uses the older versions (see: When installing a package with NPM, can you tell it to use a different version of one of its dependencies?).
You can use npm shrinkwrap functionality, in order to override any dependency or sub-dependency.
I've just done this in a grunt project of ours. We needed a newer version of connect, since 2.7.3. was causing trouble for us. So I created a file named npm-shrinkwrap.json:
{
"dependencies": {
"grunt-contrib-connect": {
"version": "0.3.0",
"from": "grunt-contrib-connect#0.3.0",
"dependencies": {
"connect": {
"version": "2.8.1",
"from": "connect#~2.7.3"
}
}
}
}
}
npm should automatically pick it up while doing the install for the project.
(See: https://nodejs.org/en/blog/npm/managing-node-js-dependencies-with-shrinkwrap/)
As of npm cli v8.3.0 (2021-12-09) this can be solved using the overrides field of package.json. As described in StriplingWarrior's answer
For example, the project has typescript version 4.6.2 as direct development dependency and awesome-typescript-loader that uses old version 2.7 of typescript. Here is how you can tell npm to use version 4.6.2 of typescript for awesome-typescript-loader:
{
"name": "myproject",
"version": "0.0.0",
"scripts": ...
"dependencies": ...
"devDependencies": {
"typescript": "~4.6.2",
"awesome-typescript-loader": "^5.2.1",
...
},
"overrides": {
"awesome-typescript-loader": {
"typescript": "$typescript"
}
}
}
If you don't use typescript as direct development dependency, then you have to write 4.6.2 instead of $typescript in overrides section:
{
"name": "myproject",
"version": "0.0.0",
"scripts": ...
"dependencies": ...
"devDependencies": {
"awesome-typescript-loader": "^5.2.1",
...
},
"overrides": {
"awesome-typescript-loader": {
"typescript": "~4.6.2"
}
}
}
For using the latest version of dependency:
{
"name": "myproject",
"version": "0.0.0",
"scripts": ...
"dependencies": ...
"devDependencies": {
"awesome-typescript-loader": "^5.2.1",
...
},
"overrides": {
"awesome-typescript-loader": {
"typescript": "latest"
}
}
}
Same overrides can be used for both dependencies and devDependencies.
If you're using npm version >5 but <8.3.0: edit your package-lock.json: remove the library from "requires" section and add it under "dependencies".
For example, you want deglob package to use glob package version 3.2.11 instead of its current one. You open package-lock.json and see:
"deglob": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz",
"integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=",
"requires": {
"find-root": "1.1.0",
"glob": "7.1.2",
"ignore": "3.3.5",
"pkg-config": "1.1.1",
"run-parallel": "1.1.6",
"uniq": "1.0.1"
}
},
Remove "glob": "7.1.2", from "requires", add "dependencies" with proper version:
"deglob": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz",
"integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=",
"requires": {
"find-root": "1.1.0",
"ignore": "3.3.5",
"pkg-config": "1.1.1",
"run-parallel": "1.1.6",
"uniq": "1.0.1"
},
"dependencies": {
"glob": {
"version": "3.2.11"
}
}
},
Now remove your node_modules folder, run npm ci (or npm install for old version of node/npm) and it will add missing parts to the "dependencies" section.
As of NPM v8.3, the correct way to deal with this is via the overrides section of your package.json file.
If you need to make specific changes to dependencies of your
dependencies, for example replacing the version of a dependency with a
known security issue, replacing an existing dependency with a fork, or
making sure that the same version of a package is used everywhere,
then you may add an override.
Overrides provide a way to replace a package in your dependency tree
with another version, or another package entirely. These changes can
be scoped as specific or as vague as desired.
To make sure the package foo is always installed as version 1.0.0 no
matter what version your dependencies rely on:
{
"overrides": {
"foo": "1.0.0"
}
}
There are a variety of other, more nuanced configurations allowing you to only override a package when it's a dependency of a particular package hierarchy. For more details, check out https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides
The only solution that worked for me (node 12.x, npm 6.x) was using npm-force-resolutions developed by #Rogerio Chaves.
First, install it by:
npm install npm-force-resolutions --save-dev
You can add --ignore-scripts if some broken transitive dependency scripts are blocking you from installing anything.
Then in package.json define what dependency should be overridden (you must set exact version number):
"resolutions": {
"your-dependency-name": "1.23.4"
}
and in "scripts" section add new preinstall entry:
"preinstall": "npm-force-resolutions",
Now, npm install will apply changes and force your-dependency-name to be at version 1.23.4 for all dependencies.
For those using yarn.
I tried using npm shrinkwrap until I discovered the yarn cli ignored my npm-shrinkwrap.json file.
Yarn has https://yarnpkg.com/lang/en/docs/selective-version-resolutions/ for this. Neat.
Check out this answer too: https://stackoverflow.com/a/41082766/3051080
Nested replacement with an entirely different package
Most of the strategies outlined in the other answers here work well if you are just interested in overriding the package's version number, but in our case, we needed to find a way to override a nested npm sub-dependency with a different package altogether. For details on why you would ever want to do this, please refer to the following question:
How to override a nested npm sub-dependency with a different package altogether (not just different package version number)?
Specify the tarball directly
For nested replacement of a package with an entirely different package using the npm-force-resolutions strategy that others have mentioned, you just need to provide a link to the tarball where you would normally specify the overriding version number.
As an example, for the case of replacing the vulnerable package, ansi-html, with the fixed fork of this package, ansi-html-community, your resolutions section of package.json should look like this:
"resolutions": {
"ansi-html": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz"
}
To find the link to the tarball, use the following command, modifying your registry as necessary:
npm view ansi-html-community dist.tarball --registry=https://registry.npmjs.org/
Also, note that for npm-force-resolutions to work when you run npm install, you will need a preinstall entry under the scripts section of package.json:
"scripts": {
"preinstall": "npx npm-force-resolutions"
}
#user11153 's answer worked for me locally, but when trying to do a clean install (aka deleting node_modules), I would get:
npm-force-resolutions: command not found
I had to update the preinstall script to be:
"preinstall": "npm i npm-force-resolutions && npm-force-resolutions"
Which ensures that npm-force-resolutions package is installed before attempting to run it.
That being said, if you're able to use yarn instead, I would do that and then use #Gus 's answer.
I had an issue where one of the nested dependency had an npm audit vulnerability, but I still wanted to maintain the parent dependency version. the npm shrinkwrap solution didn't work for me, so what I did to override the nested dependency version:
Remove the nested dependency under the 'requires' section in package-lock.json
Add the updated dependency under DevDependencies in package.json, so that modules that require it will still be able to access it.
npm i
I was about to go down the npm-force-resolutions route but it seems that simply including the dependency in my own package.json fixed the problem for me.
I believe this worked in my case because the original dependency allows for patch versions of the dependency in question that I wanted to update. Thus by manually including a newer version it still fulfilled the dependency of the original dependency and will use the one I've manually added.
Example
Problem
I need to update plyr to version 3.6.9 from 3.6.8
Mine
package.json
{
"dependencies": {
"react-plyr": "^3.2.0"
}
}
React Plyr
package.json
{
"dependencies": {
"plyr": "^3.6.8"
}
}
Notice for the plyr dependency it starts with ^ this means it can accept any minor patches. You can learn more about that here:
https://docs.npmjs.com/about-semantic-versioning#using-semantic-versioning-to-specify-update-types-your-package-can-accept
Updating Mine
This updates the plyr dependency from my package.json.
package.json
{
"dependencies": {
"plyr": "^3.6.9",
"react-plyr": "^3.2.0"
}
}
Based on the rest of the answers, I provide the same solution, but I display the package.json, as I struggled a little bit on where to place the override and how.
{
"name": "my-app",
"version": "snapshot",
"scripts": {
"ng": "ng",
"build-dev": "ng build --configuration development",
},
"private": true,
"dependencies": {
"#angular/animations": "~14.2.9",
"#angular/common": "~14.2.9"
...
},
"devDependencies": {
"#angular-devkit/build-angular": "^14.2.8",
....
},
"overrides": {
"loader-utils#>2.0.0 <3": "2.0.4",
"loader-utils#>3.0.0 <4": "3.2.1"
}
}
For November 2022 "loader-utils" security vulnerability, it was requested to
use the version 2.0.4, if you are in the 2.X
use the version 3.2.1, if you are in the 3.X
And to verify
add the package.json the override tag
delete the package-lock.json
run "npm install"
run "npm audit"
Run this first
npm i -D #types/eslint#8.4.3
it will solve the issue

Telerik platform Managing npm packages

hi i am building video streaming app through telerik platform. My app structure looks like :
my-project
app
- package.json
- app.js
node_modules
package.json
server.js
I have added firebase and bitmovin player plugin to my node_modules. Now the Telerik platform documentation says : to add require references to package.json file.
I do not get which package.json file needs to be opened . There are two files. The first one in the Project root which looks like:
{
"dependencies": {
"tns-core-modules": "2.5.1",
"bitmovin-player": "7.2.0-rc6",
"firebase": "4.1.2"
},
"devDependencies": {
"nativescript-dev-android-snapshot": "0.0.6",
"#types/firebase": "2.4.31"
}
}
The other package.json file is in the app folder looks like :
{
"name": "tns-template-blank",
"main": "app.js",
"version": "2.5.0",
"author": "Telerik <support#telerik.com>",
"description": "Nativescript blank project template",
"license": "Apache-2.0",
"keywords": [
"telerik",
"mobile",
"nativescript",
"{N}",
"tns",
"appbuilder",
"template"
],
"repository": {
"url": "https://github.com/NativeScript/NativeScript/commit/30aca890749e9e3fb9bd0f5ddc9de5b6995859bc"
}
}
and the app.js file looks like :
var application = require('application'),
mainModule = 'navigation/navigation';
application.start({
moduleName: mainModule
});
I do not get in which package.json file needs to be configured and where to enter the require reference for the module (like bitmovin player & firebase ) as mentioned in the telerik platform documentation which is shown in the picture above step no. 8.
please guide.
The first package.json (i.e. root package.json) is where any plugins go. If using the CLI, you can do tns plugin add nativescript-dom and it would then modify the package for you to be:
{
"dependencies": {
"tns-core-modules": "2.5.1",
"bitmovin-player": "7.2.0-rc6",
"firebase": "4.1.2",
"nativescript-dom": "2.0.0"
},
"devDependencies": {
"nativescript-dev-android-snapshot": "0.0.6",
"#types/firebase": "2.4.31"
}
}
The dependencies section is what needs to be changed; it needs the plugin name and the version you will be using. It that your package.json file is already correct for what you installed. You can also use http://plugins.nativescript.rocks for a list of plugins and their current versions.
A couple notes; based on you saying you needed bitmovin-player and firebase but using NativeScript; this won't work. The firebase and bitmovin-player you have referenced are not NativeScript plugins, so they won't work. To my knowledge bitmovin does not have NativeScript version (but my NativeScript-ExoPlayer plugin might be a good replacement) and then the NativeScript-Firebase I believe is the plugin you want for Firebase support in NativeScript.
I also see that you are using tns-core-modules 2.5.x; this means you want to get plugins that are 2.x compatible; the 3.x plugins will NOT work with TNS 2.x (and a large number of 2.x plugins won't work in 3.x).
When using a plugin (for example using my nativescript-dom) you do a var dom = require('nativescript-dom'); (or you can use const dom = ... as NativeScript can use ES6 grammer). You do not have to point to the actual js file inside the plugin. If the plugin is built correctly; it will automatically use the correct js file inside the plugin.
Finally in NativeScript the DevDependancies are for anything that is not being put into the application. In this case the android-snapshot plugin runs some build code during the build phase of the application.