December 23, 2023 • ☕️ 6 min read
올해 마지막 근무일 ✌️
파일을 출력 디렉터리로 내보낼 때 asset/resource
모듈은 기본적으로 [hash][ext][query]
파일명을 사용한다.
webpack 설정에서 [output.assetModuleFilename](https://webpack.kr/configuration/output/#outputassetmodulefilename)
을 설정하여 이 템플릿을 수정할 수 있다.
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "images/[hash][ext][query]",
},
module: {
rules: [
{
test: /\.png/,
type: "asset/resource",
},
],
},
};
Ref https://webpack.kr/guides/asset-modules/#custom-output-filename
proxy
를 쓰지 않았을 때는 클라이언트에서 서버 요청 시 CORS 에러가 발생할 수 있다.
proxy
속성을 설정하면 서버에서 해당 요청을 받아준다.
module.exports = {
//...
devServer: {
proxy: {
"/api": "http://localhost:3000",
},
},
};
Ref
요소가 브라우저 창의 visible 영역에 있지 않다면 요소를 visible 영역으로 스크롤해준다.
비표준 스펙으로, 지원하지 않는 브라우저가 많다
Ref https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded
async~await 구문을 여러 개 테스트할 때, 다음 워닝이 뜰 수 있다
Warning: You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one.
waitFor
키워드를 통해 순차적으로 테스트를 하면 된다.
await waitFor(() => [
screen.getByTestId("my-id-1"),
screen.getByTestId("my-id-2"),
]);
Ref https://github.com/testing-library/react-testing-library/issues/615
toHaveStyle
은 CSS module에서 작동하지 않는다identity-obj-proxy
- css 파일을 import해서 사용하는 사람에게 필요한 library
- jest는 identity-obj-proxy로 객체를 CSS module로 import할 수 있다. 그러면 style 객체 값을 갖고 있는 className들을 그대로 사용할 수 있다
- jest.config.module에 다음과 같이 설정한다
moduleNameMapper: { '.*.(css|scss)$': 'identity-obj-proxy', // ... },
Ref
빠른 시간 내에 수행되어 시간을 측정하기 어려운 경우 Promise를 이용해서 sleep 함수를 구현하여 테스트하는 방법이 있다.
그러나 이렇게 만들어진 sleep 함수의 경우 컨텍스트 스위칭이 발생한다.
sleep 대신 아래처럼 loop를 통해서 cpu 점유를 이어가는 형태로 테스트를 해볼 수 있다.
function delay(ms: number) {
const start = Date.now();
for (;;;) {
if (Date.now() - start > ms) {
return;
}
}
}
Dan Abramov의 오랜만의 블로그 글!
<p>
태그나 <i>
태그처럼 HTML에서 기본으로 제공되는 간편한 태그들은, 개발자들로 하여금 그 뒤의 복잡한 로직을 무시할 수 있게 해준다. 이와 같은 맥락에서 여러 빌트인 툴에서는 text-2xl
또는 font-sans
등의 preset className을 제공하기도 한다.
JSX로 컴포넌트를 작성할 때도 이름을 짓는다.
<Greeting person={alice} />
위 코드는 Greeting
을 그 자체의 의미로 이해하게끔 만들다.
하지만 사람이 이해하는 ‘언어’와 브라우저가 이해하는 ‘언어’는 조금 다르다. 브라우저는 Greeting
과 더불어 alice
를 어떻게 해석해야 하는지도 모를 것이다.
그래서 개발자는 alice
를 정의해줘야 한다.
const alice = {
firstName: "Alice",
birthYear: 1970,
};
그리고 Greeting
도 정의해준다.
function Greeting({ person }) {
return (
<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
Hello, <i>{person.firstName}</i>!
</p>
);
}
이제 다음 코드를 봤을 때,
<Greeting person={alice} />
브라우저는 개발자 머리속 개념인 Greeting
을 이해하진 못하더라도, 화면에 어떻게 보여줘야 할지 알 수 있게 된다.
JSX는 내부적으로 다음과 같이 구성되어 있다.
const originalJSX = <Greeting person={alice} />;
console.log(originalJSX.type); // Greeting
console.log(originalJSX.props); // { firstName: 'Alice', birthYear: 1970 }
브라우저는 JSX를 다음과 같은 과정을 거쳐 해석할 것이다.
function translateForBrowser(originalJSX) {
const { type, props } = originalJSX;
return type(props);
}
translateForBrowser
가 좀 더 복잡한 빌트인 태그들(ex. details
)과 컴포넌트의 조합으로 이루어진 코드들도 해석할 수 있게 만들어보자.
function translateForBrowser(originalJSX) {
if (originalJSX == null || typeof originalJSX !== "object") {
return originalJSX;
}
if (Array.isArray(originalJSX)) {
return originalJSX.map(translateForBrowser);
}
const { type, props } = originalJSX;
if (typeof type === "function") {
const returnedJSX = type(props);
return translateForBrowser(returnedJSX);
} else if (typeof type === "string") {
return {
type,
props: {
...props,
children: translateForBrowser(props.children),
},
};
}
}
그러면 다음과 같이 사람의 관점에서 작성한 JSX 코드는
<ExpandableGreeting person={alice} />
이렇게 바뀔 것이고,
<details>
<Greeting person={alice} />
</details>
최종적으로 다음 코드로 변환될 것이다.
<details>
<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
Hello, <i>Alice</i>!
</p>
</details>
이와 같은 과정을 chain reaction이라 부르고 싶다.
개발자는 데이터와 코드를 함께 작성하고, 브라우저는 더 이상 실행할 코드가 없을 때까지 이를 변환한다.
그런데 이 변환 과정은 어디서 발생하는 걸까?
컴퓨터? 아니면 내 자신?
열린 결말인가? 이대로 글이 끝나버렸다…
Ref https://overreacted.io/a-chain-reaction/
이미지에 있는 글자를 OCR로 따주는 앱
Ref https://textsniper.gumroad.com/l/TXSGR?offer_code=FREEFOR24H