first-child vs first-of-type

The pseudo class “:first-child” is potentially unsafe when doing server-side rendering. Try changing it to “:first-of-type”.
The pseudo class “:nth-child” is potentially unsafe when doing server-side rendering. Try changing it to “:nth-of-type”.

  • first-child를 사용하면 콘솔에 에러가 찍힌다
  • 그러면서 first-of-type을 사용하라고 알린다
  • 이참에 둘의 차이를 알아보았다
example.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style>
h1:first-child {
color: red;
}
h4:first-of-type {
color: green;
}
</style>
<body>
<div>
<h1>first-child로 빨간색이 된다</h1>
<h4>first-of-type으로 인해 초록색이 된다</h4>
</div>
<hr />
<div>
<h4>first-of-type으로 인해 초록색이 된다</h4>
<h1>효과를 안 받는다</h1>
</div>
</body>

참고

ngrok 내 웹앱 포트포워딩없이 https 공유하기

  • https://ngrok.com/download
  • 포트포워딩없이 서버 외부에 공유하기
  • https로 열어준다
  • 너무 간단하다
  • zip 받아서 원하는 곳에 풀고,
terminal
1
ngrok http 3000
  • path 환경변수 등록해서 어디서든 cli에서 실행할 수 있다

  • 근데 이거보다 더 쉬운 localtunnel이 있다

대안 ; localtunnel

terminal
1
npx localtunnel --port 3000
  • 포트만 설정해주면 끝

참고

blog fix 다크 모드 화면 깜박임 제거

화면을 넘어갈 때 눈뽕(기본 테마가 잠깐 렌더링 됨)을 해결하기

상황

  • 다크 모드에서 계속 새로고침하고 있는 상황이다
  • 중간에 번쩍하고 흰색이 보였다
  • 다크 모드 사용 중에 이렇게 새로고침이나 페이지가 넘어갈 때마다 종종 흰색 화면으로 뒤덮이는 문제가 있었다
  • 디폴트 테마 ; 화이트
  • 설정한 테마 ; 다크
  • 다크 모드이면 body에 dark 클래스 추가
  • 다크 모드에서 새로고침이나 화면을 넘어갈 때 잠깐 흰색 화면이 보인다
  • 해결해보자

해결

  • body 태그 바로 아래에 스크립트를 두어 렌더링을 막았다
  • html에 백그라운드 css가 있다면 삭제

알아낸 점

  • 페이지가 넘어갈 때 이전 화면의 백그라운드가 유지된다 (이전 화면의 html이나 body의 백그라운드 컬러)
  • 렌더링은 완전히 파싱이 끝난 후에 이뤄진다
  • 중간에 스크립트를 두어 렌더링을 막을 수 있다(블로킹)
  • color-scheme css를 사용하면 스크롤바 다크 모드도 적용할 수 있다
  • color-scheme css를 사용하면 기본 백그라운드가 생긴다 (dark일시 어두운 백그라운드)

다크 모드 체크리스트

  • color-scheme css 사용하기
  • html 또는 body 태그에 적용되는 백그라운드 색이 있다면 없애기
  • 테마 초기화하는 블로킹 스크립트 넣기

참고

로딩 아이콘 만들기 loading.io

  • 커스텀 로딩 아이콘을 만들 수 있다
  • gif, svg, css, png, apng 등 여러 형식을 지원한다
  • css로 받으면 html, css 코드 스니펫을 주는데, 너무 신기하다 ㅋㅋㅋ

참고

js fetch 요청 취소, 중단하기

example.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let controller;

const fetchData = async (pram) => {
try {
console.log(`fetchData`);
if (controller) controller.abort();
controller = new AbortController();
const { signal } = controller;

const res = await fetch(`${API_END_POINT}/${pram}`, { signal });

if (!res.ok) {
throw new Error('no ok error');
}

return await res.json();
} catch (error) {
throw new Error('server error');
}
};
  • AbortController를 사용해서 기존에 요청이 있으면
  • 취소하고 새로운 요청을 보내는 예제이다
  • 버튼을 눌러서 fetchData를 실행시킨다고 하자
  • 유저가 빠르게 버튼 10번을 눌러서 fetchData가 10번 실행되었다
  • 이런 입력에 대한 아무런 방지를 않았으면, fetch 결과에 대한 콜백이 10번 실행될 것이다
  • AbortController을 사용하면 버튼을 연속적으로 누르더라도 콜백이 마지막 결과에 대해서만 한번 동작할 것이다
  • 하지만 AbortController를 사용한다고 해서 API를 콜하는 비용이 덜 드는 것은 아니다
  • 단순히 해당 fetch에 대한 결과를 핸들하지 않겠다는 것이기 때문에,
  • 지금의 예처럼 동일한 API를 중복해서 호출하는 것을 막기 위해서는
  • 최초에 버튼을 누르면 버튼을 비활성화하는 것이 좋다

참고

defer vs DOMContentLoaded

  • defer이 먼저 실행된다

