Backgrounds
일반적인 웹개발 환경에서는, 아래와 같이 이미지를 불러올 수 있습니다.
import someImg from "./some-img.png";
<img src={someImg} />
만약 이 상황에서 해당 경로에 파일이 존재하지 않는다면, 빌드 시 Module not found 발생합니다.
대부분의 번들러들은 소스코드를 분석할 때 require, import로 참조된 모든 모듈과 자원을 탐지하며,
이 덕분에 존재하지 않는 파일을 불러오는 등의 실수를 미연에 방지할 수 있습니다.
chrome extension에서는 이미지를 불러오기 위해 조금 다른 방법을 사용해야 합니다.
익스텐션의 content_scripts는 현재 실행되는 웹페이지를 기본 context로 가지기 때문에
위와 같이 작성할 경우, 현재 웹페이지/some-img.png 경로로 파일을 조회합니다.
(파일이 있을 리가 없으니, 이미지 로드가 안 되겠죠!)
실행 중인 각 익스텐션은 별도의 자체 보안 원본을 가지고 있으며
우리가 업로드한 애플리케이션 파일 역시, 해당 위치에 보관되어 있습니다.
→ 해당 경로로 프로젝트 내 자원을 조회해줘야 하는 것이죠!
chrome은 설치 디렉터리 내의 상대 경로를 정규화된 URL로 반환하는, getURL API를 제공합니다.
import someImg from chrome.runtime.getURL('some-img.png')
// chrome-extension://익스텐션ID/some-img.png 경로로 자원 조회
<img src={someImg} />
위와 같이 작성하면, 정상적으로 이미지를 불러올 수 있습니다.
(공식 문서처럼, manifest.json내 web_accessible_resource에 해당 파일을 추가하는 것도 잊지 말아야겠죠)
Problems
하지만 위와 같은 방식은 해당 경로 내 파일 존재 여부를, 빌드 시점에 알 수 없다는 문제가 존재합니다!
import someImg from chrome.runtime.getURL('wrong-path/some-img.png') // 정상 번들링
<img src={someImg} />
이유는 간단합니다.
getURL API는 말 그대로 chrome.runtime 객체의 메서드에 불과하며,
번들러 입장에서 '.some-img.png'는 단순한 문자열에 불과하므로, 해당 위치에 자원이 존재하는지 검사할 필요가 없는 것이죠.
Solutions
파일의 존재 여부를 번들러가 검사하게 만들기 위해서는 → require, import를 통해 해당 모듈을 참조해야 합니다.
하지만 그와 동시에, 실제 img src에는 익스텐션 설치 디렉터리(getURL로 조회된)를 작성해줘야 하겠죠
따라서, 이미지 식별자 ↔ 프로젝트 내 파일 경로 ↔ chrome 정규화 URL 간 변환 함수를 구현해 이를 해결하고자 했습니다.
// lib/chrome-extension/image-url-loader.ts
// 1. 이미지 식별자와 실제 파일 경로를 매핑하는 객체 생성
const IMAGE_SOURCE_PATH_MAP = {
SOME_IMG: require("./some-img.png"), // require()를 사용해 번들러가 파일 존재 여부를 검사하게 함
};
export function getImageURL(key: keyof typeof IMAGE_SOURCE_PATH_MAP) {
// 2. IMAGE_SOURCE_PATH_MAP에서 해당 이미지 모듈 가져오기
const imageModule = IMAGE_SOURCE_PATH_MAP[key];
// 3. require()로 불러온 모듈에서 파일 경로 추출
// ES 모듈의 경우 기본적으로 default 속성에 경로가 저장됨
const imagePath = imageModule.default || imageModule;
// 4. 파일 경로에서 파일명만 추출
const filename = imagePath.split("/").pop();
// 5. chrome.runtime.getURL()을 사용해 정규화된 URL 반환
return chrome.runtime.getURL(`${filename}`);
}
가장 먼저 IMAGE_SOURCE_PATH_MAP 객체를 생성해 줬습니다.
이는 이미지 식별자와 실제 프로젝트 내 이미지 파일의 경로를 mapping 하고 있으며
해당 데이터 내 require 구문을 통해, 번들링 시 해당 파일이 실제로 존재하는지 여부를 번들러가 검사하게 됩니다.
실제 이미지 경로 사용처에서는, getImageURL 함수를 사용합니다!
앞서 작성한 IMAGE_SOURCE_PATH_MAP을 통해 입력받은 이미지 식별자(key)에 해당하는 모듈을 조회한 뒤,
모듈 파일명을 통해 익스텐션 디렉터리 경로를 생성해 반환해 주는 것이죠.
import { getImageURL } from "@/lib/chrome-extension/image-url-loader";
<img src={getImageURL('SOME_IMG'} />
→ 이를 통해 1) 번들링 시 모듈 존재 X 에러 방지 2) 이미지 파일 정상 load 가 가능해집니다!
+ getImageURL은 keyof typeof IMAGE_SOURCE_PATH_MAP 타입을 인자로 받기 때문에,
사용처에서도 호출 가능한 이미지 목록들을 타입 추론할 수 있다는 장점도 가져갈 수 있겠죠.
(반대로 단점은 사용할 이미지가 추가될 때마다, IMAGE_SOURCE_PATH_MAP에 해당 key-value를 추가해줘야 한다는 것?)
'source-code > FrontEnd' 카테고리의 다른 글
next.js에 FSD 폴더 구조 패턴 적용하기 (1) | 2024.09.24 |
---|---|
FrontEnd 개발자가 가장 빠르게 서비스를 구축하는 방법 (5) | 2024.09.08 |
Feature-Sliced Design(FSD) 도입기 (0) | 2024.08.03 |
[chrome extension] dynamic import시 Cannot find module 에러 해결하기 (0) | 2024.07.26 |
WebComponent에서 styled-components 사용하기 (0) | 2024.07.10 |