Ben Taliadoros
Ben Taliadoros

Reputation: 9451

punycode is deprecated in npm - what should I replace it with?

I'm using the npm module punycode in my Angular project. VsCode tells me it's deprecated and https://nodejs.org/api/punycode.html#punycode_punycode confirms:

The version of the punycode module bundled in Node.js is being deprecated. In a future major version of Node.js this module will be removed. Users currently depending on the punycode module should switch to using the userland-provided Punycode.js module instead.

The suggestion is to switch to the 'userland-provided' module. What is that?

There is a link to https://github.com/mathiasbynens/punycode.js and I tried including that in my package.json instead of 'punycode' and I get the same error.

Upvotes: 212

Views: 384561

Answers (13)

Wesley Silva
Wesley Silva

Reputation: 1730

Recently I faced this same issue.

I highly recommend you use the LTS(long term support) version of the node.

You can validate the version here: https://nodejs.org/en

so then in your command line you should perform:

$nvm install --lts
$nvm use --lts

This solves the problem, because makes you use the most tested and approved version.

If I use the version with latest features (actually 21.5.0 at time of writing instead of 20.0.8) I will face the problem reported here. There is an issue open in github to solve it by the way.

You can see more details here: https://github.com/yarnpkg/yarn/issues/9005

Upvotes: 134

Michael Karcher
Michael Karcher

Reputation: 4111

The issue is that Node.js has its own punycode module, which is deprecated starting with Node.js 22. The recommendation is to use a replacement punycode module from npm instead, which is not maintained by the Node.js crew. The most prominent replacement punycode package on npm is called punycode as well, and it will be pulled into a Node.js project, if packages.json contains a dependency on punycode. This mean any package that depends on punycode tries do the right thing. This does not mean, every package that depends on punycode actually does the right thing.

npm ls punycode, as suggested by some answers, lists packages with a declared dependency on "the userland-provided Punycode.js module", so it will find all packages that already comply with the migration path for the deprecation of the punycode module as supplied with Node.js. On the other hand, packages that just rely on a module named punycode being unconditionally available, because that module is part of the core Node.js runtime environment (which is the punycode module that is deprecated) are not found by this command.

The next key point is the behaviour of require("punycode"). This statements imports the "first module named punycode the JavaScript runtime stumbles upon". Most prominently, as the deprecated punycode module provided with Node.js still is present, it will be found first, even if a punycode package from npm is installed as well. So depending on punycode in pacakges.json only does half of what you need to do, because that dependency will just cause the punycode package to be downloaded, but not to be used instead of the deprecated punycode module. The require statement needs to be re-written in a way that it is unable to pick up the integrated punycode module and thus needs to resort to the punycode package inside node_modules. The recommended way of doing so is replacing require("punycode") by require("punycode/").

In my case, the issue was caused indirectly by jest-environment-jsdom which depends on jsdom: "^20.0.0" in the latest "stable" version 29.7.0. This dependency resolves to the latest 20.x version of jsdom, which is 20.0.3. Its packages.json file references whatwg-url: "^11.0.0", which will resolve to 11.0.0, as this is the only 11.x version of whatwg-url ever released. That package then references tr46: "^3.0.0", which resolves to version 3.0.0 of that package, which is a known offender that has already been mentioned in other answers.

Now let's look deeper into this package, though: In packages.json, the required dependency to download the "userland" aka "3rd party" punycode package is present, which means this package tries to not use the built-in punycode support. Nevertheless, it uses the require statement that will pick up the integrated punycode support, as long as that one is shipped with Node.js. The require statement has been fixed with version 4 of tr46, and seems to be the only significant change between version 3.0.0 and 4.0.0 except for bumping dependency versions.

So what does it mean for readers of this question? For me, the take-aways are:

  1. We do not need to get rid of dependencies on punycode.
  2. We do not get clear indications on the root cause of the issue by running npm ls punycode.
  3. Bumping dependencies helps, but this requires that bumped dependencies exist. For good reason, dependencies are locked to not apply to newer major versions. If any one package in the chain jest-environment-jsdom@latest (29.7.0 at the time of writing this post) -> jsdom@20.* (20.0.3 at the time of writing this post) -> whatwg-url@11.* (11.0.0 at the time of writing this post) would issue a patch or minor release that slightly bumps dependencies, we would get [email protected] or newer which fixes the issue (although for interop reasons, bumping the dependencies to a new major version is likely not allowed in a minor or patch version according to semver). Having a [email protected] with the punycode fix would help as well, and most likely be the smartest solution possible. Makes me wonder whether you can npm link a "private fork" of tr46 at a self-deployed 3.0.1.
  4. npm --node-options=--trace-deprecation run test did help me find the issue. (see below this list)
  5. Searching for require("punycode") or require('punycode') inside node_modules is also a way to find violators.
  6. Maybe praying also helps, because if a Node.js version comes along that no longer ships a punycode module, require("punycode") will no longer use that module instead of a "userland" module.
  7. Finally, the easiest short term solution is adding overrides for modules that contain the deprecated require("punycode") statement. For example, to work around the issue in [email protected], I added "overrides": { "[email protected]": "4.0.0"} to packages.json. As I understand it, although the major version has been bumped, it should work just fine in dependency chains created for major version 3.
(node:....) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead,
    at node:punycode:3:9
    at BuiltinModule.compileForInteralLoader (node:internal/bootstrap/ream:399:7)
    ....
    at require (node:internal/modules/helpers:141:16)
    at Object.<anonymous> (<workdir>/node_modules/tr46/index.js:3:18)

