Subscribe on changes!

An external `img` should not generate an `import` statement and use a static string when rendering

avatar
May 5th 2022

Version

3.2.33

Reproduction link

github.com

Steps to reproduce

Here's the code to reproduce the issue:

git clone git@github.com:bseib/vue-vite-external-static-image.git
cd vue-vite-external-static-image
npm install && npm run build

Or here's the same code running on stackblitz that can demonstrate the issue: https://stackblitz.com/edit/vitejs-vite-t5npgf?file=dist%2Fassets%2Fentry-point-1.ede3131f.js&terminal=dev

You can see the erroneous output in the entry-point-1.ede3131f.js file on StackBlitz, but might be easier to follow along and see the screenshot in the github issue linked above.

What is expected?

After running npm run build, the generated dist/assets/entry-point-1.e49989cd.js file should not attempt to import anything for the <img> src. The render code should just keep the original string src=/img/aaaSMPTE-color-bars.png as-is, untouched.

I had expected the build to honor the rollup config, and completely ignore that particular img tag since /img/aaaSMPTE-color-bars.png is listed as external.

What is actually happening?

The build does not ignore that tag, and generates an import statement that expects that image file to be in a relative location.

Generated file dist/assets/entry-point-1.e49989cd.js:

[blahblahblah]import n from"../../img/aaaSMPTE-color-bars.png";[blahblahblah]()=>p("img",{alt:"smpte bars",class:"logo",src:n},null,-1)

That import breaks at runtime on the client side, loading as a 404. That import should not exist in the build output, and the rendering of the <img> tag should be a static value rather than the imported variable (n). Since n fails to load, so does the image.

The backend server will serve /img/aaaSMPTE-color-bars.png just fine, if the <img> tag were left untouched.


There are more details in the github repo link, and a broken.html file you can use to actually see this fail. I tried to document the things I tried in the README of that repo. I couldn't get StackBlitz to serve up the broken.html failure, since it is a product of build-time, whereas stackblitz is really good at dev-time demonstrations. But you can follow the instructions in the github example to see it break.

BTW, I'm super sorry if this is a vite issue and I've posted to the wrong place. I pinned down all the details, but I'm not 100% certain this is the correct repo to post this issue.... ¯\_(ツ)_/¯

avatar
May 6th 2022

This is pretty certainly a problem with vite, maybe more specifically its vue plugin (also maintained in the vite repo).

Noteworthy to mention when moving you issue there:

  • the issue, in its reported form, happens because you added the path to rollupOptions.external
  • however when you don't do that, and the file is not present in /public under that path, you get an error reported that rollup can't resolve an import for that path - and get a recommendation to add it to rollupOptions.external, which is likely how you end up where you did.

But our template compiler leaves absolute paths untouched:

Bildschirmfoto 2022-05-06 um 08 26 27

See JS tab on the right side of this playground

So my non-expert opinion is that Vite somehow stille extracts this path, makes it part of its module graph and tries to resolve its existance (likely because it also does that during dev to be able to serve it? rollup/vite should just ignore this path during build, or maybe issue a warning to make you aware the file was not found in /public (where it's supposed to be found normally).

TBH I could be really wrong in my reasoning as to why vite fails here but at the end of the day, in one way or another this is to be solved in vite / @vitejs/plugin-vue IMHO

avatar
May 6th 2022

Here's the culprit:

https://github.com/vitejs/vite/blob/c7eeb8d69253d16dc9413d59cc13e45977a8c105/packages/plugin-vue/src/template.ts#L126-L132

this option is forced to be set and is responsible for absolute paths to be part of the asset pipeline.

Please move this to the vite repo, thanks!