[Vite] 컴포넌트 build시 이미지가 dynamic import되도록 환경설정

profile image pIutos 2023. 8. 18. 00:12

Icon 컴포넌트 작성

사내 라이브러리에서 icon 컴포넌트를 만들어야 했는데, 아래와 같이 동적으로 name props을 변경하면 이미지가 변경되도록 구현해야했습니다.

import styled from "@emotion/native";
import { IconsNameType } from "../../..";

export type IconProps = {
  name: IconsNameType;
  size: 16 | 20 | 24;
};

export const Icon = ({ name, size }: IconProps) => {
  return <S.ImageWrapper source={require("../../../assets/images/icons/${name}.png")} size={size} />;
};

const S = {
  ImageWrapper: styled.Image<Pick<IconProps, "size">>`
    width: ${({ size }) => size}px;
    height: ${({ size }) => size}px;
  `,
};

코드만 보면 잘 동작할 것 같지만, 빌드하여 패키지 업로드를 하려하니 여러 문제가 있었습니다.

문제점 1. build시 image가 같이 번들링되지 않는다

현재 시스템에서 라이브러리를 build하면 아래와 같이 js파일과 type파일들이 번들링됩니다. 

따라서 동적 Import를 위해 dist폴더에 이미지도 같이 빌드되어야 합니다.

https://ko.vitejs.dev/guide/assets.html

 

Vite

Vite, 차세대 프런트엔드 개발 툴

ko.vitejs.dev

vite 공식문서를 보면 public 디렉터리 아래에 asset들을 위치시키면 같이 빌드가 된다고 합니다.

하지만 src/lib폴더밖에 없는 라이브러리 개발 환경에서는 public폴더가 존재하지 않으므로 아래와 같이 임의로 폴더경로를 지정해줍니다.

// vite.config.ts

export default defineConfig({
  // ...
  publicDir: path.resolve(__dirname, "src/lib/assets"),
})

vite config에 publicDir옵션을 설정하면 해당 경로의 asset들이 자동으로 같이 build 됩니다.

이렇게 image를 dist폴더에 빌드하는것은 성공했지만, 생각해보니 다른 문제가 있었습니다.

문제점2. 이미지를 가져오는 경로가 달라야한다.

icon 컴포넌트 코드를 보면

"../../../assets/images/icons/${name}.png"

경로로 동적 import 해오고 있습니다.

하지만 모듈에서 가져와야하는 경로는

"../images/icons/${name}.png"

이므로 build시 import해오는 경로가 달라야합니다.

dist폴더에 이미지가 존재해도 dist폴더 경로에 맞게 이미지를 불러와야하는 것입니다.

공식문서에서는 전체 URL을 확인하는 방법으로 URL 생성자를 이용하는 방법을 제시합니다.

프로덕션 빌드 시, Vite는 번들링 및 에셋 해싱 후에도 해당 에셋에 대한 URL을 올바르게 가리키기 위해 필요한 변환 작업을 수행합니다.

위 방법을 사용하면 번들링 이후에 URL이 알맞게 변경된다고 하기 때문에, 이를 적용해보았습니다.

// ...
const getImageUrl = (name: IconProps['name']) => {
  return new URL(`../../../assets/images/icons/${name}.png`, import.meta.url)
    .href;
};

export const Icon = ({ name, size }: IconProps) => {
  return <S.ImageWrapper source={require(getImageUrl(name))} size={size} />;
};

이렇게 작성 후 빌드하면 URL 경로에 해당하는 image를 모두 가져와서 base64로 인코딩하고, 이를 동적으로 import하도록 번들링 된 것을 확인할 수 있습니다.

dist/*/design-system.es.js

결말

성공적으로 dynamic하게 이미지를 불러오는 icon컴포넌트를 만들었고, 이를 github registry에 배포하여 프로젝트에 불러왔습니다.

하지만 컴포넌트를 확인해보니 react native에서는 이미지 경로 require 함수에서 동적으로 가져오는것이 불가능하다고 합니다... 

제가 라이브러리를 설정할 때 native 개발 환경은 설정하지 않았는데, 실제 native환경에서 확인해보니 동작하지 않았습니다.

이후 web 컴포넌트로도 컴포넌트를 만들 예정인데, 이 때 상기 동적 import 방식을 사용하려 합니다.

이미지를 동적으로 import하는 컴포넌트를 만들고, vite로 빌드하기 위한 분들을 위해 이 글을 남깁니다..!