두가지 에러가 발생했다.
Uncaught (in promise) TypeError: self.crypto.randomUUID is not a function
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'writeText')
우리 프로젝트에서는 아래와 같은 토스트 훅을 사용하고 있었다.
export const useToast = () => {
const setToastList = useSetAtom(toastAtom);
const showToast = (
message: string,
variant?: "error" | "success" | "default",
duration?: number,
) => {
const added = {
id: self.crypto.randomUUID(),
message,
variant,
duration: duration ?? 2000,
};
setToastList({ toast: added });
};
return { showToast };
};
crypto.randomUUID
가 일부 환경에서 지원하지 않아 발생한 오류라고 판단하였다.
"randomUUID" | Can I use... Support tables for HTML5, CSS3, etc
94.86% 의 사용을 봐서 브라우저 호환성 문제는 아닐 것 같다고 생각했지만, 이것이 지원되지 않는 환경에선 어떻게 대처할 수 있을 지를 고민했다.
uuid 라이브러리 사용: 브라우저 호환성 문제가 거의 발생하지 않아 안정적으로 사용 가능
import { v4 as uuidv4 } from "uuid";
export const generateUUID = (): string => {
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
return crypto.randomUUID();
}
return uuidv4();
};
폴리필 작성
// crypto.randomUUID 폴리필
if (!crypto.randomUUID) {
crypto.randomUUID = () => {
// UUID v4 생성 로직
return ([1e7] as any + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(
Number(c) ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (Number(c) / 4)))
).toString(16)
);
};
}
브라우저 호환성 문제일까 싶어서 브라우저 호환성을 해결할 방법을 찾아봤지만, 아무리 검토해도 환경 문제는 아니라고 판단했다.
그럼 대체 뭐가 문제일까 !!!
prod 서버는 정상적으로 작동한다는 것을 알았다. 왜 rc 서버에서만 작동이 되지 않는걸까?
prod 서버는 https://algohub.kr
을 사용하고 있지만, rc 서버에서는 http://rc.algohub.kr
을 사용하고 있다.
혹시 http라서 그런걸까?
https://developer.mozilla.org/ko/docs/Web/API/Navigator/clipboard
정답이었다. Navigator Clipboard API는 HTTPS, LOCAL 환경에서만 지원해서 안 되는 것이었다.
https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID
1번에서 적은 오류 또한 HTTP 에서 사용할 수 없는 문제로 기인한 것이었다.
https를 사용하면 해결되는 문제 !
그럼 http에서는 해결책이 없을까?
execCommand
를 사용하면 된다.
const copy = async (code: string) => {
const inviteWriting = `[AlgoHub 알림]\n\n'${ownerNickname}'님께서 회원님을 ‘${groupName}’ 그룹에 초대하셨습니다!\n\n아래 링크를 클릭하셔서 초대를 수락해 주세요!\n함께 도전하며 발전하는 시간을 보내시길 기대합니다.\n\n지금 바로 참여하세요:\nalgohub.kr/join-group/${code}`;
if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
try {
await navigator.clipboard.writeText(inviteWriting);
showToast("성공적으로 복사되었습니다.", "success");
setIsCopied(true);
} catch (err) {
showToast("복사에 실패했습니다. 다시 시도해 주세요.", "error");
}
} else {
// Clipboard API 미지원 시 대체 로직
const textarea = document.createElement("textarea");
textarea.value = inviteWriting;
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand("copy");
showToast("성공적으로 복사되었습니다.", "success");
setIsCopied(true);
} catch (err) {
showToast("복사에 실패했습니다. 다시 시도해 주세요.", "error");
} finally {
document.body.removeChild(textarea);
}
}
};
textarea
요소 생성textarea
의 value
속성에 저장execCommand
로 복사
잘 읽었습니다!
execCommand의 MDN(https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand)에 가보면 Deprecated 경고가 나와요. 모든 페이지에 https를 적용하는 방법이 가장 베스트일 것 같다고 느껴집니다 :)