denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
98.22k stars 5.41k forks source link

Next.js components are not importing types properly #25359

Open richardvanbergen opened 3 months ago

richardvanbergen commented 3 months ago

I was excited to try out deno on Next.JS after hearing about it on the syntax podcast. It runs well but unfortunately I'm getting a couple of type errors when importing the next core components like next/link and next/image.

This only happens in the editor with the LSP so it might not be the right place to post it so let me know.

For good measure in the project that I found it in I tried copy and pasting the compiler options into deno.json. It had no effect.

JSX element type 'Link' does not have any construct or call signatures.deno-ts(2604) 'Link' cannot be used as a JSX component. Its type 'typeof import("file:///Users/richardvanbergen/code/deno-nextjs-bug-example/node_modules/.deno/next@14.2.7/node_modules/next/link")' is not a valid JSX element type.deno-ts(2786)

JSX element type 'Image' does not have any construct or call signatures.deno-ts(2604) 'Image' cannot be used as a JSX component. Its type 'typeof import("file:///Users/richardvanbergen/code/deno-nextjs-bug-example/node_modules/.deno/next@14.2.7/node_modules/next/image")' is not a valid JSX element type.deno-ts(2786)

Reproduction Steps:

  1. Download the repo from the link below
  2. Enable Deno from the menu command bar Deno: Enable
  3. Ensure Deno Future is checked in the user settings
  4. Just for good measure, add DENO_FUTURE=1 explicitly in the settings.
  5. Navigate to src/app/page.tsx.
  6. Behold! Errors!

Version: Deno 1.46.2 Reproduction repo: https://github.com/richardvanbergen/deno-nextjs-bug-example

Side note: I can deal with it but is there a way to enable wildcard import aliases? Side side note: There's also an error importing the styles I personally don't care about that but if it's easy to answer then it might be worth documenting it.

nayeemrmn commented 2 months ago

This has the same cause as #24451. It would work if you replace <Link> with <Link.default>, but that shouldn't be necessary. It's a quirk of tsc's esm interop that isn't integrated here properly.

richardvanbergen commented 2 months ago

Thanks for looking at this so quickly.

For anyone else searching the workaround I'm now using is.

// rexport next default exports due to this bug: https://github.com/denoland/deno/pull/25484
// remove this when it's fixed

import NextLink from 'next/link'
import NextImage from 'next/image'

const Link = NextLink.default
const Image = NextImage.default

export { Link, Image }
{
  "imports": {
    "@next": "./src/components/next.ts"
  }
}
import { Link } from '@next'
nayeemrmn commented 2 months ago

https://github.com/denoland/deno/pull/25484#issuecomment-2335046615

It turns out this isn't a bug for Deno. If you add { "type": "module" } to your package.json and modify your tsconfig to the following Deno-like one:

{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "react": "^18",
    "react-dom": "^18",
    "next": "14.2.7"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18"
  }
}

It will necessitate rewriting src/app/page.tsx to this either way:

import NextLink from "next/link.js";
import NextImage from "next/image.js";
import * as React from 'react';

const Link = NextLink.default;
const Image = NextImage.default;

export default function Home() {
  return (
    <>
      <Link href="..." />
      <Image src="..." alt="..." />
    </>
  );
}

Which would work with both tsc and Deno. I'll close this issue for now @richardvanbergen If you want please try out this config and toggle deno.enable off and on to confirm.

yanickrochon commented 1 month ago

How is this closed and marked completed?

yanickrochon commented 1 month ago

This Next.js also fails:

import localFont from "next/font/local";

const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});

Saying that

This expression is not callable. Type 'typeof import("file:///home/yanick/dev/deno/variant/node_modules/next/font/local/index")' has no call signatures.deno-ts(2349)

However, the next/font/local has this single line:

export { default } from 'next/dist/compiled/@next/font/dist/local'

which, in turn, exposes:

export default function localFont<T extends CssVariable | undefined = undefined>(options: LocalFont<T>): T extends undefined ? NextFont : NextFontWithVariable;

and this is a perfectly valid function declaration.

Both localFont and Link, as the OP reported, evaluate just fine. No errors when the code is being executed. This is strictly a linting error, and it is a false one.

karlhorky commented 1 month ago

Yeah, there are quite a few issues with ESM fully-specified imports in Next.js, some of the latest:

Are The Types Wrong? and Publint also report errors:

dmint789 commented 1 month ago

This bug gave me SUCH a headache to find. I was just trying to build my Next JS application, and I kept getting the error Cannot read properties of undefined (reading 'bold'). NOTHING about that error message suggests that this has something to do with the Link component, lol. Should I report this in the Next JS repo, so they can set up an error message for these cases?

In any case, is this bug (the one in this issue) more relevant to Deno or Next JS?

Edit: I tried the workaround using Link.default, but I still get the same error. If someone needs a reproducible example, I can make a repo.

