vercel / next.js

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

`trailingSlash` setting not honored for next/image with placeholder="blur" #63805

Open gabrielf opened 5 months ago

gabrielf commented 5 months ago

Link to the code that reproduces this issue

https://github.com/gabrielf/nextjs-image-blur-trailingslash

To Reproduce

  1. Clone the repo
  2. Run npm i and npm run dev
  3. Visit http://localhost:3000 and check the network tab in the developer tools

Current vs. Expected behavior

Expected

Setting trailingSlash: true should add slashes to all image paths including the one to the blurred placeholder image. The example app should be served with no redirects.

Actual

The blurred placeholder has an image path without trailing slash which leads to an extra request (see screenshot below)

image

The path to the blurred image is generated as /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftest.fab2915d.jpg&w=8&q=70 (no trailing slash) when it should be /_next/image/?url=%2F_next%2Fstatic%2Fmedia%2Ftest.fab2915d.jpg&w=8&q=70 (with trailing slash)

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.3.0: Wed Dec 20 21:31:00 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6020
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 18.18.2
  npm: 9.8.1
  Yarn: N/A
  pnpm: 8.15.5
Relevant Packages:
  next: 14.2.0-canary.46 // Latest available version is detected (14.2.0-canary.46).
  eslint-config-next: 14.1.4
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.4.3
Next.js Config:
  output: N/A

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

Image optimization (next/image, next/legacy/image)

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

next dev (local)

Additional context

The problem only seems to exist when running with npm run dev.

gabrielf commented 5 months ago

Below is a git path that can be applied to the next.js repo to add a e2e test that fails due to the background-image, created by setting placeholder="blur" for a statically imported image, does not take the trailingSlash: true setting into account.

An image called test.jpg also need to be added to the e2e test using:

mkdir test/e2e/app-dir/trailingslash/public/
cp test/unit/image-optimizer/images/test.jpg test/e2e/app-dir/trailingslash/public/test.jpg
diff --git a/test/e2e/app-dir/trailingslash/app/page.js b/test/e2e/app-dir/trailingslash/app/page.js
index c00ce2fb17..ac956f2d88 100644
--- a/test/e2e/app-dir/trailingslash/app/page.js
+++ b/test/e2e/app-dir/trailingslash/app/page.js
@@ -1,4 +1,8 @@
 import Link from 'next/link'
+import Image from 'next/image'
+
+import testImage from '../public/test.jpg'
+
 export default function HomePage() {
   return (
     <>
@@ -6,6 +10,7 @@ export default function HomePage() {
         <Link href="/a/" id="to-a-trailing-slash">
           To a with trailing slash
         </Link>
+        <Image id="image-with-blur-placeholder" src={testImage} placeholder="blur" />
       </p>
     </>
   )
diff --git a/test/e2e/app-dir/trailingslash/trailingslash.test.ts b/test/e2e/app-dir/trailingslash/trailingslash.test.ts
index b1731aa254..98aba1774b 100644
--- a/test/e2e/app-dir/trailingslash/trailingslash.test.ts
+++ b/test/e2e/app-dir/trailingslash/trailingslash.test.ts
@@ -40,6 +40,12 @@ createNextDescribe(
       expect(await browser.waitForElementByCss('#a-page').text()).toBe('A page')
     })

+    it('should render blurred image placeholder with trailing slash', async () => {
+      const $ = await next.render$('/')
+
+      expect($('#image-with-blur-placeholder').attr('style')).toInclude('background-image:url("/_next/image/')
+    })
+
     it('should redirect route when clicking link', async () => {
       const browser = await next.browser('/')
       await browser