토이 프로젝트를 진행하던 중 firebase storage에 저장된 이미지와 pdf, hwp 파일을 chrome 웹브라우저의 새 창으로 보여주는 기능이 필요했다. 각 파일은 firebase storage에서 얻은 download url을 사용하였다. 이미지와 pdf는 window.open(download url)을 통해 구현 가능했지만 hwp 파일은 이렇게 하면 다운로드 창이 열리면서 웹 브라우저에서 직접 볼 수 없었다. 그래서 인터넷 검색을 통해 알아본 결과 hwp.js라는 라이브러리의 존재를 알게 되었다.
hwp.js는 오픈소스 hwp 뷰어와 parser 기능이 있는 라이브러리이다. 자세한 내용은 여기에서 볼 수 있다.
본격적으로 사용하기 전 npm 혹은 yarn을 통해 hwp.js를 설치해준다.
npm install hwp.js
yarn add hwp.js
이후 사용을 원하는 컴포넌트에 import해준다. 위 글에서는 viewer 기능을 사용할 예정으로 viewer만 import 해준다.
import { Viewer } from 'hwp.js';
여기까지 사용 준비는 끝났고 이후 hwp 파일을 렌더링 할 컴포넌트를 작성해준다.
import React, { useState, useCallback, useEffect, useRef } from 'react';
import { Viewer } from 'hwp.js';
function HWPViewerPage() {
const url = 'download URL'
const ref = useRef(null);
return (
<div className="viewer" ref={ref}/>
)
}
export default HWPViewerPage
hwp.js는 div 태그의 ref 속성을 사용해서 렌더링 한다.
이제 기능을 구현하기 위한 함수를 작성해준다.
import React, { useState, useCallback, useEffect, useRef } from 'react';
import { Viewer } from 'hwp.js';
function HWPViewerPage() {
const url = 'download URL'
const ref = useRef(null);
useEffect(() => {
loadFile()
}, [])
const showViewer = useCallback((file) => {
const reader = new FileReader()
reader.onloadend = (result) => {
var _a;
const bstr = (_a = result.target) === null || _a === void 0 ? void 0 : _a.result;
if (bstr) {
try {
new Viewer(ref.current, bstr)
}
}
}
reader.readAsBinaryString(file)
}, [])
const loadFile = useCallback(() => {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function(event) {
showViewer(new File([xhr.response], 'random'))
};
xhr.open('GET', url);
xhr.send();
}, [])
return (
<div className="viewer" ref={ref}/>
)
}
export default HWPViewerPage
코드에 대해 설명 해보면 먼저 useEffect를 통해 컴포넌트가 render됨과 동시에 loadFile 함수가 호출된다.
firebase storage에서 얻은 download url을 File 객체로 변환하고 이 객체를 showViewer 함수의 parameter로 전달해서 실행하는 함수이다. 처음에는 fetch api를 통해 구현하려고 했는데 firebase storage의 download url이어서 그런지 내가 fetch api에 대해 능숙하지 못해서인지 실행이 되지 않았다. 결국 firebase storage 문서의 XMLHttpRequest 예시를 응용해서 작성했다.
File 객체를 parameter로 받아서 FileReader객체의 readAsBinaryString 메소드로 읽는다. 앞 단계가 완료되면 onloadend 메소드가 호출되면서 읽어들인 binary string을 hwp.js 라이브러리의 Viewer 객체의 parameter에 전달한다. Viewer 객체는 2가지 parameter를 받는데, 첫 번째는 HTMLElement를 받고 (여기서는 ref) 두 번째로는 Unit8Array를 (여기서는 bstr) 받는다. 세 번째 parameter는 option에 관한 parameter이다.
그 결과로 hwp파일은 ref의 형태로 div태그에 전달되고 뷰어에 출력된다.
처음에 hwp.js 라이브러리의 존재를 알았을 때는 hwp를 지원해주는 라이브러리가 있다는 것에 감격했다. 그러나 아무리 검색을 해도 chrome extension으로 사용되는 예시가 대부분이었고 React와 같은 javascript 기반 프로젝트에서는 어떻게 사용하는지 설명해주거나 사용해본 후기 글이 없었다... 그렇게 1차 멘붕 후 결국 제작자 분의 hwp.js github을 뒤져보기 시작했고 typeScript로 작성된 것을 보고 2차로 멘붕을 했다. 검색을 통해 찾아낸 ts to js 번역기와 함께 코드를 분석해서 결과적으로 구현을 성공했을 때 정말 감격적이었다. 다른 사람들은 부디 이 글을 읽고 편하게 사용했으면 좋겠어서 이 글을 남긴다. (물론 잘하시는 분들은 github 슥슥 보고 구현하겠지만...) 어서 TypeScript 공부해야겠다
※ 위 구현은 지극히 초보자가 작성한 코드이므로 더 좋은 방법이 있다면 댓글로 달아주시면 감사하겠습니다.
https://github.com/hahnlee/hwp.js
https://developer.mozilla.org/ko/docs/Web/API/FileReader
https://firebase.google.com/docs/storage/web/download-files
안녕하세요. 좋은글 감사드립니다!. 혹시 hwp.js yarn add후 임포트하실때 오류 뜨시지 않으신가요?
같은 리액트 프로젝트인데 제 프로젝트는 fs모듈 못찾는다고 뜨더군요