사이드 프로젝트를 하면서 프로젝트 소개와 마케팅을 위한 랜딩 페이지를 만드는데, SEO가 필요 없는 단순 정보전달성 섹션은 쿠팡의 제품 상세설명 이미지처럼 따로 퍼블리싱 없이 피그마에서 그대로 이미지로 추출해 웹페이지에 박아넣고 싶은 욕구에 휩싸였다.
프로젝트 팀원들과 랜딩페이지 개발을 완성하기 전에는 카페에서 아무도 못 나간다고 약속한 상태였기 때문에 빠른 퇴근만큼 설레는 일은 없었다.
얼른 이미지로 박아 넣고 이 카페에서 나가겠다는 집념 하나로 시작됐다. 솔직히 길어봤자 5분이면 끝날 줄 알았다.
문제는 5초만에 발생했다.
png 이미지가 포함된 한 페이지를 svg로 추출했는데, 용량이 무려 25메가나 됐다.
svg 파일을 조금 뜯어보니, 사이즈가 큰 이미지 파일이 base64로 그대로 인코딩 되어 들어가있었고, 설상가상 Intellij는 물론, 웬만한 svg 편집기에서는 파일이 너무 큰 탓에 readonly 모드로 열려 편집도 안 되는 상황이었다. 오로지 vim으로만 편집할 수 있는 svg xml이라니..
위 사진에서 보이는 세 개의 png 이미지가 그 문제의 용량 큰 이미지파일들이었다.
나는 퍼블리싱이 하기 싫어서 피그마에서 위 이미지 전체를 svg로 추출했는데, 이 세 개의 이미지들이 base64로 인코딩된 채로 그대로 들어가있어 용량이 너무나도 큰 svg 파일이 생성되어 버렸다.
바로 그럼 혹시 svg에서 base64로 인코딩된 이미지 정보를 빼고 대신, 이미지 url을 넣을 수 있을까 하는 궁금증이 생겼다.
이미지 url은 길어봤자 한 줄이니 분명 용량이 많이 줄 것이었다.
이렇게 넣을 수 있다는 챗지피티의 말에 다시 용기를 얻어, 그럼 image url을 얻는 가장 효율적인 방법이 무엇일까 생각하게 됐다.
선택지는 크게 세 개였다.
1. 이미 웹상에 호스팅된 이미지를 사용한다. (저작권이 없는 이미지)
2. 내가 이미지를 직접 호스팅해 사용한다.
3. nextjs의 static image를 활용한다.
가장 간단해 보이는 건 사실 1번이었으나, CORS 이슈가 있을 수 있다.
2번은 사실 복잡하기도 하고 여전히 CORS 문제가 있을 수 있어 역시 고려하지 않았다.
남은 건 3번이고, public에 image 파일만 올려주고 svg에서 올바른 path만 적어주면 되니 가장 합리적인 선택 같았다.
무지막지하게 길었던 svg 속 세 개의 image 태그들을 지우고, 단 세 줄로 변경해줬다.
<image id="g" width="2505" height="3757" xlink:href="/image/value-experience.png"/>
<image id="h" width="2505" height="3757" xlink:href="/image/value-network.png"/>
<image id="i" width="2505" height="3757" xlink:href="/image/value-safe.png"/>
피그마에서 추출한 svg였기 때문에, 잘 써진 xml이라기보다 그 상황에 맞춰서만, 확장성 없게 쓰여진 xml이라 혹시 내가 width나 height를 변경하면 이미지가 틀어질 수 있어 width와 height 값은 유지한 채로 href 부분만 수정해주었다.
이 수정을 통해 svg의 용량은 25MB에서 43KB로, 말 그대로 획기적으로 줄일 수 있었다.
그렇게 웹에서 로딩하게 하기에 부끄럽지 않은 용량 범위로 진입했다. (여전히 하나하나 퍼블리싱을 안 하고 이미지로 박는다는 건 개발자로서 부끄러운 일이긴 하지만..)
나는 NextJS를 활용해 개발하고 있었기 때문에, 정적 이미지 생성을 위해 public 폴더 안에 image 폴더를 만들고 그 안에 세 개의 이미지를 넣어주었다.
그런데 우려 했던 일이 벌어졌다.
피그마에서 추출했던 svg는 역시나 제대로 만들어있지 않았고.. 이미지가 여기저기로 늘어지고 틀어져있었다.
어쩌지.. 하다가 svg의 xml을 차근차근 읽어 보니 pattern이라는 태그에서 transform 속성이 적용되고 있는 것을 발견했다.
matrix는 6개의 숫자로 이루어져 있고, 숫자들 요리조리 만져 보니,
- 1번째 숫자는 x축으로 늘어짐에 관여를 하고,
- 4번째 숫자는 y축으로 늘어짐에 관여를 하고,
- 5번째 숫자는 x축으로 이동하는 데에 관여를 하고,
- 6번째 숫자는 y축으로 이동하는 데에 관여를 한다는 것을 발견했다.
웹문서에서는 이 값들을 아래처럼 설명하고 있다.
https://developer.mozilla.org/ko/docs/Web/CSS/transform-function/matrix
그렇게 우여곡절 끝에 사진의 위치를 잘 맞춰주었다.
오른쪽 프리뷰를 보면 사진 placeholder 이미지가 칸 안에 잘 들어가있는 것을 볼 수 있다.
(두번째는 왜인지 모르겠지만, 꽉 채우면 아래위로 늘어난 이미지가 돼서 살짝 덜 채운 채로 남겨두었다.)
자, 이제 모든 준비가 끝났다.
정적 이미지 url도 잘 넣어주었고, 이미지 위치와 stretch도 잘 잡아주었다.
이제 웹페이지에 띄우기만 하면 된다.
<div className="relative flex h-screen snap-start items-center justify-center">
<div className="absolute inset-0">
<Image
src={image}
layout="fill"
objectFit="contain"
alt="steps image"
/>
</div>
</div>
이미지를 잘 넣어주고, 실행시켜보았다.
으엥?
이미지가 빠져있다.
뭔일인가 싶어 src에 올라가있는 정적 이미지를 확인해봤다.
그랬더니 svg 내에 있는 이미지들이 비어있지 않고 잘 보인다?!
DOM 위에서는 안 보이고 svg만 따로 로드하면 보이고, 대체 무슨 차이일까..
크게 두 개 생각이 떠올랐다.
1. 내가 모르는 svg 내에 cors 정책이 있다.
2. svg를 로딩하는 시점에 이미지가 불러와지지 않은 상태고, 마침내 다 불러와졌을 때 이미지가 화면에 다시 안 그려지고 있다.
사실 나는 웹 개발자가 아니라서 웹 분야에의 지식은 거의 문외한이기 때문에 떠올릴 수 있는 가설에 큰 한계가 있었다.
계속 헤매다가 한 가지를 발견했는데, 바로 웹페이지에서는 svg 내부 이미지들을 불러오는 네트워크가 잡히지 않고, svg만 따로 로드했을 때는 그 네트워크가 잡히고 있다는 것이었다.
아래 사진을 보면, (이 사진은 svg만 따로 불러오는 경우에서의 네트워크 화면인데,)
svg(landing-value-... ) 이외에도 그 내부에 있는 이미지 세 개(value-experience.png, value-network.png, value-safe.png)를 불러오는 네트워크가 잡히고 있는 걸 볼 수 있다.
반대로, 웹페이지 네트워크에는 잡히지 않았다.
아래 사진을 보면 landing-value-... svg가 불러와지고 난 이후 아무런 png 사진도 불러오지 않고 있는 모습을 확인할 수 있다.
여기서 위에 세웠던 내 두 가지의 가설이 모두 무너졌다.
두 가설은 은연 중에 svg 내부 image 태그에 넣은 url은 무조건 파싱이 될 거라는 걸 가정하고 있었다.
CORS도 일단 요청이 들어가야 발생하고, 두 번째 가설도 이미지 자체는 불러와지지만 업데이트가 되지 않는 경우를 생각한 거였다.
다시 원점이었다.
내가 뭘 모르는지 모르겠어서 svg를 공부하고, 리액트가 svg를 다루는 법을 공부하고, svg가 image를 다루는 법을 공부하고, 폭풍 검색 학습을 하기 시작했다.
그러다가 하나의 단서를 찾았다.
image는 로드하지 않는 제약이 있지만, 이 제약이 svg를 직접 열었을 때는 적용되지 않는다는 것이었다.
내가 고민하던 것에 가장 근접한 힌트였다.
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image
이유 모를 에러가 아니라, 뭔가 조금의 단서를 찾으니 안 된다는 걸 알았지만서도 속은 시원한 기분이었다.
그러고 그 말 뒤에 있는 말에 눈길이 갔다. iframe, object, embed를 활용하면 이미지를 띄울 수 있을 수 있다.
안 그래도 스택오버플로우를 돌아다니다가 비슷한 글을 봤다.
https://stackoverflow.com/a/41195902/19595981
내 svg에 바로 적용해봤지만, 또 알 수 없는 에러로 적용이 되지는 않았다.
이 에러에 대해서도 조금 알아봤지만, 계속 문제가 되었던... 피그마로 추출된 SVG라 코드간 디펜던시가 높아 아무거나 막 고칠 수 있는 상황이 아니라서 일단 보류해뒀다.
그래도 계속 svg에 static image를 심는 방법을 계속 연구해 볼 생각이다.
잠정적 결론은, svg 내 image 태그에 nextjs static image를 심는 것은 그 자체로는 처음부터 불가능한 거였다는 것이다.
그냥 귀찮아도 참고 퍼블리싱 했으면 2-3시간이면 끝날 것을.. 그거 피하려다가 이 문제 해결에만 거의 6시간을 넘게 썼다.
그래도 이런 트러블슈팅 한 번 하면 짧은 시간에 몰입도 있게 많은 걸 학습하게 되는 것 같아서 시간 낭비라고만은 느껴지지 않는 것 같다.
25MB짜리 svg를 43KB로 줄이고 정말 기뻤는데, 아직 해결해야 할 관문이 좀 더 남았다는 게 마음에 걸리지만, 오랜만에 호기심을 자극하는 주제라 재미있게 고민하고, 공부했다.
'개발 잡기술' 카테고리의 다른 글
[Udemy 강의 후기] Spring Boot 3 & Spring Framework 6 마스터하기! (0) | 2024.04.14 |
---|---|
파이썬 input 한 줄로 쓰기 - 객체 unpacking * 사용 (0) | 2024.03.06 |
이젠 진짜 알고리즘 공부 해야지..! 코드트리 사용기 (0) | 2024.02.29 |
[Udemy 강의 리뷰] 옆집 개발자와 같이 진짜 이해하며 만들어보는 첫 Spring Boot 프로젝트 (1) | 2024.02.18 |
Metabase 필터 사용법 (날짜 필터 설정하기) (0) | 2024.01.20 |