ai/nanoid

Error: No valid exports main found for 'node_modules\nanoid'

Closed this issue ยท 15 comments

Hello!

I was trying out nanoid in a TypeScript project and came across an issue when running the code through ts-node-dev.

The setup

EDIT: Forgot to include I have Node 13.3.0 installed.

The issue occurs with nanoid version 3.0.2 when running ts-node-dev.

Compilation with tsc passes without error.

I was able to reproduce the issue with the following setup:

package.json

{
  "private": true,
  "name": "01-todo-list",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc",
    "start": "ts-node-dev -r tsconfig-paths/register --respawn --no-notify --transpileOnly ./src/index.ts"
  },
  "keywords": [],
  "author": "dstrekelj <domagoj.strekelj@gmail.com>",
  "license": "IDGAF",
  "devDependencies": {
    "@types/node": "^13.11.1",
    "ts-node-dev": "^1.0.0-pre.44",
    "tsconfig-paths": "^3.9.0",
    "typescript": "^3.8.3"
  },
  "dependencies": {
    "nanoid": "^3.0.2"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./build",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": "./src",
    "paths": {
      "@app/*": ["*"]
    }
  },
  "exclude": ["node_modules", "build", "__tests__"]
}

src/index.ts

import { nanoid } from "nanoid";

console.log(nanoid());

Afterwards:

  1. npm install
  2. npm run start

The issue

Here is the complete transcript:

