[Vue/Vite] 빌드 시 이미지 동적 로딩 에러

은승균·2022년 4월 15일
4

문제상황

인턴을 하면서 투자 설명회를 위한 애플리케이션을 빠르게 Vue로 만들어보고 PR을 하신다고 하셔서 Vite로 Vue 앱을 구성해보았다.
기존의 VueCLI가 아닌 Vite를 처음으로 사용해보기로 하였다. 데모 페이지 제작이고 페이지 분량도 6페이지 정도로 매우 작았기 때문에 새로운 기술을 적극적으로 도입해 보고자 하였다.

Vite에 대한 설명은 추후에 포스팅하겠습니다

Vite는 확실히 기존 웹팩에 비해서 매우 빨랐다. 개발 경험이 매우 향상된 것을 느낄 수 있었다.
하지만 문제점이 하나 발생하였는데, 바로 이미지 동적 로딩이 예상대로 이루어지지 않았다는 것이다.
개발 환경에서는 제대로 작동하였지만 빌드 후 배포환경에서는 에러가 발생하였다.

	<div v-for="image in images" :key="image.id">
		<img :src="`@/image_path/${image.src}`">
   </div>

기존에 VueCLI로 만든 프로젝트에서는 위와같은 경로로도 이미지를 로드할 수 있었다. 하지만 Vite에서는 404 Not Found가 발생하는 것을 발견하였다.

해결방법

시도 1. require

src 부분에 require(../image_path/${image.src}) 와 같이 require를 이용하려고 하였으나, 'require' module not found 에러가 발생하는 것을 확인할 수 있었다.
찾아보니 require는 웹팩에서 지원하는 모듈이라는 것을 알 수 있었다.

시도 2. import.meta

https://vitejs-kr.github.io/guide/assets.html#new-url-url-import-meta-url

해당 공식 문서를 참고하여 에셋을 가져오는 것을 시도하였다.

<script>
export default{
 setup(){
   
   function getImageUrl(path){
   	return new URL(path).href;  
   }
   return{
     getImageUrl
   }
 },
}
</script>
<template>
	<div v-for="image in images" :key="image.id">  
    	<img :src="getImageUrl(image.src)" />  
  	</div>
</template>

공식문서에서 제시하는 해결방법은 네이티브 ESM의 API 중 하나인 import.meta.url을 이용하여 현재 모듈의 URL을 가져오는 것이다. URL 생성자와 함께 사용하면, 정적 에셋의 URL을 확인할 수 있게 된다고 한다.

하지만 실패하였다.

실패원인

실패원인은 프로젝트 폴더 구조에 있었다.

기존의 폴더구조

	- puiblic
    	- favicon.ico
    - src
    	- assets
    	- components
        - composables
        - router
        	- ...
        - views
        	- ...
        - styles
        	- ...
        - store
        	- ...
        - App.vue
        - main.js
    - index.html
    - package.json
    - vite.config.js
   

기존구조에서 볼 수 있듯이 assets를 src폴더에서 관리하도록 만들어 놓았다. 기존 프로젝트에서는 문제가 발생하지 않았지만 Vite에서는 이러한 구조를 사용할 수 없었다.
빌드 시에는 dist폴더에 js,css,html파일이 생성이 되는데, 이때 src폴더에 있는 assets는 제대로된 경로에 들어가지 못하게 된다고 한다.
Vite에서는 assets 폴더를 public 폴더에 넣도록 가르쳐주고 있다.

다음 에셋의 경우 public 폴더에 위치시킨다.
1. robots.txt와 같이 소스 코드에서 참조되지 않는 에셋
2. 해싱 없이 항상 같은 이름을 갖는 에셋
3. 또는 URL을 얻기 위해 굳이 import 할 필요 없는 에셋

public 폴더에 넣어 둔 assets은 개발 시에 / 경로에, 배포 시에는 dist 디렉터리에 위치하게 된다.

이때 public 디렉터리에 위치해 있는 에셋을 가져오고자 하는 경우, 항상 루트를 기준으로 하는 절대 경로로 가져와야만 합니다. ( public/icon.png 에셋은 소스 코드에서 /icon.png으로 접근이 가능합니다.)
public 디렉터리에 위치한 에셋은 JavaScript 코드로 가져올 수 없습니다.

분명히 공식문서를 따라가면서 환경 설정을 하고 코드를 작성하였는데, assets을 public폴더에 위치시켜야 한다는 것을 눈으로는 보았으나 가볍게 여겨 내 맘대로 폴더구조를 만들어버렸다. 결과적으로 빌드시에 Vite가 만들어내는 결과물에 맞지 않아 에러가 발생하였다.

이후 수정한 폴더구조는 아래와 같다.

	- puiblic
    	- favicon.ico
        - assets
        	- images
            	- ...
    - src	
    	- components
        - composables
        - router
        - views
        - styles
        - store
        - App.vue
        - main.js
    - index.html
    - package.json
    - vite.config.js

이후 코드에서는 public폴더의 assets 폴더에 절대경로로 접근한다.

	 <img
         :src="`/assets/images/${imageName}.jpg`"
         alt="product"
     />

오늘의 교훈

공식 문서를 꼼꼼히 읽자!

profile
3대 500을 향해서

0개의 댓글