defer 여러개 실행 순서

1
2
<script src="./defer.js" defer></script>
<script src="./defer2.js" defer></script>
  • 여러개의 defer가 있으면 위에서 아래로 순서대로 실행된다
  • defer.js 실행 -> defer2.js 실행

async와 DOMContentLoaded는 서로 무관하다

  • DOMContentLoaded 먼저 실행될수도 async가 먼저 실행될수도 있다

참고

이미지 레이지로딩

https://css-tricks.com/the-complete-guide-to-lazy-loading-images/

레이지로딩

  • 페이지에 이미지가 너무 많으면 로딩 속도가 느리다
  • 일반적으로 페이지가 로드되고 페이지에 포함된 모든 이미지가 로드된다
  • 레이지 로딩을 사용하면 로드를 뒤로 미룰 수 있고, 원하는 타이밍에 로드할 수 있다
  • 이를 통해 페이지를 빠르게 로딩할 수 있다
  • 콘텐츠를 제공하는 서버 비용을 아낄 수 있다

src 대신 data-src사용

1
2
<!-- <img src="https://via.placeholder.com/468x200?text=1" /> -->
<img class="lazy" data-src="https://via.placeholder.com/468x200?text=1" />
  • src를 사용하면 이미지가 로드되기 때문에, src는 사용하지 않는다
  • 대신 이미지 주소를 data-src에 저장한다
  • data-를 사용하면 js에서 dataset을 통해 접근할 수 있다

Observer API 사용

public/js/method2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let lazyloadImages;

if ('IntersectionObserver' in window) {
lazyloadImages = document.querySelectorAll('.lazy');
const imageObserver = new IntersectionObserver(
function (entries, observer) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
const image = entry.target;
image.src = image.dataset.src;
image.classList.remove('lazy');
imageObserver.unobserve(image);
}
});
},
{
root: document.querySelector('.container'),
rootMargin: '0px 0px 500px 0px',
}
);

lazyloadImages.forEach(function (image) {
imageObserver.observe(image);
});
}
  • Observer API를 통해 이미지가 뷰포트에 들어오면
  • 그제야 src를 초기화해서 이미지를 로드한다
  • 로드된 이미지는 더 이상 옵저버가 관찰하지 않도록 unobserve() 해준다
  • IntersectionObserver 생성자 두 번째 인자로 rootMargin을 설정해줄 수 있는데,
  • 사용하지 않았을 때, 뷰포트에 들어오면 이미지 로드가 시작되어 불러오는 반면
  • rootMargin을 설정해주면, 설정한 값만큼 미리 옵저버가 반응해서 이미지를 로드할 수 있도록 한다

참고

모바일 크롬 개발자 도구 사용, 포트포워딩해서 localhost 환경 만들기

  • 모바일에서 동작하는 devicemotion 이벤트 등 디버깅하기 위해 개발자 도구를 봐야 했다
  • 모바일에서 개발자 도구를 어떻게 켜는지 등 찾아보다가
  • 핸드폰을 데탑에 연결하고
  • 데탑의 크롬에서 console의 출력 결과를 확인할 수 있다
  • 그리고 모바일 화면을 미러링 해준다

하는 법

“[Android 개발] 크롬 개발자 도구 모바일 디버깅/Mobile Debugging/ PC에서 모바일 디버깅 / 모바일 개발환경 구축”
https://backstreet-programmer.tistory.com/30

  • 위 블로그를 참고해서 핸드폰과 데탑을 연결했다

포트포워딩 하기

  • devicemotion, geolocation 등 보안 컨텍스트가 필요한 Web API의 경우 localhost로 만들어줘야 한다
  • 내부IP:PORT 해서 접속은 할 수 있지만,
  • devicemotion가 정상 동작하려면 localhost여야 한다

상황

  • 데탑에서 웹 개발 진행 중

  • 로컬에서 5500 포트로 웹서버가 열려있음

  • 모바일에서 위 웹서버에 접속하려면 내부아이피:포트를 입력해야함

  • 모바일에서 localhost:5500을 입력해서 접속할 수 있도록 해보자

  • chrome://inspect/#devices 에 접속한다

  • 내 핸드폰이 잘 연결되었는지 확인한다

  • 포트 포워딩 버튼을 누른다

  • 5500 포트와 localhost:5500을 매칭시켰다
  • 이제 핸드폰 크롬에서 localhost:5500으로 접속하면 웹서버에 접속할 수 있다!
  • 물론 Web API도 모두 잘 동작한다

참고

geolocation 등 HTTP에서 사용할 수 없는 Web API 목록

  • geolocation 등 특정 Web API들은 localhost 또는 HTTPS 환경에서만 동작한다
  • 그래서 로컬에서 테스트했을 땐 동작하는 것들이 http로 배포했을 때 동작하지 않을 수 있다
  • secure context가 필요한 API 목록은 아래 링크에서 확인할 수 있다

참고