현재 Next.js는 14 버전을 사용하고 있고 앱 라우팅 방식을 사용하고 있다.
그리고 codesandbox에서 제공하는 코드 에디터 라이브러리인 sandpack을 도입해 프로젝트에 적용하고 있는 상황 이었다.
sandpack은 브라우저에서 코드 실행 환경을 제공하는 라이브러리인데, 왼쪽에서 코드를 입력하면 오른쪽에서 바로 실행 결과를 확인할 수 있다.

현재 로컬 환경에서 3001번 포트에서 Next.js 개발 서버를 실행하고 있고, 직접 127.0.0.1:3001로 접근하는 대신에 hosts 파일을 수정해 example.local(예시) 도메인을 127.0.0.1로 매핑하여 사용 중이었다.

그리고 sandpack을 테스트하기 위해서 /sandpacktest 경로를 따로 라우팅했다.
// sandpacktest/page.tsx
import { Sandpack } from "@codesandbox/sandpack-react";
export default function SandpackTestPage() {
const files = {};
return <Sandpack files={files} theme="light" template="react" />;
}
sandpack에서 제공하는 기본 예제 코드로 테스트를 진행하려고 브라우저에서 example.local:3001/sandpacktest에 접속했는데, 다음과 같은 오류가 발생했다.
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'digest')

이 오류는 sandpack-react 라이브러리 내부에서 WebCrypto API를 사용하는데, crypto.subtle.digest가 undefined일 경우 발생하는 문제라고 한다.
처음에는 crypto가 서버 사이드 렌더링(SSR) 환경에서 동작하지 않는 것 같아서 여러 가지 방법을 시도해봤지만 결국 해결되지 않았다.
이 오류에 대한 해결책을 찾기 위해 구글링을 하던 중, 해외 GitHub 이슈에서 한가지 힌트를 발견할 수 있었다.

GitHub의 내용을 정리하면 다음과 같다.
WebCrypto API는 보안 환경(secure context)에서만 사용할 수 있습니다.
즉, 오로지 localhost나 다른 https 호스트에서만 이용이 가능합니다.
불행하게도, 이 문제를 우회하려면 SHA-256을 JavaScript로만 구현한 라이브러리를 추가해야 하지만,
솔직히 이것은 우리가 전혀 원하지 않는 방향입니다.
이런 라이브러리들은 성능이 매우 낮고, 공급망 공격(supply-chain attacks)에 취약할 가능성이 높기 때문입니다.
그러므로, 우리는 이 문제를 수정하지 않을 것입니다.
그래도 여전히 IP 주소에서 사용하려면, 다음 방법을 사용할 수 있습니다:
1. WebCrypto API를 JavaScript로 구현한 Polyfill을 적용
2. IP 주소를 HTTPS로 제공
localhost에서만 이용이 가능하다고 해 127.0.0.1:3001/sandpacktest로 접속해봤는데,
놀랍게도 오류가 발생하지 않았다.
즉, example.local이 127.0.0.1로 매핑되더라도 브라우저는 이를 보안 컨텍스트(secure context)로 취급하지 않는다는 것을 깨달았다.
하지만 매번 127.0.0.1로 접속하는 것은 너무 번거롭기 때문에, example.local:3001/sandpacktest에서도 정상적으로 동작하도록 만들고 싶었다.
그래서 2번째 방법인 "IP 주소를 HTTPS로 제공"하는 방식으로 해결하고 싶었다.
로컬 환경에서도 https를 적용하면 문제를 해결할 수 있다는 것이다.
그래서 로컬에서도 https 환경을 적용하는 방법을 찾아보았다.
sandpack이 https 환경에서만 동작하는 문제를 해결하기 위해서 로컬에서 https 프록시를 설정하는 방법을 적용했다.
이 과정에서 mkcert와 local-ssl-proxy 라이브러리를 사용해 http 개발 서버(3001번)를 https(3002번)로 변환하는 방식을 사용했다.
Next.js 개발 서버(http) → 기존대로 3001번 포트에서 실행
3002번 포트에서 https 프록시를 실행해 https 요청을 http로 변환
브라우저에서 https://example.local:3002/ 로 접속하면, 내부적으로 3001번 개발 서버로 연결됨
이렇게 하면 example.local:3002에서 https 환경을 제공하면서도, Next.js 개발 서버는 기존 방식 그대로 유지할 수 있다.
그러기 위해서는 local-ssl-proxy와 mkcert 라이브러리가 필요하다.
local-ssl-proxy 라이브러리는 https → http 변환 프록시 역할을 하는 라이브러리이고 mkcert를 사용하여 로컬 인증서를 발급할 수 있다.
local-ssl-proxy는 다음과 같이 설치한다.
yarn add local-ssl-proxy
그리고 나는 macOS를 사용 중이기 때문에 터미널에 homebrew로 mkcert를 설치해 주었다.
brew install mkcert
mkcert가 설치가 완료되었다면, 다음 명령어로 macOS Keychain에 로컬 인증서를 신뢰하도록 등록한다.
mkcert -install
그리고 프로젝트의 루트 폴더에서 다음 명령어를 실행해 https 서버용 인증서와 개인 키를 생성한다.
mkcert example.local
명령어 실행이 완료되면 프로젝트 루트 폴더에 아래 두 개의 파일이 생성된다.
이제 이 인증서로 https 프록시를 구성할 수 있다.
나는 package.json 파일의 기존 scripts에 dev:ssl-loc 명령어를 추가했다.
scripts": {
"dev:ssl-loc": "local-ssl-proxy --source 3002 --target 3001 --cert ./example.local.pem --key ./example.local-key.pem"
}
이렇게 한 뒤 yarn run dev:ssl-loc 명령어로 실행하니 아래와 같이 실행되었다.

그리고 기존 3001번 포트에 기존 개발 서버를 띄우던 방식으로 동시에 띄웠다.
이제 브라우저에서 https://example.local:3002/sandpacktest로 접속하면,
프록시되어 https 환경에서도 sandpack이 정상적으로 동작한다!
