최근 프로젝트에서 우리가 개발한 JavaScript SDK를 다른 회사에 제공하는 일이 있었습니다. 이 SDK는 여러 회사에서 사용될 예정이었기 때문에, 소스 코드를 보호하기 위해 JavaScript 파일을 암호화하고 난독화하여 제공해야 했습니다. 하지만 여기서 문제가 발생했습니다. 그 중 한 회사는 TypeScript(이하 TS) 기반의 React 프로젝트를 사용하고 있었고, 그들은 난독화된 SDK를 해당 프로젝트에서 사용할 수 있기를 원했습니다. 이 글에서는 이 문제를 해결하기 위해 시도한 다양한 방법과 최종적으로 채택한 해결책에 대해 상세히 설명하고자 합니다.
우리가 제공한 SDK는 기본적으로 JavaScript 파일이었습니다. 보안을 위해 소스 코드가 암호화되고 난독화되어 있어, 일반적인 방식으로는 TS 기반의 React 프로젝트에 바로 가져다 사용할 수 없었습니다. TS 프로젝트에서는 일반적으로 import
나 require
를 통해 모듈을 가져와 사용하지만, 이미 난독화된 SDK 파일에서는 이러한 방법을 사용할 수 없었습니다. 난독화된 파일은 기존의 TS에서 JavaScript 파일을 가져다 쓰는 방식으로는 전혀 호환되지 않았습니다.
이 문제를 해결하지 못하면, SDK를 사용하려는 회사는 파일을 다시 TS로 작성하거나 기존 코드를 모두 수정해야 하는 상황에 놓이게 됩니다. 이는 시간과 리소스의 낭비를 초래할 뿐만 아니라, 우리 SDK의 사용성을 크게 저해할 수 있었습니다.
문제를 해결하기 위해 몇 가지 방법을 시도했습니다. 각 방법은 그 나름의 이유와 가능성을 가지고 있었지만, 최종적으로는 모든 방법이 실패로 끝났습니다. 그럼에도 불구하고 이 과정에서 얻은 경험은 최종 해결책을 찾는 데 큰 도움이 되었습니다.
useState
와 같은 React Hook을 활용한 접근첫 번째로 시도한 방법은 React의 useState
와 같은 Hook을 활용하는 것이었습니다. 이 방법은 난독화된 JavaScript 파일을 가져와서 React 상태로 관리하고, 이를 컴포넌트 내에서 사용하는 것을 목표로 했습니다. 이를 통해, 난독화된 SDK 파일을 TS에서 쉽게 사용할 수 있기를 기대했습니다.
그러나 이 방법은 예상과 달리 효과적이지 않았습니다. 난독화된 파일은 TS와의 호환성이 떨어졌으며, 파일 내에서 필요한 변수를 TS에서 관리하는 것도 어려웠습니다. 특히, TS의 엄격한 타입 검사와 호환되지 않아서 이 방법을 포기해야 했습니다.
다음으로 시도한 방법은 난독화된 JS 파일을 IIFE로 감싸서 전역 범위에 SDK 객체를 등록하는 것이었습니다. 이 방법은 전역 변수를 이용해 SDK를 접근할 수 있게 해주며, TS의 모듈 시스템을 우회할 수 있는 가능성이 있었습니다.
하지만, 이 방법 또한 문제를 해결하지 못했습니다. TS의 컴파일러는 여전히 해당 전역 변수를 인식하지 못했으며, TS 파일 내에서 이를 제대로 가져와 사용하는 것이 불가능했습니다. 또한, 난독화된 코드 내에서의 참조 문제도 여전히 존재했기 때문에 이 방법 역시 실패로 끝났습니다.
또 다른 접근 방법으로, 난독화된 JS 파일에서 필요한 부분을 export
한 후, TS 파일에서 import
하는 방법을 시도했습니다. 이는 기존의 TS와 JS 간의 모듈 가져오기 방식을 그대로 유지하면서도 난독화된 파일을 활용할 수 있는 방법이었습니다.
그러나 이미 난독화된 파일은 내부 구조가 손상되었기 때문에, export
및 import
는 전혀 작동하지 않았습니다. 내부 함수나 변수들을 내보낼 수 없었으며, TS 파일에서 이를 가져올 수도 없었습니다. 이로 인해 이 방법도 포기할 수밖에 없었습니다.
여러 가지 시도 끝에, 우리는 전통적인 웹 개발 방식으로 돌아가서 문제를 해결하기로 했습니다. 난독화된 SDK 파일을 TS 파일이나 React 컴포넌트에서 직접적으로 사용하는 대신, 해당 파일을 퍼블릭 폴더에 넣고 index.html
파일에서 <script>
태그를 통해 로드하는 방법을 선택했습니다.
우선, 프로젝트의 퍼블릭 폴더에 sdk.js
파일을 배치했습니다. 퍼블릭 폴더는 웹 서버가 정적으로 제공하는 파일들을 보관하는 곳으로, 여기서 제공된 파일들은 웹 페이지가 로드될 때 클라이언트 측에서 직접 접근할 수 있습니다. 그런 다음, index.html
파일에 <script src="/sdk.js"></script>
태그를 추가하여 SDK 파일이 웹 페이지 로드 시 자동으로 포함되도록 설정했습니다.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My React App</title>
</head>
<body>
<div id="root"></div>
<script src="/sdk.js"></script>
</body>
</html>
이제 SDK가 전역적으로 접근 가능하도록 하기 위해, TS 코드에서 전역 객체에 SDK를 바인딩하는 작업이 필요했습니다. 이를 위해, TS에서 declare global
구문을 사용해 Window
객체에 새로운 프로퍼티를 선언하고, useEffect
훅을 이용해 컴포넌트가 마운트될 때 SDK를 전역 객체에 바인딩하도록 설정했습니다.
// AppWrapper.tsx
import React, { useEffect } from 'react';
declare global {
interface Window {
SDK: any;
}
}
const AppWrapper: React.FC = () => {
useEffect(() => {
try {
eval('window.SDK = SDK;');
} catch (error) {
console.error('SDK를 window 객체에 바인딩할 수 없습니다.', error);
}
if (window.SDK) {
let ws;
window.SDK.createInstance("wss://-.com", "param1", "param2");
ws = window.SDK.getInstance();
console.log(ws);
} else {
console.error('SDK가 로드되지 않았습니다.');
}
}, []);
return <App />;
};
export default AppWrapper;
useEffect
로 SDK 초기화useEffect
훅은 React 컴포넌트가 처음 렌더링될 때 실행되는 코드 블록을 설정할 수 있는 기능입니다. 이 훅을 이용해, index.html
에서 로드된 sdk.js
파일이 제대로 전역 객체에 바인딩되었는지 확인하고, 이후 필요한 초기화를 진행할 수 있었습니다.
이 과정에서 eval
을 사용해 SDK
를 전역 window
객체에 바인딩했습니다. eval
사용은 가능한 피해야 하지만, 이 경우 난독화된 파일을 직접적으로 접근할 방법이 없기 때문에, 부득이하게 이 방법을 사용했습니다.
이번 문제는 난독화된 JavaScript SDK를 TS 기반의 React 프로젝트에서 활용하는 과정에서 발생한 복잡한 문제였습니다. 여러 가지 방법을 시도했지만, 최종적으로는 전통적인 HTML과 JavaScript의 방식을 활용해 문제를 해결할 수 있었습니다. 퍼블릭 폴더와 <script>
태그를 이용해 난독화된 SDK를 로드하고, TS 코드에서 전역 객체를 사용해 이를 참조함으로써, 리소스를 최소화하면서도 기존의 TS 프로젝트 구조를 크게 변경하지 않고 SDK를 사용할 수 있게 되었습니다.
이번 경험은 난독화된 코드와 모던 웹 기술의 통합에 대해 깊이 고민하게 만든 사례였으며, 앞으로 유사한 상황에서 큰 도움이 될 것입니다. 이 글이 비슷한 문제를 겪고 있는 개발자들에게 도움이 되기를 바랍니다.