모듈 달래기 (Mediapipe 모듈 불러옴 문제)

7월 10일 저녁 식사 이후로 팀장 지시로 디버깅을 하나 맡게 되었다.

  • 배포 서버 환경하에서, 지화(자음, 모음)을 수행하는 섹션에서 Mediapipe 모듈에 관한 로딩 문제를 해결하기

 

증상 좁히기 - 증상 바꾸기 - 영향권 확인하여 적용이라는 nonstop-routine을 고수하던 입장에서 증상 좁히는데 감을 도저히 잡을 수가 없었다. 한 밤 11시쯤은 되어서야 겨우 확인 한 것이..

  • 로컬에서 가져오는 모듈의 내용과 배포 서버에서 가져오는 내용이 전혀 다름. 정확히 이야기하면 배포 서버는 내용이 없고 빈 껍데기뿐이다.

mediapipe 에서는 흔히 발견되는 문제라곤 하는데 해결책은 제각각이던가 영 도움이 안되는 식의 내용들 밖에 없는게 상당히 막막한 상황이었다. 심지어 2년 전에 정글 2기 수료생이 작성했던 글에도 일부 누락 된 내용이 있어 github에 당시 진행했던 프로젝트를 전부 뒤집어 엎어 봤지만 유의미한 소득은 없었다.

 
let HandsConstructor; 
	try 
	{ 
		const { Hands } = await import('@mediapipe/hands'); 
		HandsConstructor = Hands; 
		console.log('MediaPipe Hands 로드 성공:', typeof HandsConstructor);
	} catch (error)
    { 
    console.error('MediaPipe Hands 로드 실패:', error);
    throw new Error('MediaPipe Hands를 로드할 수 없습니다. 페이지를 새로고침해주세요.');
    }
    if (typeof HandsConstructor !== 'function')
    {
    	throw new Error('MediaPipe Hands 생성자가 유효하지 않습니다.');
    }
    const hands = new HandsConstructor({ locateFile: (file) => 
    { // CDN URL을 더 안정적으로 설정 
    const baseUrl = 'https://cdn.jsdelivr.net/npm/@mediapipe/hands@0.4.1646424915';
    return `${baseUrl}/${file}`; }, });

이 함수는 로컬에선 별 이상이 없어서 배포 환경에서도 무슨 일이 있을까 했지만 배포 환경에서는 HandsConstructor가 생성자가 아니라는 뭔 이상한 소리를 하고 있어 싶은 오류만 나타났다. 이 코드를 아래와 같이 수정하였다.

 

 
 
const HandsConstructor = (window as any).Hands;
	if (typeof HandsConstructor !== 'function')
	{
		console.error('window.Hands is not a constructor:',(window as any).Hands);
        throw new Error('MediaPipe Hands 생성자를 찾을 수 없습니다 (global)');
        }
        const hands = new HandsConstructor({ locateFile: (file: string) => { return `/${file}`; },​

그리고 추가적인 작업이 필요하다.

작업 환경 + 로컬 환경에서는 node_modules 안에 @mediapipe/hands가 가 당연히 포함되어 있을 것이라고 기대하게 되지만 EC2에서는 그렇지 않은 모양이다. 그래서 node_modules 내의 내용을 프론트가 활용 할 수 있는 리소스 폴더인 public에 위치시켰다.

 
 
const CameraConstructor = (window as any).Camera; // Camera 인스턴스 생성
console.log(CameraConstructor);
const camera = new CameraConstructor(videoElement, { onFrame: async () => 
	{
	try
	{
    // hands 인스턴스가 유효한지 확인
    if (hands) {
    	await hands.send({ image: videoElement }); } }
        catch (error) {​

Camera에 대해서도 동일하게 적용해준다. 다만 이 부분은 모호함의 여지가 있어 기존 import문을 지워야했다.

 

 

야호