next.js icon indicating copy to clipboard operation
next.js copied to clipboard

fix: make typescript imports work with nodenext module resolution

Open lucgagan opened this issue 1 year ago • 4 comments

What?

A fix for nodenext module resolution.

https://www.typescriptlang.org/tsconfig#moduleResolution

Why?

  • fixes https://github.com/vercel/next.js/issues/46078

How?

Adding exports.

lucgagan avatar May 25 '23 22:05 lucgagan

Looks like this is failing because it cannot resolve dist/compiled/* paths.

I am not sure how to properly fix this.

"./dist/compiled/*": {
  "require": "./dist/compiled/*"
},

This fails because it cannot find /dist/compiled/chalk

The file we want is ./index.js. However, if we change export to:

"./dist/compiled/*": {
  "require": "./dist/compiled/*/index.js"
},

then other dependencies start to fail:

dist/compiled/arg/index.js/index.js

etc.

Long story short, I tried patching them one by one...

"exports": {
  ".": {
    "import": "./index.js",
    "types": "./index.d.ts"
  },
  "./amp": {
    "import": "./amp.js",
    "types": "./amp.d.ts"
  },
  "./app": {
    "import": "./app.js",
    "types": "./app.d.ts"
  },
  "./babel": {
    "import": "./babel.js",
    "types": "./babel.d.ts"
  },
  "./cache": {
    "import": "./cache.js",
    "types": "./cache.d.ts"
  },
  "./client": {
    "import": "./client.js",
    "types": "./client.d.ts"
  },
  "./config": {
    "import": "./config.js",
    "types": "./config.d.ts"
  },
  "./dist/compiled/@next/react-refresh-utils/dist/ReactRefreshWebpackPlugin": {
    "require": "./dist/compiled/@next/react-refresh-utils/dist/ReactRefreshWebpackPlugin.js"
  },
  "./package.json": {
    "require": "./package.json"
  },
  "./dist/compiled/@next/react-refresh-utils/dist/runtime": {
    "require": "./dist/compiled/@next/react-refresh-utils/dist/runtime.js"
  },
  "./dist/pages/*": {
    "require": "./dist/pages/*.js"
  },
  "./dist/compiled/devalue": {
    "require": "./dist/compiled/devalue/devalue.umd.js"
  },
  "./dist/compiled/regenerator-runtime": {
    "require": "./dist/compiled/regenerator-runtime/runtime.js"
  },
  "./dist/compiled/unistore": {
    "require": "./dist/compiled/unistore/unistore.js"
  },
  "./dist/next-config-validate.js": {
    "require": "./dist/next-config-validate.js"
  },
  "./dist/compiled/@babel/runtime/package.json": {
    "require": "./dist/compiled/@babel/runtime/package.json"
  },
  "./dist/compiled/webpack/*": {
    "require": "./dist/compiled/webpack/*.js"
  },
  "./dist/compiled/acorn": {
    "require": "./dist/compiled/acorn/acorn.js"
  },
  "./dist/compiled/neo-async": {
    "require": "./dist/compiled/neo-async/async.js"
  },
  "./dist/compiled/webpack/webpack": {
    "require": "./dist/compiled/webpack/webpack.js"
  },
  "./dist/compiled/loader-runner": {
    "require": "./dist/compiled/loader-runner/LoaderRunner.js"
  },
  "./dist/compiled/@edge-runtime/primitives/crypto": {
    "require": "./dist/compiled/@edge-runtime/primitives/crypto.js"
  },
  "./dist/compiled/stacktrace-parser": {
    "require": "./dist/compiled/stacktrace-parser/stack-trace-parser.cjs.js"
  },
  "./dist/compiled/@next/react-dev-overlay/dist/middleware": {
    "require": "./dist/compiled/@next/react-dev-overlay/dist/middleware.js"
  },
  "./dist/compiled/@edge-runtime/primitives/abort-controller": {
    "require": "./dist/compiled/@edge-runtime/primitives/abort-controller.js"
  },
  "./dist/compiled/watchpack": {
    "require": "./dist/compiled/watchpack/watchpack.js"
  },
  "./dist/compiled/arg/index.js": {
    "require": "./dist/compiled/arg/index.js"
  },
  "./dist/compiled/*": {
    "require": "./dist/compiled/*/index.js"
  },
  "./dist/client/components/noop-head": {
    "require": "./dist/client/components/noop-head.js"
  },
  "./dist/shared/lib/*": {
    "require": "./dist/shared/lib/*.js"
  },
  "./dist/compiled/sass-loader": {
    "require": "./dist/compiled/sass-loader/cjs.js"
  },
  "./dist/compiled/punycode": {
    "require": "./dist/compiled/punycode/punycode.js"
  },
  "./dist/compiled/string_decoder": {
    "require": "./dist/compiled/string_decoder/string_decoder.js"
  },
  "./dist/build/webpack/config/blocks/css": {
    "require": "./dist/build/webpack/config/blocks/css/index.js"
  },
  "./font/google/target.css": {
    "require": "./font/google/target.css"
  },
  "./font/local/target.css": {
    "require": "./font/local/target.css"
  },
  "./dist/client/*": {
    "require": "./dist/client/*.js"
  },
  "./dist/compiled/constants-browserify": {
    "require": "./dist/compiled/constants-browserify/constants.json"
  },
  "./dist/compiled/os-browserify": {
    "require": "./dist/compiled/os-browserify/browser.js"
  },
  "./dist/compiled/@next/font/*/loader": {
    "require": "./dist/compiled/@next/font/*/loader.js"
  },
  "./dist/compiled/@next/react-refresh-utils/dist/loader": {
    "require": "./dist/compiled/@next/react-refresh-utils/dist/loader.js"
  },
  "./dist/compiled/assert": {
    "require": "./dist/compiled/assert/assert.js"
  },
  "./dynamic": {
    "require": "./dynamic.js"
  },
  "./document": {
    "import": "./document.js",
    "types": "./document.d.ts"
  },
  "./error": {
    "import": "./error.js",
    "types": "./error.d.ts"
  },
  "./font": {
    "import": "./font/index.js",
    "types": "./font/index.d.ts"
  },
  "./font/google": {
    "import": "./font/google.js",
    "types": "./font/google.d.ts"
  },
  "./font/local": {
    "import": "./font/local.js",
    "types": "./font/local.d.ts"
  },
  "./head": {
    "require": "./head.js",
    "import": "./head.js",
    "types": "./head.d.ts"
  },
  "./headers": {
    "import": "./headers.js",
    "types": "./headers.d.ts"
  },
  "./image": {
    "import": "./image.js",
    "types": "./image.d.ts"
  },
  "./link": {
    "require": "./link.js",
    "types": "./link.d.ts"
  },
  "./navigation": {
    "import": "./navigation.js",
    "types": "./navigation.d.ts"
  },
  "./router": {
    "import": "./router.js",
    "types": "./router.d.ts"
  },
  "./script": {
    "import": "./script.js",
    "types": "./script.d.ts"
  },
  "./server": {
    "import": "./server.js",
    "types": "./server.d.ts"
  },
  "./web-vitals": {
    "import": "./web-vitals.js",
    "types": "./web-vitals.d.ts"
  }
},

