July 2, 2022 • ☕️☕️ 12 min read
여름이닷
URL에서 pathname
, parameter
를 우아하게 가져올 수 있다.
// URL 사용하지 않고 특정 path를 가져올 때
const { pathname } = window.location;
const path = pathname.split("/")[1];
// URL을 사용해서 가져올 때
const { pathname } = new URL(window.location.href);
Ref https://developer.mozilla.org/en-US/docs/Web/API/URL
inner border line을 그리고 싶을 때, 일반적으로 box-sizing: border-box
를 사용하는데, 해당 케이스는 width나 height이 특정값으로 고정되어있을 때만 inner-border-line이 생긴다.
width, height이 auto 값으로 쓰여지는 경우가 생기면 예상과는 다르게 outside-border-line이 생긴다. 이런 경우에는 box-shadow
로 inner-border-line을 만들 수 있다.
useImperativeHandle
은 ref
를 사용할 때 부모 컴포넌트에 노출되는 인스턴스 값을 사용자화(customizes)한다. (즉 ref를 사용하는 부모 측에서 커스터마이징된 메서드를 사용할 수 있게 해준다.) forwardRef
와 함께 사용되는 훅이며, 새로운 ref
에 커스터마이징 작업을 할 수 있다. 아래 예시에서처럼 FancyInput
컴포넌트를 사용하는 곳에서 커스터마이징된 값을 이용할 수 있다.
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
// FancyInput 컴포넌트를 사용하는 곳
function FancyForm() {
useEffect(() => {
inputRef.current.focus(); // ✅ FancyInput의 `useImperativeHandle` 내 `focus` 함수를 실행한다.
}, [])
return (
<FancyInput ref={inputRef} />
)
}
Ref https://ko.reactjs.org/docs/hooks-reference.html#useimperativehandle
<a download/>
<a />
태그에 download 속성을 넣으면 href 경로에서 파일을 다운 받을 수 있는데, 해당 경로의 파일이 이미지라면 미리보기를, docx같은 파일이면 바로 다운로드 창이 뜬다.
이미지 또한 바로 다운로드창을 띄우고 싶으면 해당 경로에 대해 fetch를 사용해서 응답값을 받고, blob, URL, createObjectURL 등을 사용해서 링크를 새로 만들어서 받아온다.
fetch(url, { mode: "no-cors" })
.then((response) => response.blob())
.then((blob) => {
const blobUrl = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.download = fileName || "download";
a.href = blobUrl;
a.click();
});
Basic Auth는 하나의 HTTP 인증 방식이다.
username과 pw를 Base64 인코딩 해서 Basic -
의 형식으로 보내는 방식이다.
헤더에 Bearer AccessToken 보내는 방식과 유사하지만, Basic Auth 방식에서는 username, pw을 axios 요청에 넣어주면 axios가 알아서 Base64로 인코딩 처리해준다. 그후 요청을 열어보면, Authorization: Basic ZGVtbzpwQDU1dzByZA==
과 같은 형식으로 들어가 있다.
Ref https://stackoverflow.com/questions/34013299/web-api-authentication-basic-vs-bearer
chmod +x
- 실행권한을 부여하는 명령어이다.grep
- 현재 프로젝트에서 특정 문자열의 위치들을 찾을 수 있다. (vs code 검색기능이랑 동일)# -I 는 binary 파일 제외, r은 재귀적으로 탐색, n은 라인넘버 추출, w는 단어가 whole matching인 것만
grep --exclude-dir={"/User/...", ...} -I -rnw "${brosMobileDir}" -e "$imageName"
wc -w
- 문자열의 word 매칭개수를 반환한다.tr -d ' '
- trim 기능을 구현할 수 있다.superstruct 의 assign()
유틸 함수는 자바스크립트의 Object.assign()
과 유사하지만 첫번째 파라미터로 전달된 것과 동일한 구조체를 반환한다.
const schema = assign(
type({}), // ✅ 첫번째 파라미터가 type이기 때문에, 아래 구조체는 type이 된다.
object({
name: string(),
walk: func(),
})
);
const obj = {
name: "Jill",
age: 37,
race: "human",
walk: () => {},
};
assert(obj, schema); // OK
타입스크립트에서 타입가드를 위해 is
를 사용할 수도 있지만, asserts
키워드와 함께 사용해서 에러를 throw하는 방식으로도 타입가드를 할 수 있다.
const assert = (v: unknown): v is string => {
return typeof v === 'string'
}
const assert2 = (v: unknown): asserts v is string => {
if (typeof v !== 'string') throw Error()
}
function fn(v: unknown){
if (assert(v)) {
console.log(v) // ✅ 여기서 v의 타입은 string이 된다
}
// ✅ v가 string이 아니라면 Error를 throw한다.
// ✅ v가 string이라면 런타임에서 문제가 없지만, 이후에 v의 타입이 string이 된다
assert2(v)
console.log(v) // 위에서 throw Error가 되지 않으면 v는 string
}
forwardRef
를 사용한 아래 예시 코드를 살펴보자.
import React, { useRef } from 'react';
interface ChildProps {
message: string;
}
const ChildComponent = React.forwardRef<HTMLInputElement, ChildProps>((props, ref) => {
const { message, children } = props;
return (
<div>
<input ref={ref} />
<span>{message}</span>
{children}
</div>
);
});
const ParentComponent = () => {
const inputRef = useRef<HTMLInputElement>(null);
return (
// 🚨 Property 'children' does not exist on type 'IntrinsicAttributes & ChildProps & RefAttributes<HTMLInputElement>'
<ChildComponent message="hello child" ref={inputRef}>
<div>children을 넣어주고 싶어요</div>
</ChildComponent>
);
};
ParentComponent
에서 ChildComponent
를 렌더링할 때, ChildComponent
에 children
prop을 끼워넘기면 에러가 발생한다. 물론 ChildProps
에 children: React.ReactNode
를 명시적으로 넣어서 해결해줄 수도 있지만, forwardRef
의 타입 시그니처가 아래와 같이 되어 있어서 children
을 명시해주지 않아도 children
prop이 자동으로 들어갈 것이라고 생각했다.
function forwardRef<T, P = {}>(render: ForwardRefRenderFunction<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;
interface ForwardRefRenderFunction<T, P = {}> {
(props: PropsWithChildren<P>, ref: ForwardedRef<T>): ReactElement | null;
displayName?: string | undefined;
defaultProps?: never | undefined;
propTypes?: never | undefined;
}
forwardRef
의 인자로 들어가는 render()
함수의 타입인 ForwardRefRenderFunction
의 타입 시그니처에는 (props: PropsWithChildren<P>)
가 있지 않은가? 🤔
이 문제로 몇날을 속썩이다가, 동기가 한 의견을 제시해주었다. forwardRef
의 타입 시그니처 function forwardRef<T, P = {}>
에서 P
에 children
이 없다면, forwardRef
의 리턴 타입인 <PropsWithoutRef<P> & RefAttributes<T>>
에도 children
이 들어가지 않을 것이다!
render()
함수의 인자 타입이 PropsWithChildren<P>
이라는 사실에만 꽂혀서, 리턴 타입을 보지 못했던 것이다! 😵
@typescript-eslint/eslint-plugin
에서 지원하는 rules @typescript-eslint/eslint-plugin
Ref How to use ESLint with TypeScript | Khalil Stemmler
let items = [1, 2, 3];
// Don't force these extra parameters
items.forEach((item, index, array) => console.log(item));
// Should be OK!
items.forEach((item) => console.log(item));
보통의 경우 타입스크립트에서 타입 체크는 초과 속성을 허용하지만(공변), 함수의 인자 타입은 그 반대로 동작한다. (반변) forEach()
메서드를 보면 알 수 있는데, item
, index
, array
3가지의 인자를 모두 사용하지 않더라도 forEach()
함수의 콜백 인자로 넘겨줄 수 있다!
Ref Documentation - Type Compatibility
lockfileVersion
1
: npm v5와 v6에서 사용하는 lockfileVersion2
: npm v7에서 사용하는 lockfileVersion으로, v1 lockfiles과 호환된다.3
: npm v7에서 사용하는 lockfileVersion으로, 이전의 버전들과 호환되지 않는다. node_modules/.package-lock.json
의 숨겨진 lockfile에서 사용되며, npm v6 지원이 더 이상 필요하지 않을 때 npm의 추후 버전에서 사용될 것이다.Ref
RN 테스트코드를 작성할 때에는 OS도 모킹해줘야한다. OS를 모킹하지 않으면 mac 로컬에서는 iOS로 인식하여 통과하지만, CI에서는 iOS가 아니라서 Fail이 될 수 있다.
android studio로 에뮬레이터를 돌릴 때, 갤럭시 기기와 에뮬레이터 사이즈를 비교해보고 싶다면 https://developer.samsung.com/galaxy-emulator-skin/galaxy-s.html 에서 확인할 수 있다. 스킨도 다운받아서 에뮬레이터를 갤럭시처럼 꾸밀 수도 있다.
스크린 리더가 필요할 때 Mac 기준 - 시스템 환경설정 → 손쉬운 사용 → VoiceOver 를 사용하면 된다.
nvm use
- 현재 터미널에서의 node 버전을 변경하는 명령어이다. 새로운 터미널에서도 지정한 node 버전을 유지하려면 nvm alias default
로 지정해야 한다.
uuid는 universally unique identifier의 약자로, ‘범용 고유 식별자’를 의미한다.
jest 에서 실제 라이브러리의 일부만 모킹해줄 수 있다.
// redux mocking
jest.mock("react-redux", () => {
const actualRedux = jest.requireActual("react-redux");
return {
...actualRedux,
useDispatch: jest.fn,
};
});
touchstart
, touchmove
, touchend
이벤트가 발생하였을 때 event.preventDefault()
를 호출하여 해당 event를 cancel하면 이후의 click
이벤트가 발생하지 않는다. (Ref)
safari on iOS에서 체크박스 를 빠르게 클릭 시 좌표가 보정되는 이유는, dblclick
이벤트 핸들러가 설정되어 있기 때문이다. (react 에서는 root element에 모든 이벤트 핸들러를 등록해두기 때문에, 의도치않게 항상 dblclick
이벤트 핸들러가 설정되어 있다.) (Ref)
jest.mock()
의 3번째 인자로 { virtual: true }
를 주면 mocking하려던 모듈이 자바스크립트 상에 존재하지 않아도 모킹할 수 있다. (ex. RN에서 native module)
DOM Tree를 순회할 수 있는 API가 존재한다. (Ref)
인터페이스 설계는 상황이 변경됨(추가, 수정, 삭제)에 따라 좌지우지 되면 안된다. 설계 초기에는 상황을 잘 모르거나, 달라질 수 있는 부분이 많이 존재하기 때문에 다 열어주는 형식으로 만들어서 추후 변경에 취약하지 않게끔 설계해야한다.
storybook은 preview iframe을 입맛대로 다룰 수 있게 html을 사용할 수 있게 지원해준다. .storybook
폴더 아래에 preview-body.html 과 preview-head.html 을 만들어서 적절히 사용할 수 있다.
storybook 에서 addons panel이 사라져 안보이는 경우가 cache로 남아서, controls 등 인터렉티브를 다룰 때 불편해질 수 있는 상황이 있다. 이는 스토리북의 고질적인 문제이며 localStorage.clear()
를 통해 해결할 수 있다. storybook의 preview-body.html에 script로 localStorage.clear() 해주는 코드를 추가하면 이 동작을 자동화할 수 있다.
@storybook/addon-viewport
라이브러리를 통해 기본적인 (갤럭시, 아이폰, 태블릿 기종별) 모바일 view에서 디자인을 확인할 수 있다. 추가적으로 사이즈를 커스텀해서 등록할 수 있는 기능도 포함되어있다.
CRA 환경에서 ESBuild 를 사용하면(craco-esbuild plugin) babel 을 esbuild 로 대체하기 때문에 babel 구성이 사용되지 않는다. issue
질문에 대한 답에 따르면 babel-loader
와 esbuild-loader
를 동시에 사용하는 신박한 방법이 있는데, esbuild
사용의 속도 이점을 누릴 수 없기 때문에 권장하지 않는 방법이라고 한다.
차세대 자바스크립트 번들러로, 문서에 따르면 webpack5 보다 125배 빠르다고 한다. (5^3…? 😲)
Ref https://github.com/evanw/esbuild
모든 브라우저/플랫폼을 하나의 API로 테스트할 수 있는(?!) e2e 테스트 라이브러리다.
ts-node 를 대체할 수 있는 타입스크립트 실행 도구로, esbuild 로 컴파일 하기 때문에 빠르다.
Ref https://github.com/esbuild-kit/tsx
웹팩 내 빌드 속도 향상을 위한 툴이다. ESBuildMinifyPlugin 이 내장 되어있어 TerserPlugin, CSSMinimizerPlugin 등 파일 축소를 위해 직접 사용했던 플러그인들을 대체할 수 있다.
아직 Next를 제대로 써본 않았지만~ 미들웨어를 여러 개 정의할 수 없는 꽤 큰 변화가 있었다고 한다!
Ref https://nextjs.org/blog/next-12-2
Frech stable 첫 번째 버전으로, Deno를 위한 풀스택 웹 프레임워크라고 한다. 클라이언트에 자바스크립트 코드를 보내지 않는다는데, 정체가 뭐지?
CSR은 상당히 무겁고, 몇몇 새로운 프레임워크들은 SSR을 지원한다. 하지만 대부분의 경우 모든 렌더링을 클라이언트에 위임하기 때문에 UX 경험이 좋지 않다.
Fresh는 클라이언트에 자바스크립트를 전달하지 않는다! 대부분의 내용은 서버에서 렌더링이 끝나며, 클라이언트는 아주 작은 양의 상호작용만 맡게 된다. 서버에서는 JIT 방식의 렌더링을 제공하며, Fresh를 이용하여 서버 데이터를 불러오는 코드도 작성할 수 있다. 그리고 클라이언트에서는 Islands라고 불리는 컴포넌트를 사용하는데, 이들은 클라이언트에서 re-hydration된다.
Preact(!)와 JSX를 사용하는 상당히 fancy한 프레임워크이며, 라우팅은 Next.js를 흉내낸, 믹스덩어리같아 보인다.
Ref
Ref https://survey.stackoverflow.co/2022/
노들섬~ 짱 가깝다 😆
너어어어무 덥다! 가 아니고 습하다! 밖에 거의 나가지 않는데도, 잠깐만 나가는 순간 바로 집 가고 싶어진다. 어쩔 수 없는 여름…
오랜만에 멋사 운영진들을 만났다. 다들 어엿한 직장인이 되어 비슷한 고민들 생각들을 나누고 있었다. 그래도 여전히 초딩같은 생각과 말과 웃음포인트들이 남아있어서 즐거웠던 시간 ☺️