Note that the whole stack trace is just the internal logic in Node.js that processes the require statement in tr46/index.js and doesn't provide any value in diagnosis, just the lowest line points to the issue.

Upvotes: 4

Alin Galatan
Alin Galatan

Reputation: 308

If you want to use Node 21 or above (and sooner or later, you will, we all will), the main problem here is that many 3rd party libraries depend on native punycode and you don't have easy access to them.

Actually, you do have decent access.

See here the solution:

npm install module-alias

Then in your code:

const moduleAlias=require('module-alias')
moduleAlias.addAlias('punyCode', 'punyCode/')

From punycode.js/issues/137

Upvotes: 4

Asen Geshev
Asen Geshev

Reputation: 147

You need to install first Punycode. In the console type npm or yarn or 'pnpm i punycode', depending on what you use. Then open Notepad++ and and go to 'Search/Find in Files'. On 'Find what:' write 'require("punycode")' and on 'Replace with' write 'require("punycode/")'. Then press the 'Replace in Files' button and everything should be ok now.

Upvotes: -2

Russo
Russo

Reputation: 3062

Using the latest BunJs v1.1.26 solves the problem for me :)

Upvotes: -4

vijaivir
vijaivir

Reputation: 626

This warning just means that one of your project dependencies is using the punycode module that is deprecated. I fixed the error by following these steps:

  1. Run npm ls punycode to see the dependencies using punycode.
├─┬ [email protected]
│ └─┬ [email protected]
│   └─┬ [email protected]
│     └─┬ [email protected]
│       └── [email protected] deduped
└─┬ [email protected]
  └─┬ [email protected]
    └── [email protected]
  1. Run npm update <package1> <package2> ... to resolve the warning. In this example, I ran npm update expo expo-dev-client

Upvotes: 53

Choco Li
Choco Li

Reputation: 541

Step1:

Use npm ls punycode to find the dependencies that is using punycode.

In my case, that is ajv, which is from typescript-eslint/parser

from node_modules/@typescript-eslint/parser
  └─┬ [email protected]
    └─┬ [email protected]
      └── [email protected]

When I look into ajv and found it's resolved in newer version, I override the version of ajv by editing package.json

  "overrides": {
    "ajv": "^8.17.1"
  }

npm ls punycode says there is no dependence anymore. But in my case, when running the app again, the warning is still there.

Step2

By add --trace-deprecation the compile script, we found other dependencies that is still using punycode

"scripts": {
    "compile": "tsc && node --trace-deprecation dist/src/app.js",
}

And found whatwg-url is the one that is using punycode.

└─┬ @google-cloud/[email protected]
  └─┬ [email protected]
    └─┬ [email protected]
      └─┬ [email protected]
        └─┬ [email protected]
          └── [email protected]

When looking into whatwg-url, the newer version also address the issue.

We update package.json again

  "overrides": {
    "ajv": "^8.17.1",
    "whatwg-url": "^14.0.0"
  }

No warning anymore :)

Upvotes: 29

Ali Zaki
Ali Zaki

Reputation: 51

Fixed

As Mentioned at NPM

https://www.npmjs.com/package/punycode#installation

First

Throw VSC Search Bar

You Must Press 3 Points at Right Bottom AND Select ./node_modules IN 'files to include' Text Box

OR Right Click ON node_modules Folder and Select 'Find On Folder'

THEN You Can Replace ALL

require("punycode"); WITH require("punycode/");

AND All Ones with Single Quotes Too

require('punycode'); WITH require('punycode/');

Upvotes: 5

xuhdev
xuhdev

Reputation: 9370

While punycode is deprecated, you can still use it at least for now and bear with the warning. However, to prepare for its future removal, it's still good practice to figure out where it is used and address it before it is removed. It's better to be safe than sorry later.

  1. Trace down where punycode is used by passing --trace-deprecation option to node. If it's triggered by npx, run npx with ----node-options --trace-deprecation.
  2. Address the code that triggers the warning.
    • If this is your own code, replace punycode with alternatives.
    • If this is a dependency, contact the maintainer of the dependency. Chances are the dependency may be unmaintained if the warning has been left for a long time. If this is the case, it's better replacing the dependency.

Upvotes: 9

Allan Bazinet
Allan Bazinet

Reputation: 1837

Frequently, usage of the punycode module was simply for conversion of a domain name to ASCII, e.g., when MIME-encoding an address.

Yes, the module does a lot more, but commonly, you're just using the toASCII() function, handing it a domain name. For that, this deprecation, confusion over the magic trailing slash, further confusion when using ESM imports, all ends up being a bit complicated.

If that's the case, then the domainToASCII() function in the node:url package might be a simpler way to get your desired result.

Upvotes: 2

sharon
sharon

Reputation: 101

I also got the message:

(node:14220) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.

I solved it by running npm update ajv.

AJV stands for Another JSON Schema Validator.

Upvotes: -1

BkackBob
BkackBob

Reputation: 41

From my experience, this solution with ('punycode/') - does not work. It doesn't seem to have any problems with any LTS version, but on anything 21.^ and above - unfortunately not a single hack I've seen - does NOT work (so far). I tried the final LTS version (v20.11.0) this morning and it works.

Upvotes: 3

Sanchyan Chakraborty
Sanchyan Chakraborty

Reputation: 163

Refer to this GitHub issue

In my case, despite not using punycode directly in my codebase, Nodemailer relies on it. To address this, I implemented a custom script, as detailed in the linked GitHub issue.

If your situation differs, you may need to identify which library is utilizing punycode and apply a similar workaround until an official fix is released. Feel free to share a test case publicly, and I'd be happy to assist you further.

Upvotes: 6

Related Questions