Long story short, this approach is not going to work.

Pretty big problem as it makes next.js pretty much unusable with default TypeScript v5 settings.

lucgagan avatar May 25 '23 23:05 lucgagan

Just in case, leaving this PR open to drive attention. Not expecting work to continue, as it seems that this approach will not work. Unless there is some underlying work that can be done with how the loaders function.

lucgagan avatar May 28 '23 19:05 lucgagan

Why so complicated? Something as simple as this should work for the majority of the public API:

  "exports": {
    ".": "./index.js",
    "./*": "./*.js",
    "./font/*": "./font/*/index.js",
    "./dist/*": "./dist/*/index.js"
  },

parcelgraph avatar Nov 08 '23 18:11 parcelgraph

Why so complicated? Something as simple as this should work for the majority of the public API:

Unfortunately these wildcards are too aggressive,

  • they will change dist/compiled/arg/index.js to dist/compiled/arg/index.js/index.js
  • they will change next/link.js to next/link.js.js

We can fix these two issues with:

+    "./dist/*.js" : "./dist/*.js",
    "./dist/*" : "./dist/*/index.js",

But we still fail to resolve dist/compiled/devalue to dist/compiled/devalue/devalue.umd.js, dist/compiled/regenerator-runtime to dist/compiled/regenerator-runtime/runtime.js, etc. Now it seems the issue here is that if we use "exports" to resolve one name, we must use it to resolve ALL names. So we can't resolve some names through "exports" and everything else through the default node resolution algorithm.

There are a lot of these packages: find . -name "package.json" -exec jq -r 'if .main != "index.js" then .main else empty end' {} + | less

It looks like "exports" is not expressive enough to handle such vendored packages unfortunately.

llllvvuu avatar Feb 01 '24 01:02 llllvvuu

This wont work, it is not nearly enough to make things work I am afraid. But good for driving discussion. See https://github.com/vercel/next.js/issues/46078#issuecomment-2134508560

klippx avatar May 28 '24 07:05 klippx