vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.94k stars 26.87k forks source link

NextJs requests custom route when using `navigator.clipboard.writeText` #71288

Open cuongle-hdwebsoft opened 5 days ago

cuongle-hdwebsoft commented 5 days ago

Link to the code that reproduces this issue

https://github.com/cuongle-hdwebsoft/nextjs-bug

To Reproduce

  1. Start the application in development mode
  2. Go to homepage http://localhost:8080/
  3. Click the button Click me, and wait until it alerts Copy clipboard successfully
  4. Open server log in the terminal, it will appear ==> This route is called

Current vs. Expected behavior

Current behavior:

Expected behavior:

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.0.0: Mon Aug 12 20:51:54 PDT 2024; root:xnu-11215.1.10~2/RELEASE_ARM64_T6000
  Available memory (MB): 16384
  Available CPU cores: 10
Binaries:
  Node: 20.11.1
  npm: 10.2.4
  Yarn: 1.22.22
  pnpm: 9.12.0
Relevant Packages:
  next: 14.2.15 // Latest available version is detected (14.2.15).
  eslint-config-next: 14.2.15
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.6.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

create-next-app

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

No response

anibalalpizar commented 4 days ago

Hi, @cuongle-hdwebsoft.

Thank you for sharing the issue and providing the code that reproduces the unexpected behavior.

This issue occurs because when using navigator.clipboard.writeText with a URL pointing to your local server (in this case, http://localhost:8080/api/i/1), the browser may attempt to resolve or validate the URL being copied. This can sometimes trigger an automatic HTTP GET request to that URL on your server, causing your API route to be invoked and leading to the ==> This route is called message in the server logs.

Potential Solutions:

  1. Change the text being copied to the clipboard: To prevent the browser from making any additional requests, try copying plain text instead of a local URL. For example:
navigator.clipboard.writeText("Some random text").then(() => {
  alert('Copy clipboard successfully');
});

This should stop the browser from triggering the API route.

  1. Copy a URL unrelated to your local server: If you need to copy a URL, use one that is not associated with your server, like https://example.com, to avoid the browser making a request to your local API.
navigator.clipboard.writeText("https://example.com").then(() => {
  alert('Copy clipboard successfully');
});
  1. Check for prefetching or prerendering behavior: Next.js might be attempting to prefetch or prerender the local URL during development, which could also be causing the issue. If that's the case, try disabling prefetching globally in development by adding this configuration to your next.config.js:
module.exports = {
  experimental: {
    prefetch: false, // Disable prefetching in development
  },
};

The behavior is likely caused by the browser or Next.js attempting to resolve the URL being copied. Changing the text being copied or using an external URL should prevent the request from being made to the server.

Hope this helps resolve the issue! Let me know if you have any further questions.

cuongle-hdwebsoft commented 4 days ago

Hi @anibalalpizar For both solutions 1 and 2 I were able not to implement, because I am working on sharing URL features, and I want user can copy my URL to the clipboard. I also try solution 3 as well, but there is no prefetch option. I use Next v14.2.15, I don't exactly know if we've already have alternative option.

anibalalpizar commented 4 days ago

Hi @cuongle-hdwebsoft Thanks for the update and clarification. I see you need the ability to copy URLs specifically for your feature, so solutions 1 and 2 aren’t suitable in your case.

Alternative Solution: Isolating the Clipboard Action

  1. Use a different method to avoid resolving the URL: Instead of directly copying the full URL with the localhost domain, you could copy it in parts or encode it in such a way that the browser doesn’t attempt to fetch it, then decode it after pasting. Here’s an example:
const urlToCopy = encodeURIComponent("http://localhost:8080/api/i/1");
navigator.clipboard.writeText(urlToCopy).then(() => {
  alert('URL copied successfully');
});

When the user pastes the URL, it will be encoded, and you can guide them to decode it. While this might not be the ideal solution for a sharing feature, it avoids triggering requests to the API route.

  1. Use absolute URLs in production: This issue may only occur in your local development environment (localhost). In a production environment, copying the full domain (e.g., https://yourdomain.com/api/i/1) should not trigger this behavior since the browser wouldn’t automatically resolve local API routes the same way it does for localhost.

During development, you can replace the localhost URL with a placeholder or non-local domain for testing purposes, like this:

const isDev = process.env.NODE_ENV === 'development';
const urlToCopy = isDev
  ? 'https://example.com/api/i/1' // Replace localhost in dev
  : 'https://yourdomain.com/api/i/1'; // Real URL in prod

navigator.clipboard.writeText(urlToCopy).then(() => {
  alert('URL copied successfully');
});

Double-check custom routes: It’s also worth verifying if there’s anything specific in your custom API route configuration that could be triggering the request when copying the URL. If possible, review the setup of /api/i/[id] to ensure that it's not being hit unintentionally during the clipboard action.

Unfortunately, this issue might be tied to how the browser or Next.js handles local URLs during development. Isolating the URL or using absolute production URLs might mitigate the problem. Let me know if you need further assistance with these approaches or if you find an alternative solution in Next.js v14.2.15!

cuongle-hdwebsoft commented 4 days ago

Yes @anibalalpizar, thanks for the quick response. Actually, your solution does not fit for me, it's not convenient for the user to decode our encoded string, which would make it complicated for those. I'm sorry for including my additional information here late, but I also encountered with issue in production that was deployed in the Vercel host.