일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- html
- 에러
- 코딩테스트
- http
- 코딩
- 비동기
- JavaScript
- error
- React Query
- 자바스크립트
- 공부
- 알고리즘
- SSR
- csr
- 프론트엔드
- dynamic import
- Sass
- 취업준비
- React
- TypeScript
- Next.js
- Vite
- 차이
- DOM
- 개발자
- Browser
- Git
- 백준
- 취업
- css
- Today
- Total
minTech
[Project, React] 한 파일에 있는 이미지 한 번에 import 하기 본문
자기 소개 웹페이지 중에서 프로필 페이지 구현을 모두 마치고 프로젝트 페이지를 구현 중에 있다.
프로젝트 페이지의 경우 한 프로젝트 당 들어가는 이미지가 여러장 되기 때문에 프로젝트 페이지 하나에 프로젝트 하나의 이미지들만 import 해도 기본 6장은 되었다. 이를 하나하나 import 하려니 soso 귀찮,,,
어떻게 하면 하나의 파일에 있는 이미지를 모두 가져올 수 있을까? 바로 구글링을 해보았다!
그 결과, 내가 인터넷 검색을 통해 찾아보았던 방법은 두✌️개이다.
1. 이미지를 import 하는 js 파일을 따로 생성 후에 거기서 컴포넌트처럼 import 해온다.
import project1_1 from "../assets/images/project1_results/project1_1.png";
import project1_2 from "../assets/images/project1_results/project1-2.png";
import project1_3 from "../assets/images/project1_results/project1-3.png";
const project1 = {
project1_1,
project1_2,
project1_3,
};
export const images = () => {
return project1;
};
이러한 방식은 상대적으로 import 해오는 파일에서는 코드가 간단해지고, 사용 방법이 복잡하지 않다.
하지만 export 하는 images.js 파일의 경우 파일이 하나 추가되거나 제거 될 때마다 import 코드를 두 줄이나 추가적으로 작성해야한다.
- 해당 이미지 import 해오기
- project1 객체에 넣기
이러한 작업은 프로젝트가 늘어남에 따라 이미지 개수도 늘어나게 되면 찾는 것도 힘들고, 수정하기도 힘들어진다는 단점을 갖는다.
2. require.context 를 이용한다.
🤷♂️이 과정에 들어가기 전에 궁금해졌다.
require이란 무엇이고, require.context는 어떤 것인가? 각각 어떤 동작을 하는 것일까?
require
- require은 외무 모듈을 가져올 때 사용하는 메서드로 리턴 값은 module.exports이다.
- 파라미터로 추가할 모듈의 파일 경로 값을 받는다.
require('파일 경로')
- 그렇다면 어떻게 동작할까?
- 동작을 코드로 작성하면 다음과 같다.
let require = function(src) { // 파일 경로를 인자로 받는다.
var fileAsStr = readFile(src); // 소스파일을 읽어서 fileAsStr에 저장한다.
var module.exports = {}; // module.exports 이름의 빈 해시를 만든다.
eval(fileAsStr); // fileAsStr을 가져온다.
// 즉 이 부분은 가져온 파일의 소스 파일을 복붙한 것과 같음
return moudule.exports; // module.exports를 리턴한다.
}
결론적으로, 파라미터로 받은 파일 경로의 소스코드를 읽고, export 한 부분의 변수와 그 값을 key와 value형태인 해시 형태로 변환 후에 module.exports 에 넣어준다. 그리고 이를 리턴한다.
그렇다면 require.context는 어떠할까?
require.context()
- 여러 컴포넌트를 한 개의 root만을 이용해 한꺼번에 가져올 때 사용하는 메서드이다.
- 파라미터로는 파일 경로, 하위 디렉터리를 검색해야 하는지의 여부, 가져올 파일들을 필터링할 정규식이 있다.
require.context(가져올 폴더의 경로, true/false, 정규식)
이 require.context를 이용해 프로젝트 이미지 파일을 한 번에 가져와보았다.
export const getProjectImages = (projectId) => {
function importAll(r) { // 가져온 후, forEach를 이용하여 해당 파일에 접근한 후,
// image 배열에 저장한다.
let images = {};
r.keys().forEach((key) => {
images[key] = r(key);
});
return images;
}
let images = importAll(
require.context(
"../assets/images/project1_results", // 해당 경로를 가진 파일에 접근한다.
true,
/\.(png|jpe?g|svg)$/ // png, jpg, svg 형태의 파일을 가져온다.
)
);
return images;
}
해당 코드 작성 후, console.log(images)를 이용해 images 값을 확인해보았다.
잘 출력됨을 확인하였다.
문제 상황
테스트까지 모두 완료된 후에 나는 함수의 파라미터로 프로젝트의 id 값을 입력으로 받아
파라미터 값에 따라 파일 경로를 동적으로 변하도록 작성해보았다.
export const getProjectImages = (projectId) => {
function importAll(r) {
let images = {};
r.keys().forEach((key) => {
images[key] = r(key);
});
return images;
}
let images;
images = importAll(
require.context(
`../assets/images/project${projectId}_results`,
true,
/\.(png|jpe?g|svg)$/
)
);
console.log(images);
return images;
}
그랬더니 에러가 발생했다.
왜 잘 되다가 안되는거지..?😭😭😭😭😭
계속 인터넷으로 찾아보다가 나와 비슷한 상황에 처한 분을 발견했고, 나는 답을 찾았다.
출처 : https://github.com/webpack/webpack/issues/4772
원인
require.context() 같은 경우 웹팩에서 제공하는 기능으로, 정적 코드 분석을 실행한다.
정적 분석은 프로그램 실행 전에 코드를 검사하는 컴퓨터 프로글매 디버깅 방법이다.
따라서 동적으로 분석해야하는 변수를 context 의 인수로 넣어줄 경우, 해당 에러가 발생하는 것이다.
💡결국 require.context의 인수에는 리터럴만 넣을 수 있다.
결론
이 부분에 대해서는 webpack.config.js 파일을 손대서 해결할 수 있는지 찾아보았지만, 마땅한 해결방법이 없기에 ,,
결국, 프로젝트 id 값을 파라미터로 받고, 그 값을 require context 메서드를 이용해 해당 프로젝트 image 들을 동적으로 가져오기 위해 나는 프로젝트 id를 기준으로 switch로 상황을 나누었고, 상황별로 맞는 리터럴 값을 일일히 지정해주었다.
이 말이 이해가 잘 안될 수 있기에 직접 코드를 넣어보았다.
export const getProjectImages = (projectId) => {
function importAll(r) {
let images = {};
r.keys().forEach((key) => {
images[key] = r(key);
});
return images;
}
let images;
switch (projectId) {
case 1:
images = importAll(
require.context(
`../assets/images/project1_results`,
true,
/\.(png|jpe?g|svg)$/
)
);
console.log(images);
break;
case 2:
images = importAll(
require.context(
"../assets/images/project1_results",
true,
/\.(png|jpe?g|svg)$/
)
);
break;
case 3:
images = importAll(
require.context(
"../assets/images/project1_results",
true,
/\.(png|jpe?g|svg)$/
)
);
break;
case 4:
images = importAll(
require.context(
"../assets/images/project1_results",
true,
/\.(png|jpe?g|svg)$/
)
);
break;
default:
break;
}
return images;
};
각 프로젝트별로 같은 코드를 반복해서 쓴 것이 정말,, 아쉽긴 하지만,,
require.context를 이용해 이미지를 가져올 경우, 각 프로젝트 내에서 이미지의 이름이 수정되거나, 이미지 자체가 추가/삭제 되어도 일일히 코드를 작성해주지 않아도 된다는 장점이 있다.
그래서 난 이 프로젝트에선 두 번째 방법을 채택했다.
결과적으로 많이 아쉽지만, 새롭게 require메서드와 require.context 메서드를 경험하고, 완벽하진 않지만 상황에 맞게 사용해보았다는 것에 만족한다.
그리고 require.context는 리터럴 값만 인수로 작성해야한다는 것도 꼭꼭 기억해두어야겠다!!!!
참고자료
'Project' 카테고리의 다른 글
[Storybook] 스토리북에 대해 알아보자 (2) | 2024.08.14 |
---|---|
[Project, React] 타이핑 효과 적용하기 (0) | 2024.03.13 |
[Project] [내 소개 웹사이트] 개인 프로젝트 시작 (1) | 2024.03.08 |