dmint789 commented 1 month ago

I also just realized that the same error happens when I try to build, when there is a component somewhere in my project that imports a component that doesn't exist. It just gives me that cryptic error message. The same message also occurs when I use an incorrect component attribute (e.g. <Link to=.../> instead of <Link href=.../>).

Edit: I believe this is an unrelated bug to this issue, and I'm sure this is a Deno bug, since I get proper error handling with npm run build. I think having such a cryptic error message is a bug in and of itself. It would be good to have it display something more similar to what NPM does.

dmint789 commented 1 month ago

This issue also displayed the same error message for a totally different bug. So far I have circumvented this cryptic error message by having my build task as deno lint && next build instead of just next build.

telmotrooper commented 1 month ago

One would expect that with @ry himself stating that we can use Next.js with Deno that Deno's language server would behave better when you implement a simple Next.js web app following the official documentation.

My experience refers specifically to VS Code, with the official Deno extension and "deno.enable": true in .vscode/settings.json, as well as with recommended JSX settings.

--

Just to be clear, I don't mean to be rude at all. Love the work you guys put on Deno!

fengkiej commented 1 month ago
{
  "deno.enable": true,
  "deno.disablePaths": [
    "./src/pages",
    "./src/app",
    "./src/components",
  ]
}
dmint789 commented 1 month ago
{
  "deno.enable": true,
  "deno.disablePaths": [
    "./src/pages",
    "./src/app",
    "./src/components",
  ]
}

Can you explain what this is supposed to fix? You just shared some config with no explanation. Is this meant to fix the issue in the title? If so, I don't see how this is at all relevant, it just disables the Deno LSP for the paths where you're likely to see Next JS components, that's just sidestepping the problem.

wanderer commented 1 month ago

This bug gave me SUCH a headache to find. I was just trying to build my Next JS application, and I kept getting the error Cannot read properties of undefined (reading 'bold'). NOTHING about that error message suggests that this has something to do with the Link component, lol. Should I report this in the Next JS repo, so they can set up an error message for these cases?

you need to do deno run --unstable-unsafe-proto -A npm:next build the Cannot read properties of undefined (reading 'bold') is coming from chalk

dmint789 commented 1 month ago

This bug gave me SUCH a headache to find. I was just trying to build my Next JS application, and I kept getting the error Cannot read properties of undefined (reading 'bold'). NOTHING about that error message suggests that this has something to do with the Link component, lol. Should I report this in the Next JS repo, so they can set up an error message for these cases?

you need to do deno run --unstable-unsafe-proto -A npm:next build the Cannot read properties of undefined (reading 'bold') is coming from chalk

Oh, that worked! Why is this not the default behavior? Also, why is the flag called "unstable"? I thought the convention was to call those kinds of flags "experimental".

dmint789 commented 1 month ago

Turns out, this is not only a problem with Next JS components. For example, the import from the jwt-decode library also errors out saying This expression is not callable.

veryhealthy commented 4 weeks ago

Hello everyone,

I initiated a next js project with app router and came to the same type error.

import Image from "next/image";
'Image' cannot be used as a JSX component.

Replacing <Image> by <Image.default> is working.

Thank you for good work.

fro-profesional commented 4 weeks ago

This bug gave me SUCH a headache to find. I was just trying to build my Next JS application, and I kept getting the error Cannot read properties of undefined (reading 'bold'). NOTHING about that error message suggests that this has something to do with the Link component, lol. Should I report this in the Next JS repo, so they can set up an error message for these cases?

In any case, is this bug (the one in this issue) more relevant to Deno or Next JS?

Edit: I tried the workaround using Link.default, but I still get the same error. If someone needs a reproducible example, I can make a repo.

I had the exact same issue, for me it was that I had deno code using jsr and nextjs normal app, I had to exclude in tsconfig the path for the deno script, so the nextjs doesn't pick it

stefvw93 commented 4 days ago

When you are creating a project with a tsconfig.json file (like NextJS has), it is recommended by the IDE plugin to disable the Deno LSP for that particular project.

For example, I am using NextJS in a deno workspaces environment, and I have to disable the LSP for the NextJS app to get proper type support.

I am using VS Code, and the Deno plugin reports:

A tsconfig.json with compiler options was discovered in a Deno-enabled folder. For projects with compiler plugins, it is recommended to disable the Deno language server if you are seeing errors.

I have a monorepo structure like:

apps/web (nextjs)
packages/ui
packages/lib

I updated my deno workspace settings in .vscode/settings.json like so:

{
  "deno.enable": true,
  "deno.disablePaths": [
    "apps/web"
  ]
}

With these settings, VS Code will use the default Typescript LSP, rather than the Deno LSP for my NextJS app.

I agree it is far from ideal, and gets especially annoying when using multiple typescript projects in a monorepository setup, but somewhat understandable given the fact that NextJS provides its own build tooling and Typescript configuration.