Using ts-node version 8.8.2, typescript version 3.8.3
Error: No valid exports main found for 'F:\projects\ts\challenges\reproducible\node_modules\nanoid'
    at resolveExportsTarget (internal/modules/cjs/loader.js:618:9)
    at applyExports (internal/modules/cjs/loader.js:499:14)
    at resolveExports (internal/modules/cjs/loader.js:548:12)
    at Function.Module._findPath (internal/modules/cjs/loader.js:650:22)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:948:27)
    at Function.Module._resolveFilename (F:\projects\ts\challenges\reproducible\node_modules\tsconfig-paths\lib\register.js:75:40)
    at Function.Module._load (internal/modules/cjs/loader.js:854:27)
    at Module.require (internal/modules/cjs/loader.js:1023:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (F:\projects\ts\challenges\reproducible\src\index.ts:1:1)
[ERROR] 18:39:55 Error: No valid exports main found for 'F:\projects\ts\challenges\reproducible\node_modules\nanoid'

Other information

After downgrading to nanoid 2.1.11 everything worked fine, though I had to install @types/nanoid to get completion.

Older 3.x versions throw the same error.

I'm thinking ts-node-dev is at fault or something in my configuration, but seeing as how version 3.x is still fresh I figured it's worth to create an issue just to be safe.

Might be related to #205?

ai commented

The ideal example of the issue ๐Ÿ‘

Honestly, I am overworked right now. I will be able to look only a few days after. Can you look into the ts-node-dev source code?

#205 happens because CRA does not support .cjs file ext, which we use for CommonJS (and CRA uses CJS during jest run). It could potentially be related (but TS should always use ESM files). Another way to find the problem is starting to remove options one by one. I am especially curious about "module": "commonjs".

ai commented

Until we will discover the problem, I added ts-node-dev notice to known issues of 3.0 migration guide
https://github.com/ai/nanoid/releases/tag/3.0.0

@ai No worries, I'll look into it tomorrow afternoon at the latest :) Thanks for the quick reply!

Alright, it's been a while since I last did some good old fashioned detective work. Couldn't resist but to give it a go now.

The first thing I tried was changing the "module": "commonjs" configuration as suggested. No success. The error messages changed to reflect the syntactical requirements set forth by the selected module resolution strategy. Other than that, there was nothing out of the ordinary to report.

Next up, I looked through the ts-node-dev source code. I added the --debug flag to the npm run start script to get some additional information and started off by looking through ts-node-dev/lib/wrap.js. At line 61 is where the trail goes cold as it jumps to another process.

The ts-node-dev library in itself is nothing more than a middleman. As described in the library's docs it's a "tweaked version of node-dev that uses ts-node under the hood". I ran tsc -v and ts-node -vv to compare TypeScript versions and both seem to use use 3.8.3, so it looks like it isn't that. Though it is odd that I run my code successfully through tsc, but not through ts-node.

Back on track with our error message, I searched through other issues on GitHub looking to pinpoint the line of code where the error message is constructed. This led me to find this issue:

home-assistant/home-assistant-js-websocket#113

... where the comment about using the new exports field and the comment about removing the exports field fixing a bug similar to this one grabbed my attention.

So I looked into how nanoid exports modules and noticed that package.json contains the "exports": { ... } property. I deleted the property (as per the aforementioned comment) and - no error! The script ran without any issue.

I'm not familiar with the exports property and seeing how that issue talked about supporting Node versions, I went to look for how exactly the thing works and how well it is supported. This led me to a StackOverflow post about TypeScript not supporting exports, which in turn led me to this issue:

microsoft/TypeScript#33079

I haven't had a change to go through it in detail yet and try fixes, but at least it's something.

ai commented

Wow. So big research ๐Ÿ˜

I will review it tomorrow, because I am going to sleep soon. Just want to say that you are great.

Thanks! :D

Here's a small update regarding ts-node and ts-node-dev.

I tried running ts-node directly using ts-node-dev --project tsconfig.json src/index.ts (and without the --project flag in case the config is the problem). The error persists.

npm list shows the following version information:

+-- ts-node-dev@1.0.0-pre.44
| +-- ts-node@8.8.2

Both are set to the latest versions available through npm at the time of writing.

So far it looks to be a ts-node issue. Are we running into this by chance?

TypeStrong/ts-node#935

ai commented

I added ts-node test to dual-publish and everything works.

We use this dual-publish to create a dual ESM/CJS package for Nano ID.

But I found that you should use CommonJS in your package. So you must have:

const { lib } = require('lib')

Will moving to CommonJS solved you problem with ts-node-dev?

I set up a project reflecting the fixture you provided. I still had the error.

Then I realised that my test results aren't valid unless I ran the tests in the same Node environment you use.

Assuming the latest version of Node is used to run the tests, I updated from 13.3.0 to 13.12.0.

I tried...

import { nanoid } from "nanoid";

... and...

const { nanoid } = require("nanoid");

After updating to Node 13.12.0 both worked without a problem!

I will try and play around with some additional samples to see if anything else breaks. As it stands now this seemed to be caused by my older version of Node acting up.

Thank you very much for your patience and expertise in figuring this out!

ai commented

Wow, Great!

I think although package.json specifies index.cjs for require export we are somehow still getting index.js instead. Manually copying over index.cjs and require'ing it fixes the problem for me on node@13.2.0. Though, that is obviously less than ideal. Tried require("nanoid/index.cjs") but `index.cjs is not exposed. I wonder if there is something wrong with the package configuration of this library?

ai commented

@cansin creates a separate issue with all details of your project. What builder do you use?

@cansin See the latest node 13 version is v13.14.0. Your version is very old.
https://nodejs.org/docs/latest-v13.x/api/

Wow, you guys are quick ๐Ÿ˜Š Ok, let me create a re-prod repo. Btw, if you are not supporting certain node versions, you should introduce an engines.node entry to package.json (referring to @TrySound 's comment).

Ok, @ai @TrySound here is the repro: https://github.com/cansin/nanoid-module-not-found-repro

And a sample run on my local:

cansin@localhost nanoid-repro % node --version
v13.2.0
cansin@localhost nanoid-repro % yarn --version
1.22.4
cansin@localhost nanoid-repro % yarn install
yarn install v1.22.4
[1/5] ๐Ÿ”  Validating package.json...
[2/5] ๐Ÿ”  Resolving packages...
[3/5] ๐Ÿšš  Fetching packages...
[4/5] ๐Ÿ”—  Linking dependencies...
[5/5] ๐Ÿ”จ  Building fresh packages...

โœจ  Done in 0.09s.
cansin@localhost nanoid-repro % node index.js 
internal/modules/cjs/loader.js:614
  throw e;
  ^

Error: No valid exports main found for '/Users/cansin/code/nanoid-reprod/node_modules/nanoid'
    at resolveExportsTarget (internal/modules/cjs/loader.js:611:9)
    at applyExports (internal/modules/cjs/loader.js:492:14)
    at resolveExports (internal/modules/cjs/loader.js:541:12)
    at Function.Module._findPath (internal/modules/cjs/loader.js:643:22)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:941:27)
    at Function.Module._load (internal/modules/cjs/loader.js:847:27)
    at Module.require (internal/modules/cjs/loader.js:1016:19)
    at require (internal/modules/cjs/helpers.js:69:18)
    at Object.<anonymous> (/Users/cansin/code/nanoid-reprod/index.js:1:20)
    at Module._compile (internal/modules/cjs/loader.js:1121:30) {
  code: 'MODULE_NOT_FOUND'
}

Edited: Sorry, made a small mistake prior. Just force-pushed and updated the console output here for the correct repro a minute ago.

Oh, sorry I should've created a separate issue. Will do that right away.