본문 바로가기

회사생활

[JavaScript] html2pdf를 사용하면서 겪은 margin 설정 문제

사건의 발단

회사가 제공하는 서비스가 항상 외부 URL을 사용하여 라이브러리를 읽을 수만은 없습니다..

(인프라 설정에 따라 방화벽에 막히거든요)

결국, 회사 서버에 올려서 거기 URL을 불러와서 사용해야하는데,

그 상황에서 무언가 문제가 생길 수도 있는 건 어쩌면 당연한 일일지도 모르겠습니다,,

 

이번 개발 태스크는 HTML 형식으로 작성된 문서를 pdf화 하여 사용자에게 제공하는 기능입니다.

단순히, 외부 라이브러리를 사용하면 해당 기능은 구현이 쉬우니,

금방금방 끝나겠지라고 생각했었죠 ㅋ,, ( ChatGPT도 이에 동의했었습니다.. )

 

구현 과정

https://github.com/eKoopmans/html2pdf.js/tree/main

 

그냥 여기 레포 방문해서 튜토리얼대로 코드 복붙하니 잘 동작하길래

사용자 설정 기능도 추가했죠,, 

var element = document.getElementById('element-to-print');

var opt = {
  margin:       1,
  filename:     'myfile.pdf',
  image:        { type: 'jpeg', quality: 0.98 },
  html2canvas:  { scale: 2 },
  jsPDF:        { unit: 'in', format: 'letter', orientation: 'portrait' }
};

// New Promise-based usage:
html2pdf().set(opt).from(element).save();

 

저기 보이는 opt 변수에 할당될 pdf 생성 명세가 들어가 있는데요,

저기 보이는 하나하나를 사용자가 설정할 수 있도록 input을 받아 처리해주는 기능을 추가했습니다.

그냥 단순히 변수 별로 input 인터페이스를 추가해줬다고 보시면 돼용 👍🏻

 

※ IE 브라우저 쓰시는 분들은 polyfill.js 라이브러리를 추가하시면 됩니다.

※ 참고로 html2pdf.js보다 스크립트 태그가 위에 와야합니다.

 

문제 발생

문제는 아주 단순한 곳에서 발생했는데,

저기 저 위의 예시 코드에 margin 보이시죠?

저 margin 항목은 사실 단일 숫자, 2개의 원소를 가진 배열, 4개의 원소를 가진 배열로 값을 입력할 수 있습니다.

그래서 당. 연. 히. UX를 높이기 위해 아래처럼 pdf 여백 설정 페이지를 구상했죠,,

근데 이게 뭡니까,, 4개 배열을 만들어서 명세에 입력했더니..? 오류가 뜨는 거에요..?? 😮

길이 2짜리 배열을 하든,, new Array(1, 2, 3, 4) 이렇게 명시적으로 작성해서 입력하든,,

똑같이 에러를 띄우는 거에요..?

근데,, 한가지 에러 없이 제대로 결과물을 출력하는 경우가 있었는데,

그건 예시처럼 단일 숫자를 넣어주는 경우였습니다..

 

하..

무엇이 문제인지~

이것 때문에 몇 시간을 보낸건지~

 

문제 해결

여러번의 테스트를 거치고 1시간 정도 지났을 때, 떠올린 것은,

이거 설마.. 라이브러리 자체의 문제..? 라는 생각이 들었습니다.

 

그래서 바로 저 에러 코드를 기반으로 라이브러리 소스를 탐색하기 시작했죠,,

 

그 결과,

utils.js 파일의 objType 함수를 사용하는

worker.js 파일의 setMargin 함수가 문제였습니다..

https://github.com/eKoopmans/html2pdf.js/tree/main/src/utils.js

https://github.com/eKoopmans/html2pdf.js/tree/main/src/worker.js

 

아하..

 

사실 큰 문제는 아니고

Array 객체를 objType 함수 자체에서 Array 객체로 못 읽더라구요.

그래서 CDN 파일을 직접 다운 받아서 서버에 올리기 전에 아래처럼 수정했습니다~

 

A.prototype.setMargin=function(e){
	return this.then((function(){
		switch((0,s.objType)(e)){
			case"number":
				e=[e,e,e,e];
			case"array":
				if(2===e.length&&(e=[e[0],e[1],e[0],e[1]]),4===e.length)
					break;
			default:
				return this.error("Invalid margin array.")
		}
		this.opt.margin=e
	})).then(this.setPageSize)
}

얘를

