May 11, 2024 • ☕️☕️☕️ 14 min read
window.matchMedia
와 prefers-color-scheme
으로 사용자의 다크/라이트 모드 구분하기window.matchMedia
로 미디어 쿼리 문자열을 분석할 수 있다.
if (window.matchMedia("(min-width: 400px)").matches) {
/* 뷰포트 너비가 400 픽셀 이상 */
} else {
/* 뷰포트 너비가 400 픽셀 미만 */
}
그리고 CSS의 prefers-color-scheme
속성은 사용자의 디바이스가 다크모드인지 라이트모드인지 알려준다.
.theme-a {
background: #dca;
color: #731;
}
@media (prefers-color-scheme: dark) {
.theme-a.adaptive {
background: #753;
color: #dcb;
outline: 5px dashed #000;
}
}
사용자가 웹페이지에서 다크/라이트 모드를 직접 변경하도록 옵션을 제공하고 싶을 때, 다음과 같이 작성할 수 있다.
window.matchMedia("(prefers-color-scheme: dark)").matches ? ... : ...;
Ref
webpack config에서 loader가 적용되는 순서는 ‘뒤에서부터’라고 하는데, 잘 이해가 되지 않았다.
다음과 같이 적용 순서를 표현하면 이해하기 쉽다.
{
test: /\.ext$/
use: ['third-loader', 'second-loader', 'first-loader']
}
위 코드는 다음과 같이 동작한다.
third(second(first(source)))
Ref https://kettanaito.com/blog/writing-custom-webpack-loader
babel의 @babel/preset-react
에서 development를 사용하는 이유는 디버깅의 용이성 때문이다.
development 옵션을 사용하면 아래 플러그인을 추가로 사용한다.
@babel/plugin-transform-react-jsx-self
@babel/plugin-transform-react-jsx-source
그러면 jsx에 __self
와 __source
프로퍼티를 주게 되는데, 각 프로퍼티의 역할은 다음과 같다.
__self
: JSX 태그에 대한 참조를 나타내고, React가 이벤트핸들러 내에서 발생하는 오류를 디버깅할 때 사용된다.__source
: JSX 엘리먼트가 정의된 파일의 위치와 줄 번호 정보를 포함해서 개발자가 문제가 발생한 정확한 위치를 찾을 수 있도록 도움을 제공한다.Ref
iOS에서 input이 disabled인 경우, opacity가 0.4로 적용된다. (native style sheet - safari)
색상을 정확하게 표시 하기 위해서는 opacity 조정 및 -webkit-text-fill-color 추가로 색상을 고정해야 한다.
color: {color};
-webkit-text-fill-color: {color};
-webkit-opacity: 1;
opacity: 1;
운영체제에 따라 기본 폰트가 다르다.
Mac에서는 sans-serif 폰트에 대해서 Apple SD 산돌고딕 Neo 폰트가 적용되고, windows 에서는 맑은고딕(Malgun Gothic) 폰트가 적용된다.
같은 폰트 사이즈를 적용하더라도 실제 width가 같지 않아 문구 적용 시 여유가 거의 없는 경우라면 줄바꿈이 일어날 수 있다.
Promise.withResolvers
Promise.withResolvers
로 new Promise
를 대체할 수 있다. Promise.withResolvers
는 Promise
객체와 resolve
, reject
함수를 포함한 객체를 반환한다.
AS-IS
const delay = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms))
TO-BE
const delay = (ms: number) => {
const { promise, reject, resolve } = Promise.withResolvers();
setTimeout(resolve, ms);
return promise
}
ESLint v9는 4월 6일에 출시되었으며 현재는 9.2.0이다.
v9는 Flat Config 지원, 패키지에 ESLint 플러그인 내장 가능, 실행 속도 증가 등의 큰 변화가 있었다.
다만 생태계가 아직 Flat Config 호환 작업 진행중이기 때문에 실제 적용은 내년에나 하지 않을까 싶다.
oklch()
rgb()
혹은 hsl()
과 같이 색상을 정의할 때 사용할 수 있는 함수 표현식 중 하나
보통은 RGB를 많이 사용하지만, OKLCH는 RGB에 비해 코드만으로 색상 정보를 예측할 수 있을 정도로 가독성이 좋다는 장점이 있다.
Ref https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
form이 dirty할 때 navigation을 수행하기 전 confirm을 받을 수 있다.
client-side 라우팅 시에는 라우터 쪽에서, document를 새로 불러오는 라우팅 시에는 직접 beforeUnload
이벤트를 활용하면 된다.
cf) react-router-dom v6에는 useBlocker
훅이 존재한다.
babel, swc는 tsconfig.json을 바라보지 않는다.
tsc는 타입체킹, 컴파일을 모두 수행하기 때문에 타입 영역, 값 영역을 모두 바라본다.
그러나 babel, swc 등의 컴파일러는 트랜스파일에만 관심있고 타입체킹은 하지 않기 때문에 tsconfig.json을 필요로 하지 않는다. (값 영역만 사용)
cf) tsserver는 tsconfig.json을 이용해서 타입체킹을 합니다. (타입영역만 사용)
사실 생각해보면 당연한게 babel, swc 등의 컴파일러는 값 영역만 바라보기 때문에 tsconfig.json 옵션 거의 대부분이 필요하지 않다!
env
ESLint의 설정중 env
필드는 코드의 실행 환경을 ESLint에 알려주는 역할을 한다.
env: { browser: true, es2020: true }
browser: true
: 코드가 브라우저 환경에서 실행된다는 것을 나타내며, 브라우저 환경에서 사용 가능한 전역 변수(예: window, document 등)가 정의되어 있다고 가정한다. ESLint는 이러한 전역 변수를 인식하고 해당 변수 사용 시 오류를 발생시키지 않는다.es2020: true
: 코드가 ECMAScript 2020 (ES11) 이상의 기능을 사용한다는 것을 나타낸다. 즉, ESLint가 ES2020에 도입된 문법을 인식한다.
es2020: true
를 넣지 않으면 ES5가 기본값으로 설정된다.latest
가 기본값이다.
env
에서의 es버전과parserOptions
에서의 ecmaVersion도 주의해야 한다.env
에서는 특정 es버전의 전역변수를 위해 사용되고, 구문분석은parserOptions.ecmaVersion
를 사용한다.
criteriaMode
react-hook-form의 useForm
API에 criteriaMode
옵션이 있다.
발생한 validation을 하나만 잡을지 트래킹할지 고르는 옵션이다. (firstError
또는 all
)
all
로 설정하면 실패한 모든 validation을 알 수 있다. 에러 객체에 types
필드 안에 들어간다.
챗GPT에 의하면 firstError
로 설정하면 유효성 검사가 조금은 더 빠르다고 한다.
페이징 처리를 위한 서버의 offset 방식과, 이것이 왜 성능에 좋지 않은지 알아보자.
클라이언트는 보통 페이지네이션을 위해 page
(currentPage), pageSize
(limit)를 request param으로 보낸다.
그러면 서버에서 offset 값을 구하게 된다.
offset = (page - 1) * pageSize
(ex. 3페이지를 요청하는데, 10개까지만 볼래요 -> (3-1) * 10 = 20, offset = 20 )
그러면 서버에서는 질의를 다음과 같이 한다.
SELECT * FROM table LIMIT 10, OFFSET 20; -- 21 ~ 30 번까지 노출
앞 부분의 데이터를 조회할때는 문제가 되지 않지만, offset이 매우 클 경우 (ex. 1,000,000 부터 10개를 조회하는 경우)에는 성능상 문제가 될 수 있다.
이유는 데이터를 반환할 때, 처음 데이터부터 offset에 해당하는 row + limit 개수 까지 조회한 후에 앞에 필요하지 않은 데이터들을 날린 결과를 반환한다.
(ex. OFFSET: 5000, LIMIT 10인 경우, 5010개의 데이터를 모두 읽은 후, 5000번까지의 데이터는 버림. 이후 5001 ~ 5010까지 반환.)
watch
, formState.errors
대신, useWatch
, useFormState
를 사용하면 리렌더링 되는 범위를 해당 훅이 있는 컴포넌트로 격리할 수 있다.
trigger
를 사용할때 파라미터를 빈값이나 배열로 넘기면 전체 form 상태가 리렌더링 된다. 필드를 하나만 넘기는 것이 좋다.
딥링크: 특정 컨텐츠에 직접 도달하는 링크
예를 들어, https://comic.naver.com 로 들어가서 클릭 클릭을 통해 특정 웹툰 페이지로 들어가지 않고, https://comic.naver.com/webtoon/list?titleId=807178&tab=wed 로 직접 들어갈 때 사용되는 이 링크가 딥링크.
모바일에서 딥링크를 구현하는 방식은 세 가지가 있다.
App Link는 안드로이드만 지원, Universal Link는 iOS만 지원한다. URI Scheme은 모바일 앱에서 딥링크를 작동시키는 기술 표준으로, 사용자가 앱 내부의 컨텐츠에 직접 접근할 수 있게 해준다. 세 방식 중 가장 오래되었다.
하지만 URI Scheme에는 단점도 있다.
cf) 스킴: URI Scheme을 이용한 딥링크는 앱에 Scheme값을 등록한 후, 특정 Scheme값을 호출하면 특정 앱을 오픈한다.
앱스킴: URI Scheme 방식을 활용해 구현한, 앱에서 사용하는 Scheme
(ex. baemin://
, baemin-beta://
)
부록: 특정 지면에 사용되는 앱스킴과 달리 함수 또는 기능을 실행하는
action
스킴도 있다. (baemin-action://
)
<div style="margin-top: 10px">
<div style="margin-top: 10px"></div>
</div>
두 개의 <div>
가 모두 margin-top: 10px
을 갖고 있기 때문에, 결과적으로 margin-top
이 20px
이 될 것이라고 생각하기 쉽다. 하지만 실제로는 10px
의 margin
만 표시된다.
이를 마진 상쇄(margin collapse) 현상이라고 합니다.
마진이 상쇄되는 조건은 여러 가지가 있다.
이를 해결하기 위해서는 display: flow-root
를 사용할 수 있다. 해당 속성을 부모 자식 박스에 주면 새로운 BFC(Block Formatting Context)를 생성하게 된다. 부모와 자식은 서로 다른 BFC를 가지게 되어 마진 상쇄 현상이 발생하지 않는다.
Map을 사용하는 이유
객체를 사용하는 이유
Ref https://velog.io/@surim014/use-maps-more-and-objects-less
form
attribute를 사용하면 된다
<form id="my-form">
<input type="text" name="name" />
</form>
<button type="submit" form="my-form">저장</button>
Ref https://www.impressivewebs.com/html5-form-attribute/
구글 SEO 엔진은 <meta name="keywords">
태그를 무시한다.
keyword stuffing을 방지하기 위함인 것 같다
keyword stuffing? 검색 엔진에서 높은 우선순위를 얻기 위해 웹 페이지에 특정 키워드를 고의로 다량 삽입하는 행위를 말한다.
Ref
vscode의 settings.json 파일에서 eslint.workingDirectories
역할은 다음과 같다.
사용자가 페이지에 머무는 동안 발생시키는 모든 인터렉션을 관찰하여 전반적인 응답성을 관찰하는 지표
구글에서는 첫번째 입력만 체크하는 FID(First Input Delay) 지표를 대체하여 사용하고 있다. 200ms 이내일 때 좋은 INP 수치를 가졌다고 본다.
resolveLoader
- loader의 alias를 정할 수 있다 (Ref)(Ref)
세상에는 참 신기하고 대단한 사람이 많다.
Ref https://kciter.so/posts/ascii-3d-renderer/
토스에서 만든 새로운 한글 라이브러리
k-popo도 유용하다. 은/는/이/가 처리가 필요한 곳에 쓰기 좋다. (Ref)
Ref https://www.npmjs.com/package/es-hangul
npm의 superset으로 deno 팀에서 개발한 자바스크립트 레지스트리
npm이 출시될 때는 현재의 개발 환경을 염두에 두고 만들어지지 않았기 때문에, 이를 개선하고자 만들어졌다고 한다. 타입스크립트와 ESM 배포에 최적화되어 있다.
node 뿐만 아니라 deno, bun과 같이 다양한 자바스크립트 런타임 환경을 지원한다.
Ref https://jsr.io/
npm package의 크기를 체크해준다.
bundlephobia는 (모듈별로 나뉘긴 하지만) 통째로 보여주는 반면, bundlejs는 import하는 코드를 직접 작성하고 그것을 빌드한 결과물을 측정하므로 나무를 흔든 후의 실제 크기를 볼 수가 있다.
React19와 React Sever Component 관련 내용이 많이 보인다.
Ref https://conf.react.dev/agenda
사내 TIL 챌린지가 끝나지 않고 있다. 매주 새로 배우는 내용, 블로그에 적을 내용이 풍성해져서 좋지만 조금 벅차기도 하다 (ㅋㅋㅋ)
날씨도 따숩고 왠지 한가한 5월을 적당히 여유롭게 보내고 있는 요즘이다.
그리고 진짜 가고 싶던 뷰민라를 다녀왔지 🎵
다음은 펜타포트인가…🎸 큰일났다