https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
다시 isMobile 조건을 찾아보기 위해 위 mdn의 browser detection 내용을 보기로 한다.
참고할 만한 부분은 다음과 같다.
Considerations before using browser detection
When considering using the user agent string to detect which browser is being used, your first step is to try to avoid it if possible. Start by trying to identify why you want to do it.
어떤 브라우저에서 실행되는지 확인하고 싶다면, 그다지 좋은 방법이 아닙니다. 정확히 왜 필요한지 먼저 생각하세요.
Are you trying to work around a specific bug in some version of a browser?
Look, or ask, in specialized forums: you're unlikely to be the first to hit this problem. Also, experts, or people with another point of view, can give you ideas for working around the bug. If the problem seems uncommon, it's worth checking if this bug has been reported to the browser vendor via their bug tracking system (Mozilla; WebKit; Blink; Opera). Browser makers do pay attention to bug reports, and the analysis may hint about other workarounds for the bug.
버그를 찾고자 하는 것이라면, 브라우저의 버그 리포트 시스템을 먼저 확인하세요. 에러 메시지가 다른 경우가 있을 것입니다.
Are you trying to check for the existence of a specific feature?
Your site needs to use a specific Web feature that some browsers don't yet support, and you want to send those users to an older website with fewer features but that you know will work. This is the worst reason to use user agent detection because odds are eventually all the other browsers will catch up. In addition, it is not practical to test every one of the less popular browsers and test for those Web features. You should never do user agent sniffing. There is always the alternative of doing feature detection instead.
특정한 기능 지원이 필요한가요?
user agent를 찾기보다, 아래에 feature detection 예시를 보고 적용하세요.
Do you want to provide different HTML depending on which browser is being used?
This is usually a bad practice, but there are some cases in which this is necessary. In these cases, you should first analyze your situation to be sure it's really necessary. Can you prevent it by adding some non-semantic <div> or <span> elements? The difficulty of successfully using user agent detection is worth a few disruptions to the purity of your HTML. Also, rethink your design: can you use progressive enhancement or fluid layouts to help remove the need to do this?
브라우저에 따라 html 자체를 바꾸려고 하나요?
역시, 권장하지 않습니다.
위에서 보았듯이, 원래 사용하던 방법은 좋지 않다고 설명하는데,
function isMobile() {
if (_isNavigatorDefined()) {
// tslint:disable-next-line:no-any
var a = navigator.userAgent || navigator.vendor || window.opera; // tslint:disable-next-line:max-line-length
return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || // tslint:disable-next-line:max-line-length
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4));
}
return false;
}
// 이것 말고 다른 걸 사용해야 한다..
위 mdn 문서에서는 이러한 코드를 설명한다.
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
// 어떤 기기에는 터치스크린이 존재하는 경우도 있기 때문에, 터치스크린이 아니라 터치 스크린의 개수를 판별하는 값으로 모바일을 판단한다.
hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
const mQ = matchMedia?.("(pointer:coarse)");
// 모바일에서 사용하는 포인터 방식, pc는 fine으로 알고있음
if (mQ?.media === "(pointer:coarse)") {
hasTouchScreen = !!mQ.matches;
} else if ("orientation" in window) {
hasTouchScreen = true; // deprecated, but good fallback
} else {
// Only as a last resort, fall back to user agent sniffing
// 그리고 위 코드 이후에 유저 에이전트까지 검사한다.(원래 하던 방식 대로)
const UA = navigator.userAgent;
hasTouchScreen =
/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
/\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
}
}
if (hasTouchScreen) {
document.getElementById("exampleButton").style.padding = "1em";
}
위 코드를 4-1에서 만든 훅에 넣어주었다.
'use client';
import { useEffect, useState } from 'react';
import { useWindowSize } from '.';
import { TAILWIND_XL } from '@/constants/resoultions';
export function useResolutions() {
const { width, height } = useWindowSize();
const [isXL, setIsXL] = useState<boolean>(false);
useEffect(() => {
requestAnimationFrame(() => {
let hasTouchScreen = false;
if ('maxTouchPoints' in navigator) {
hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ('msMaxTouchPoints' in navigator) {
hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
const mQ = matchMedia?.('(pointer:coarse)');
if (mQ?.media === '(pointer:coarse)') {
hasTouchScreen = !!mQ.matches;
} else if ('orientation' in window) {
hasTouchScreen = true; // deprecated, but good fallback
} else {
// Only as a last resort, fall back to user agent sniffing
const UA = navigator.userAgent;
hasTouchScreen =
/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
/\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
}
}
if (hasTouchScreen) {
return;
}
if (width >= TAILWIND_XL) {
setIsXL(true);
} else {
setIsXL(false);
}
});
}, [width]);
return {
isXL,
};
}
그렇다면 이렇게 lazy load가 구현된 페이지의 렌더링 시간은 얼마나 걸릴까?
빌드 이후 pc 화면을 기준으로 비교하였을 때,
lazy loading 구현된 코드
기존 코드 server component만으로 된 코드
대략 100ms 정도의 차이가 난다.
현재로써는 코드에 부하가 걸릴 것 만한 것도 없고, 크게 정밀하게 분석할 필요는 없다고 생각한다.
또한 nextjs13 의 앱 라우팅이 아직 베타단계이기도 하기 때문에, 차후 프로젝트 크기를 키워 나가면서 추가적으로 분석을 해도 충분할 것이다.