A.prototype.setMargin=function(e){
	return this.then((function(){
		switch((0,s.objType)(e)){
			case"number":
				e=[e,e,e,e];
			case"array":
				if(2===e.length&&(e=[e[0],e[1],e[0],e[1]]),4===e.length)
					break;
			case"object":
				if(Array.isArray(e)&&2===e.length&&(e=[e[0],e[1],e[0],e[1]]),4===e.length)
					break;
			default:
				return this.error((0,s.objType)(e)+" array.")
		}
		this.opt.margin=e
	})).then(this.setPageSize)
}

이렇게 바꿨습니다..

 

중간에 보이시는 대로 object인 경우에 Array인지 한 번 더 체크하는 로직을 추가했습니다~

 

그렇게 하니 잘 됨 ㅎㅎ

근데 뭐가 문제였던 거지..

그냥 브라우저 켜서 활용하면 잘되는데,, 시스템에만 넣으면,, 흠,,

 

후속 문제 발생

근데 또 문제가 발생한게,,

pdf를 바로 파일화 안하고? BLOB 파일로 형태를 유지해서 Canvas tag에 띄우면?

좌측에 약간의 buffer가 껴서 출력이 되더라구요..

 

파일 출력 전, 미리보기 화면을 만들어야 돼서 BLOB 형태의 데이터가 필요하거든요ㅠㅠ

그래서 포기 못하는데,,

 

그냥 냅두기엔 이게 너무 안 이쁨 ㅠㅠ

무조건 클레임 들어옴 ㅠㅠ

 

후속 문제 해결

얘는 생각보다 간단하게 끝이 났습니다 ㅋ

구글링(Bing을 더 많이 쓴 듯 ㅎㅎ) 좀 하니까 (진작 검색 때릴 걸 ㅎㅎ)

StackOverFlow의 한 글이 해결해줬어요!!!!!

https://stackoverflow.com/questions/76003066/why-is-left-margin-and-overlap-problem-with-html2pdf-js-package

 

Why is left-margin and overlap problem with html2pdf.js package?

I try to make pdf file with the html2pdf. It works at some point very good, but I have two main problem. The first, when the element which I select for rendering, is bigger than the window view hei...

stackoverflow.com

대충 html2pdf에 문제가 있다~는 글인데 유심히 살펴본 결과

정답은..?

.

.

.

버전을 낮춰라. 이 말이었습니다..

와,, 천잰데..? 항상 버전 낮춘 테스트를 해보는 것을 염두에 두어야겠습니다..

옛날에 Flutter 하면서 정말 많이 깨달았던 건데 다시 새삼 느끼네요 ㅎㅎ

 

저는 그래서 0.10.2 -> 0.9.3으로 바꿨더니 모든 테스트 통과하고 성공했네요~

 

참고로 여기서 더 낮추면 안된다네요~

https://github.com/eKoopmans/html2pdf.js/issues/360

이 사람은 0.9.2 쓰는데 좌측 여백이 생기는 경험을 했다고 합니다..

답변이 더 가관,, 횡마진에 마이너스 값을 주라니,, 으흐흐,,

 

짧은 소감

사실,, 처음엔 '사용자 설정 기능은 그냥 뺄까? 💡'도 생각했습니다,,

뭔가 사용자가 이 기능을 모른 채로 냅둬도, 모른 채로 잘 살아가실 수 있을 거라 생각했기 때문이죠,,

근데 그냥 마음을 고쳐먹고,, 열심히 잘 하기로 했습니다..

 

저 버전 문제도 하루죙일 봤는데도 못찾겠어서 포기하기 직전까지 갔거든요;;

대충 대안들이 있으니 그 대안들을 적용할까? (시간이 배로 들거나, 형태가 최적화되지 않은 것들)

아니면 그냥 모른 척 할까? 등등이요,,

 

이런 거 보면, 개발자에게 가장 지양해야할 점은 포기하는 것 같네요,

StackOverFlow, ChatGPT가 있는 이 시대에, 사람이 일반적으로 가능할 거 같다고 생각되는 것은,

웬만하면 구현 가능한 것 같습니다,, 진짜로,,

 

또, 진짜 그냥 개뻘글이나 '뭔 저런 문제로 끙끙 앓고 있냐 ㅋ' 싶은 글들도

사실은,, 어떤 조건이 갖춰지면 우리에게 필요한 질문글일 수도 있습니다.

그걸 보고 이거 답변 어딨어!!!!! 이거 해결하셨어요?!?!?!?!? 하게 될 수도 있는 거죠..

 

 

써보니 후덜덜하네요.

이걸 보면 한 주를 알차게 보낸 것 같기도하고요.

이런 챌린징한 일만 회사에 가득했으면 좋겠다는 생각이네요 ㅎㅎ