I'm building my project with Vue.js 3, Vite.js. The app works fine when in dev mode (when using the dev server). Once I do launch the build command, Vite creates for me the /dist directory containing the build for my app. If I run the preview command (vite preview) it starts with no problem the preview of my build.
The problem is with some images which are coming from Vue components. All the images of my project are in the src/assets directory.
.
├── Attribution.txt
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── Temp.png
│ │ ├── bridge.png
│ │ ├── city-security.png
│ │ ├── credit-card.png
│ │ ├── deforestation.png
│ │ ├── eagle.png
│ │ ├── favicon
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ └── favicon.ico
│ │ ├── global-goals.png
│ │ ├── hall.png
│ │ ├── italian-flag.png
│ │ ├── machine-learning.png
│ │ ├── modern-architecture.png
│ │ ├── moon-festival.png
│ │ ├── people.png
│ │ ├── planet-earth.png
│ │ ├── police.png
│ │ ├── teamwork.png
│ │ ├── uk-flag.png
│ │ └── virtual.png
│ ├── components
│ │ ├── Button.vue
│ │ ├── Card.vue
│ │ ├── Column.vue
│ │ ├── Footer.vue
│ │ ├── MainContent.vue
│ │ ├── Navbar.vue
│ │ └── components-it
│ │ ├── Card-it.vue
│ │ ├── Footer-it.vue
│ │ └── Navbar-it.vue
│ ├── main.js
│ ├── router
│ │ └── index.js
│ ├── tailwind.css
│ └── views
│ ├── CitySecurity.vue
│ ├── Contribute.vue
│ ├── Credits.vue
│ ├── Goals.vue
│ ├── Home.vue
│ ├── It
│ │ ├── CitySecurity-it.vue
│ │ ├── Contribute-it.vue
│ │ ├── Credits-it.vue
│ │ ├── Goals-it.vue
│ │ ├── Home-it.vue
│ │ └── Municipality-it.vue
│ └── Municipality.vue
├── tailwind.config.js
└── vite.config.js
The images in the views have the correct path and are displayed correctly in the build. But the images in the components folder have a problem: the path doesn't change in the build file.
i.e.
<template>
<Navbar />
<div >
<h1 >A new way to live the City</h1>
<img src="../assets/hall.png" alt="Town Hall" width="250" />
<p >
To improve the municipality livings being we tought about some ideas, that
are somehow able to improve the qol(Quality of life). One of the most
reliable problem that requires to be solved is the minimization of
burocracy, tryna to make things digital any sort of procedure. One of ours
ideas is to improve the mechanism of shifting around the city, by giving
cityzens public and shareble veichles to reduce pollution and the waste of
fuel.
</p>
<div >
<div >
<h1 >Digitalization</h1>
<img
src="../assets/virtual.png"
alt="Digitalization"
width="100"
/>
<p >
Burocracy is so annoying, so we tought about how we can semplify it.
The Answer is... DIGITALIZATION! Everything's simpler when digital, so
our city is going to have a system for all of them.
</p>
</div>
<div >
<h1 >Infrastructures Upgrading</h1>
<img
src="../assets/bridge.png"
alt="Digitalization"
width="100"
/>
<p >
To make our city better, our city is going to invest in
infrastructures to let cityzens live their life much better. Better
"bridges" makes better people.
</p>
</div>
<div >
<h1 >Innovative Learning</h1>
<img
src="../assets/Machine-Learning.png"
alt="Digitalization"
width="100"
/>
<p >
Our city is going to offer a learning system to make everyone learn
about technologies and new innovation. The mind of a man is the most
precious part of him.
</p>
</div>
</div>
</div>
<Footer />
</template>
<script>
import Navbar from "../components/Navbar.vue";
import Footer from "../components/Footer.vue";
import Button from "../components/Button.vue";
export default {
name: "Municipality",
components: {
Navbar,
Footer,
Button,
},
};
</script>
<style></style>
This is one of my views. In the build, all the img tags will have the correct path (Ex: /assets/imgName.randomNumbersAndString.png).
But this doesn't happen in the components.
i.e. - Card.vue component
<template>
<div
>
<a :href="`${link}`">
<img
:
:src="`./src/assets/${imgName}`"
:alt="`${imgAlt}`"
width="100"
/>
</a>
<p >{{ text }}</p>
</div>
</template>
<script>
export default {
name: "Card",
props: {
link: String,
imgClass: String,
imgName: String,
imgAlt: String,
text: String,
},
};
</script>
<style scoped></style>
Credits.vue view
<template>
<Navbar />
<h1 >
Images and Icons attributions
</h1>
<div >
<Card
link="Hall icons created by Smashicons - Flaticon"
text="Hall icons created by Smashicons - Flaticon"
imgAlt="Hall vector representation"
imgName="hall.png"
/>
<Card
link="https://www.flaticon.com/free-icons/moon-festival"
text="Pokemon icons created by Roundicons Freebies - Flaticon"
imgAlt="Temp logo"
imgName="Temp.png"
/>
<Card
link="https://www.flaticon.com/free-icons/moon-festival"
text="Moon festival icons created by Flat Icons - Flaticon"
imgAlt="Moon vector representation"
imgName="moon-festival.png"
/>
<Card
link="https://www.flaticon.com/free-icons/digital"
text="Digital icons created by Freepik - Flaticon"
imgAlt="Digital vector representation"
imgName="virtual.png"
/>
<Card
link="https://www.flaticon.com/free-icons/tower-bridge"
text="Tower bridge icons created by Freepik - Flaticon"
imgAlt="Bridge vector representation"
imgName="bridge.png"
/>
<Card
link="https://www.flaticon.com/free-icons/machine-learning"
text="Machine learning icons created by Flat Icons - Flaticon"
imgAlt="Machine learning vector representation"
imgName="machine-learning.png"
/>
<Card
link="https://www.flaticon.com/free-icons/business-and-finance"
text="Business and finance icons created by Freepik - Flaticon"
imgAlt="City security vector"
imgName="city-security.png"
/>
<Card
link="https://www.flaticon.com/free-icons/credit-card"
text="Credit card icons created by Freepik - Flaticon"
imgAlt="Credit card vector"
imgName="credit-card.png"
/>
<Card
link="https://www.flaticon.com/free-icons/deforestation"
text="Deforestation icons created by Freepik - Flaticon"
imgAlt="Deforestation vector representation"
imgName="deforestation.png"
/>
<Card
link="https://www.flaticon.com/free-icons/eagle"
text="Eagle icons created by Freepik - Flaticon"
imgAlt="Eagle vector"
imgName="eagle.png"
/>
<Card
link="https://www.flaticon.com/free-icons/modern-architecture"
text="Modern architecture icons created by Freepik - Flaticon"
imgAlt="Modern architecture vector"
imgName="modern-architecture.png"
/>
<Card
link="https://www.flaticon.com/free-icons/environment"
text="Environment icons created by Freepik - Flaticon"
imgAlt="Earth planet vector"
imgName="planet-earth.png"
/>
</div>
<div >
<Card
link="https://www.flaticon.com/free-icons/police"
text="Police icons created by Freepik - Flaticon"
imgAlt="Police officer vector"
imgName="police.png"
/>
<Card
link="https://www.flaticon.com/free-icons/collaboration"
text="Collaboration icons created by Freepik - Flaticon"
imgAlt="Community vector"
imgName="teamwork.png"
/>
</div>
<Footer />
</template>
<script>
import Card from "../components/Card.vue";
import Navbar from "../components/Navbar.vue";
import Footer from "../components/Footer.vue";
import Button from "../components/Button.vue";
export default {
name: "Credits",
components: {
Navbar,
Footer,
Button,
Card,
},
};
</script>
<style scoped></style>
In this case, when I pass the imgName to the Card component, in the build file the path of the image is ./src/assets/name.png.
How can I fix?
CodePudding user response:
Instead of using relative path (..) to the assets folder, you can use @/assets from any of the vue components to refer to files in the assets folder.
E.g this should work, no matter how deep the Vue component is nested.
<img src="@/assets/images/name.png"/>
CodePudding user response:
The problem is, that you are passing file names as a property to the components. The full image path in the component would then be derived from both the path and the variable file name. Such dynamic paths are however not possible because all import paths need to be defined during the build time. With your component, you could theoretically pass e.g. a string from a remote server or a random string as file name, so Vite has no chance to find these images during build time.
The solution to this is very simple though: Instead of passing partial paths (file names) to the component, just pass the imported image directly as a property. The image will be automatically resolved to an absolute file path which can be resolved by Vite.
Here is an example:
<template>
<Card :image="Teamwork" />
</template>
<script>
import Teamwork from '../../assets/teamwork.png';
export default {
setup: () => {
return { Teamwork };
}
};
</script>
Using the options API, you can also pass the image via data or computed to the template. With TypeScript you would also need to define the shim for images so that you can import images.
