vite icon indicating copy to clipboard operation
vite copied to clipboard

Vue + Vite + SSR: Referencing public assets with the root path (`/myimage.jpg`) inside the `public` directory results in a Rollup error

Open truumahn opened this issue 2 years ago • 9 comments

Describe the bug

Using vite-plugin-ssr with Vue, running build with an asset referenced from the root path (e.g. /myimage.jpg) results in a Rollup error. This doesn't occur during dev.

Also, the issue doesn't occur when used with a generic Vue SPA.

However, @brillout noted that vite-plugin-ssr doesn't do anything about the public directory

Here's a detailed explanation of the scenarios:

Scenario A: VPS with Vue using npm init vite-plugin-ssr@latest

"vite": "^3.0.9",
"vite-plugin-ssr": "^0.4.32",
"@vitejs/plugin-vue": "^3.0.3"

myimage.jpg can be found in public directory, inside the root component in the template:

this breaks:

<img src="/myimage.jpg" />

this works:

<img src="http://localhost:3000/myimage.jpg" />

Scenario B: Vue 3 project using npm init vue@latest

"vite": "^3.0.9",
"@vitejs/plugin-vue": "^3.0.3"

myimage.jpg can be found in public directory, inside the root component in the template:

this works:

<img src="/myimage.jpg" />

this works:

<img src="http://localhost:3000/myimage.jpg" />

Reproduction

https://github.com/truumahn/vps-public-image-repro

System Info

System:
    OS: Linux 5.10 Ubuntu 20.04.2 LTS (Focal Fossa)
    CPU: (12) x64 AMD Ryzen 5 4600H with Radeon Graphics
    Memory: 5.76 GB / 15.31 GB
    Container: Yes
    Shell: 5.8 - /usr/bin/zsh
  Binaries:
    Node: 16.16.0 - /mnt/wslg/runtime-dir/fnm_multishells/31022_1662972639084/bin/node
    npm: 8.11.0 - /mnt/wslg/runtime-dir/fnm_multishells/31022_1662972639084/bin/npm
  Browsers:
    Chrome: 96.0.4664.45
  npmPackages:
    @vitejs/plugin-vue: ^3.0.3 => 3.1.0 
    vite: ^3.0.9 => 3.1.0

Used Package Manager

pnpm

Logs

Click to expand!
[vite]: Rollup failed to resolve import "/politecat.jpg" from "renderer/PageShell.vue?vue&type=script&setup=true&lang.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
[vite-plugin-ssr:autoFullBuild] [vite]: Rollup failed to resolve import "/politecat.jpg" from "renderer/PageShell.vue?vue&type=script&setup=true&lang.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
error during build:
Error: [vite]: Rollup failed to resolve import "/politecat.jpg" from "renderer/PageShell.vue?vue&type=script&setup=true&lang.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
    at onRollupWarning (file:///path/to/project/vite-ssr-project/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-665b0112.js:45824:19)
    at onwarn (file:///path/to/project/vite-ssr-project/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-665b0112.js:45622:13)
    at Object.onwarn (file:///path/to/project/vite-ssr-project/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:23225:13)
    at ModuleLoader.handleResolveId (file:///path/to/project/vite-ssr-project/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:22352:26)
    at file:///path/to/project/vite-ssr-project/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:22313:26
 ELIFECYCLE  Command failed with exit code 1.

Validations

truumahn avatar Sep 12 '22 09:09 truumahn

Vite-plugin-ssr doesn't do anything with public/ assets, so it's likely a Vite issue during SSR building.

brillout avatar Sep 12 '22 10:09 brillout

It seems it does not reproduce with a simple setup. https://stackblitz.com/edit/github-marmex?file=src%2FApp.vue

And it happens with vite-plugin-ssr + react too. https://stackblitz.com/edit/github-6pyqmj?file=renderer%2FPageShell.jsx

sapphi-red avatar Sep 12 '22 11:09 sapphi-red

And it happens with vite-plugin-ssr + react too.

Only because you imported the images, not used them with the root path as /logo.svg directly at the src attribute of the img element. It successfully builds like this: https://stackblitz.com/edit/github-6pyqmj-wrxz1m?file=renderer/PageShell.jsx

The same doesn't work with Vue though.

truumahn avatar Sep 12 '22 13:09 truumahn

plugin-vue transforms <img src="/logo.svg"> into

<template>
  <img :src="logoSvg" />
</template>

<script setup>
import logoSvg from '/logo.svg'
</script>

So something is not working around resolving /logo.svg. And since it does not happen with Vite only, I guess something in vite-plugin-ssr is interacting it.

sapphi-red avatar Sep 12 '22 13:09 sapphi-red

It builds successfully with the following vite.config.ts:

import vue from "@vitejs/plugin-vue";
import ssr from "vite-plugin-ssr/plugin";
import { UserConfig } from "vite";

const config: UserConfig = {
  plugins: [
    vue({
      template: {
        transformAssetUrls: {
          img: [],
        },
      },
    }),
    ssr({ prerender: true }),
  ],
};

export default config;

https://stackblitz.com/edit/vitejs-vite-nsfvwb?file=vite.config.ts

So it is indeed the Vue plugin that causes this. I'm just checking the documentation: https://github.com/vitejs/vite/tree/main/packages/plugin-vue#asset-url-handling

This behaviour was introduced in 3.x.

truumahn avatar Sep 12 '22 13:09 truumahn

It seems that @vitejs/plugin-vue tries to resolve src if it doesn't match a public/ asset.

Vite-plugin-ssr 0.4 changed Vite's config publicDir to false for SSR, which explains the problem.

I reverted that change and released a new version [email protected] which should fix the problem.

@truumahn Let me know if you run into any other issues. We can close this in the meantime.

@sapphi-red The proper fix would be to stop separating the client-side and server-side building process into two isolated processes. FYI, this is one of many reasons why I believe the decision the Vite team took here https://github.com/vitejs/vite/discussions/9496#discussioncomment-3384709 was a mistake. Separating both builds is asking for trouble.

brillout avatar Sep 13 '22 09:09 brillout

The proper fix would be to stop separating the client-side and server-side building process into two isolated processes. FYI, this is one of many reasons why I believe the decision the Vite team took here https://github.com/vitejs/vite/discussions/9496#discussioncomment-3384709 was a mistake. Separating both builds is asking for trouble.

I created a discussion #10097 - Unify client-side and server-side build steps about this.

brillout avatar Sep 13 '22 10:09 brillout

It seems that @vitejs/plugin-vue tries to resolve src if it doesn't match a public/ asset.

Yes. This is because of https://github.com/vitejs/vite/issues/10082#issuecomment-1243764867.

Vite-plugin-ssr 0.4 changed Vite's config publicDir to false for SSR, which explains the problem.

What is the purpose of changing this? Avoiding the public directory to be copied? I think it's correct not to resolve public assets when publicDir: false is set.

sapphi-red avatar Sep 13 '22 10:09 sapphi-red

Yes, to avoid the public directory being copied twice at dist/client/assets/ and dist/server/assets/. If the user has a couple of gigabytes of images, that's significant.

brillout avatar Sep 13 '22 10:09 brillout

I'm closing this as the original issue has been resolved. The discussion can be continued in https://github.com/vitejs/vite/discussions/10097

truumahn avatar Sep 16 '22 12:09 truumahn