slidev icon indicating copy to clipboard operation
slidev copied to clipboard

Static assets in public/ fail (redirect or resolve error) with nested entry point

Open waewoo opened this issue 8 months ago • 7 comments

Describe the bug

When the Slidev dev server (v51.6.0) is started with an entry point Markdown file located in a subdirectory (e.g., meetings/myfile.md), static assets from the public/ directory (e.g., /images/myimage.png) are not served or resolved correctly.

This manifests in one of two ways:

  1. Accessing the asset URL directly (e.g., http://localhost:3030/images/myimage.png) redirects to the base route (/), serving the first slide instead of the asset. Images referenced in slides using <img src="/images/..."> appear broken.
  2. Alternatively, the Vite pre-transform step fails with a Failed to resolve import "/images/myimage.png" from "meetings/myfile.md..." error in the console during startup.

This issue does not occur if the entry point Markdown file is at the project root (e.g., slides.md).

Minimal reproduction

Steps to reproduce the behavior locally:

  1. Ensure Node.js (>=18) and npm are installed.
  2. Create a new Slidev project: npm init slidev@latest (This should install @slidev/cli v51.6.0 or similar).
  3. Create the following directory structure within the project:
├── public/
│   └── images/
│       └── test.png  # Place any PNG image here
├── meetings/         # Subdirectory for entry point
│   └── meeting.md
├── package.json
└── node_modules/ # after npm install
  1. Add the following content to meetings/meeting.md:
# Test Slide

Image test (should appear below):
<img src="/images/test.png" alt="Test Image" width="100">
  1. From the project root, run the dev server targeting the nested file:
npx slidev meetings/meeting.md --port 3030
  1. Open http://localhost:3030 in the browser and navigate to the slide. Observe: The image is broken.

  2. Try accessing the image directly: http://localhost:3030/images/test.png. Observe: Results in a 404 Page /images/test.png not found error.

  3. Check the terminal console where slidev is running. Observe: Potentially (depending on exact conditions), Vite errors like Failed to resolve import "/images/test.png"... might appear.

Expected behavior:

The image should display on the slide. Direct access to http://localhost:3030/images/test.png should show the image. No Vite errors related to resolving /images/test.png should occur.

10:37:08 AM [vite] (client) Pre-transform error: Failed to resolve import "/images/c4-overview.png" from "meetings/meeting.md__slidev_1.md". Does the file exist?
  Plugin: vite:import-analysis
  File: /mnt/d/Travail/SandBox/slide-communaute/slidev/meetings/meeting.md__slidev_1.md:21:25
  19 |  }
  20 |  import { createElementVNode as _createElementVNode, createTextVNode as _createTextVNode, normalizeProps as _normalizeProps, guardReactiveProps as _guardReactiveProps, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  21 |  import _imports_0 from '/images/c4-overview.png'
     |                          ^
  22 |  
  23 |  

  10:37:09 AM [vite] Internal server error: Failed to resolve import "/images/c4-overview.png" from "meetings/meeting.md__slidev_1.md". Does the file exist?
  Plugin: vite:import-analysis
  File: /mnt/d/Travail/SandBox/slide-communaute/slidev/meetings/meeting.md__slidev_1.md:21:25
  19 |  }
  20 |  import { createElementVNode as _createElementVNode, createTextVNode as _createTextVNode, normalizeProps as _normalizeProps, guardReactiveProps as _guardReactiveProps, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  21 |  import _imports_0 from '/images/c4-overview.png'
     |                          ^
  22 |  
  23 |  
      at TransformPluginContext._formatLog (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:42499:41)
      at TransformPluginContext.error (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:42496:16)
      at normalizeUrl (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:40475:23)
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
      at async file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:40594:37
      at async Promise.all (index 3)
      at async TransformPluginContext.transform (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:40521:7)
      at async EnvironmentPluginContainer.transform (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:42294:18)
      at async loadAndTransform (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:35735:27)
      at async viteTransformMiddleware (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:37250:24)
10:37:11 AM [vite] Internal server error: Failed to resolve import "/images/c4-overview.png" from "meetings/meeting.md__slidev_1.md". Does the file exist?
  Plugin: vite:import-analysis
  File: /mnt/d/Travail/SandBox/slide-communaute/slidev/meetings/meeting.md__slidev_1.md:21:25
  19 |  }
  20 |  import { createElementVNode as _createElementVNode, createTextVNode as _createTextVNode, normalizeProps as _normalizeProps, guardReactiveProps as _guardReactiveProps, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  21 |  import _imports_0 from '/images/c4-overview.png'
     |                          ^
  22 |  
  23 |  
      at TransformPluginContext._formatLog (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:42499:41)
      at TransformPluginContext.error (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:42496:16)
      at normalizeUrl (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:40475:23)
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
      at async file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:40594:37
      at async Promise.all (index 3)
      at async TransformPluginContext.transform (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:40521:7)
      at async EnvironmentPluginContainer.transform (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:42294:18)
      at async loadAndTransform (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:35735:27)
      at async viteTransformMiddleware (file:///mnt/d/Travail/SandBox/slide-communaute/slidev/node_modules/vite/dist/node/chunks/dep-Bn81Esdm.js:37250:24) (x2)

Environment

Slidev version: v51.6.0
Node.js version: v22.15.0
Browser: Microsoft Edge 135.0.3179.98
OS: Windows 11 with WSL2 Ubuntu 2o2.04
Package Manager used: npm v11.3

waewoo avatar May 03 '25 08:05 waewoo

Have the same issue, very annoying

MeikelLP avatar Jun 04 '25 07:06 MeikelLP

A not elegant workaround is move the public dir to meetings dir.

yuyinws avatar Jun 05 '25 03:06 yuyinws

A not elegant workaround is move the public dir to meetings dir.

Tried that. Didn't work for me. The build didn't include any public folder nor any of its contents

MeikelLP avatar Jun 05 '25 05:06 MeikelLP

@MeikelLP I create a playground for it and it works normally:

https://stackblitz.com/edit/github-n1hufsvh?file=package.json

you can try npm run build on the terminal, and check the dist dir, includes the image

Image

yuyinws avatar Jun 05 '25 06:06 yuyinws

Image

Directory structure

  • slides/
    • 2025/
      • 06.md
      • 05.md
    • public/
      • images/
        • avatar.png
  • packacke.json

Command

slidev build slides/2025/06.md

MeikelLP avatar Jun 05 '25 06:06 MeikelLP

Try put public under 2025 folder.

yuyinws avatar Jun 05 '25 07:06 yuyinws

Works thanks ❤

MeikelLP avatar Jun 05 '25 07:06 MeikelLP

The behavior of <img>'s src attribute in Slidev markdown should be the same as in an ordinary Vue component. It is recommended to use a relative path for <img>'s src attribute:

<img src="./assets/image.png">

meetings/
  slides.md
  assets/
    image.png

kermanx avatar Nov 15 '25 13:11 kermanx