May 14, 2022 • ☕️☕️☕️ 16 min read
양평같은 방 아니고 진짜 양평
종속 관계
를 바탕으로 프로젝트 결과물이 나오기까지의 단계를 여러 계층으로 나눠 시각적으로 분류한 것이다. 즉, 프로젝트를 진행하기 위해(또는 결과를 위해) 필요한 정보들을 파악할 수 있도록 하는 딜리버러블 지향(결과물을 도출할 수 있도록 하는) 분업 구조를 의미한다.await
함수의 에러만!ErrorBoundary는 await
하지 않은 비동기 함수에서의 에러는 감지하지 못한다. 추가로 아래 2가지 경우에서도 에러를 감지하지 못한다.
setTimeout
혹은 requestAnimationFrame
콜백)await
하지 않고 실행한 비동기 함수는 리액트의 render와 commit phase 밖에서 동작하기 때문이다. 우회적으로 await
하지 않은 비동기 함수의 catch
문에서 에러를 던지고 싶다면, hook 내부에서 에러를 던지는 방법으로 작성하는 방식이 있다.
setState(() => {
throw new Error("hi");
});
이를 재사용 가능한 hook으로 만들면 다음과 같다.
const useAsyncError = () => {
const [_, setError] = React.useState();
return React.useCallback(
(e) => {
setError(() => {
throw e;
});
},
[setError]
);
};
React의 render vs commit phase
- render phase에서는 JSX 코드를 JavaScript 표현식으로 바꿔 Virtual DOM을 생성한다.
- commit phase에서는 위 표현식을 실제 DOM에 반영한다. 👩🏫 이 모든 과정을 통틀어 재조정(reconciliation) 이라고 한다.
Ref https://github.com/facebook/react/issues/14981#issuecomment-468452682 https://medium.com/trabe/catching-asynchronous-errors-in-react-using-error-boundaries-5e8a5fd7b971 https://dev.to/thee_divide/reconciliation-react-rendering-phases-56g2
기본적으로 노드 서버는 자바스크립트로 요청이 올 때, v8 엔진이 싱글쓰레드로 읽으므로 여러 프로세스를 동작하도록 해야한다. 만약 이게 싫다면 성능을 낮추고 작은 서버로 여러 인스턴스를 띄우는 것도 방법이다.
pm2의 클러스터 모드를 활용해 여러 노드 프로세스를 띄울 수 있다. 클러스터 모드를 사용하면, 서버 안에 CPU가 처리할 수 있는 프로세스의 개수 안에서 프로세스 당 하나씩 노드 서버를 띄울 수 있다.
implicit props는 @types/react
에서 자동으로 추가되는 암시적인 props를 가리킨다.
<Input key=’first’ />
explicit props는 명시적으로 props interface에 작성되어 있는 props를 의미한다.
interface InputProps { type: string; }
const Input: React.FC<InputProps> = ({ type }) => <input type={type} />
<Input type="search" />
빌드되지 않은 형태의 TypeScript 파일을 직접 임포트해서 사용할 수 있다.
Nextjs는 기본적으로 외부 패키지를 트랜스파일하지 않는다. next-transpile-modules
는 Nextjs에서 지원하는 모든 확장자의 트랜스파일을 지원한다. (.js
.jsx
.ts
.tsx
.mjs
.css
.scss
.sass
)
모노레포 환경에서 다른 워크스페이스에 있는 컴포넌트를 사전 트랜스파일링 없이 바로 가져오고 싶을 때 유용하다.
// shared-ui/components/Button.js
function Button(props) {
return <button type="button">{props.children}</button>;
}
export default Button;
// next.config.js
const withTM = require("next-transpile-modules")(["shared-ui"]);
module.exports = withTM();
Ref https://www.npmjs.com/package/next-transpile-modules
npm, yarn과 같은 패키지 매니저 중 하나다.
평탄하지 않은 node_modules
를 생성하기 때문에 오직 직접적인 의존성을 가진 패키지만 사용된다. (자동완성도 실제로 설치한 패키지에서만 동작한다)
모노레포 프로젝트에 적합하며, 빠르다는 장점이 있다.
usb를 꽂으면 바로 연결되는 것처럼, “꽂으면 실행된다”는 의미로 사용한다. 하드웨어에서는 사용자가 별다른 조작이나 설정하지 않고 바로 연결됨을 의미한다.
모노레포에서 이 개념은 상위 레포에서 필요한 모듈을 버전별로 모두 가지고 있고, 하위 레포에서 모듈 버전 정보만 소유한다는 의미를 가진다.
하위 레포에서 해당 모듈을 사용할 때 가지고 있는 버전 정보를 기반으로 상위 레포에서 필요한 모듈을 가져오는 것을 의미한다.
MR 때 하지 않아도 되는 CI 작업이라면 MR 머지 후 release 브랜치에 커밋이 생긴 시점으로 해결하는 방법도 있다.
node 13버전 이하에서는 optional chaining, nullish 문법을 쓸 수 없다.
디자인 토큰 - 브랜드 색상, 간격과 같은 스타일 변수를 말하는 용어로 쓰인다.
docusaurus - 예쁜 다큐먼트 사이트를 뚝딱 만들 수 있게 도와준다.
웹뷰를 띄울 때 기존 웹뷰를 남기려면 query param에 shouldKeepPresentedView=true
옵션을 주면 된다.
Logical nullish assignment (x ??= y)
- x
가 nullish (null
또는 undefined
일 때만) 값을 할당한다. (Ref)
sFTP - ssh 방식을 사용하여 안전하게 암호화된 구간에서 FTP(파일 전송)기능을 사용할 수 있다.
Location.hash
- #
뒤에 나오는 식별자를 value로 하는 값
webviewWillAppear
인터페이스는 웹뷰가 새롭게 띄워졌을 때가 아닌 focus out 됐다가 focus in 될 때 실행된다.
스냅샷 테스팅(Snapshot Testing) - 어떤 기능의 예상 결과를 미리 정확히 포착해두고 실제 결과에 비교하는 테스트 방식
타입스크립트에서 객체에 readonly
가 붙어도 객체의 필드는 수정이 가능하다.
File
객체의 type
필드 - MIME 타입을 반환한다. (Ref)
pps, ppsx 파일 확장자 - MS powerpoint XML을 가리킨다. (Ref)
LINE에서 Turborepo로 모노레포를 개발한 경험을 공유한 글이다.
Turborepo의 주요 미션은 모노레포 환경에서 개발자가 조금 더 쉽고 빠르게 개발할 수 있도록 빌드 도구를 제공하는 것입니다. 고급 빌드 시스템을 구축하는 복잡한 과정을 Turborepo가 대신해 주기 때문에 개발자는 복잡한 설정과 스크립트에 신경 쓰는 대신 개발에 더 집중할 수 있습니다.
역시 개발자들은 귀찮음을 해결하기 위해 뭔가를 또 만든다..! 불편하면 불편한 대로 사는 나와는 참 다르다.
Turborepo의 기본 원칙은 한 번 작업을 수행하며 수행한 계산은 이후 다시 수행하지 않는 것이다. 따라서 두 번째 실행할 때는 이전에 계산한 작업은 건너뛰고 이전에 캐싱해 놓은 로그를 다시 보여준다.
마지막에 Performance가 향상된 모습을 보여주는데, 탐난다..! :amaze:
Ref https://engineering.linecorp.com/ko/blog/monorepo-with-turborepo/
구글에서 공개했다. 흑백이고 가변 글꼴이어서 색상이나 굵기 설정도 가능하다.
그리고 무엇보다 귀엽다!
Ref https://developers.googleblog.com/2022/04/what-is-black-and-white-and-read-all.html
리액트에서 가장 기본이면서도 항상 골칫덩어리인 문제!
😜 TL;DR
리액트는 컴포넌트를 다음과 같은 상황일 경우 (재)렌더링한다.
아래 예시가 특히 흥미로웠다!
default function App() {
return (
<Parent lastChild={<ChildC />}>
<ChildB />
</Parent>
);
}
function Parent({ children, lastChild }) {
return (
<div className="parent">
<ChildA />
{children}
{lastChild}
</div>
);
}
function ChildA() {
return <div className="childA"></div>;
}
function ChildB() {
return <div className="childB"></div>;
}
function ChildC() {
return <div className="childC"></div>;
}
만약 Parent
의 업데이트가 예정되어 있다면, 어떤 컴포넌트가 리렌더링 될까?
당연히 Parent
자체는 업데이트를 예약한 컴포넌트이기 때문에 리액트에 의해 리렌더링 될 것이다. 하지만 모든 자식 컴포넌트 ChildA
, ChildB
, ChildC
도 리렌더링 될까?
🤔🤔🤔…
답은 ChildA
만 리렌더링된다!
ChildA
와 달리 ChildB
와 ChildC
는 리렌더링 되지 않는다. 그 이유는 ChildB
와 ChildC
가 렌더링 제외 기준을 충족했기 때문에 리액트가 렌더링을 건너뛰었기 때문이다.
리액트의 렌더링 제외 기준을 알기 위해 이 글에서는 소스 코드까지 살펴보고 있다. 😵
코드 내에서 리액트의 렌더링 제외 로직 관련 코드는 다음과 같다.
// 보류 중인 업데이트 또는 context가 없습니다. 여기서 렌더링을 제외합니다.
didReceiveUpdate = false;
return attemptEarlyBailoutIfNoScheduledUpdate(
current,
workInProgress,
renderLanes
);
이 라인에 도달하기 위해서는 다음 조건이 충족되어야 한다.
current !== null
oldProps === newProps
hasLegacyContextChanged() === false
hasScheduledUpdateOrContext === false
해석하면 대략 다음과 같다.
context
값 중 변경된 것이 없다.처음 살펴보았던 예시에서,
function Parent() {
return (
<div>
<Child />
</div>
);
}
Parent
에서 반환된 <Child />
는 Babel에 의해 React.createElement(Child, null)
로 컴파일되고 { type: Child, props: {} }
과 같은 형태의 ReactElement
가 생성된다.
props
는 자바스크립트 객체이기 때문에 다시 생성될 때마다 참조가 변경된다. 기본적으로 React는 ===
를 사용하여 이전 props
와 현재 props
를 비교한다. 따라서, props
는 리렌더링 되면 다른 값으로 간주된다. 그렇기 때문에 Child
는 props
의 일부로 Parent
로부터 아무것도 받지 않지만, Parent
가 리렌더링 될 때마다 여전히 리렌더링 된다. React.createElement
는 Child
를 위해 호출되고 새로운 props
객체를 만든다.
하지만 만약 Child
를 Parent
의 props
로 전달할 수 있다면 어떻게 될까?
function App() {
return (
<Parent>
<Child />
</Parent>
);
}
function Parent({ children }) {
return <div>{children}</div>;
}
리액트에 의해 Parent
가 렌더링될 때 Child
에 대한 React.createElement
함수가 호출되지 않는다. 따라서 Child
의 새로운 props
가 생성되지 않고, 이는 위에서 언급한 네 가지 렌더링 제외 기준을 모두 충족시킨다.
이것이 처음 예시에서 Parent
가 업데이트를 예약할 때마다 ChildA
만 리렌더링 되었던 이유다.
function Parent({ children, lastChild }) {
return (
<div className="parent">
<ChildA /> // ChildA만 리렌더링된다.
{children} // 리렌더링 제외
{lastChild} // 리렌더링 제외
</div>
);
}
조금 복잡한 내용이다..!!
두고두고 다시 읽어봐야겠다.
Ref https://velog.io/@eunbinn/when-does-react-render-your-component
Node.js용 가상환경 같은 툴로, 프로젝트 구성원끼리 노드 버전 맞출 용도라면 nvm 대신 사용할 수 있다.
이전에도 두어 번 읽어보았던 글인데, 볼 때마다 신선하고 정말 재미있다. 철학적 관점에서 프로그래밍 언어를 풀어내다니, 정말 간지…
Ref https://medium.com/@limsungmook/자바스크립트는-왜-프로토타입을-선택했을까-997f985adb42
아나콘다가 발표한 새로운 언어다. 이름이..!! 정말 끔찍한 혼종
파이스크립트는 사용자가 파이썬과 표준 HTML을 결합하여 브라우저에서 풍부한 파이썬 애플리케이션을 만들 수 있도록 지원하는 프레임워크다. 브라우저 내 단일-포함(single-include) 방식으로 HTML 페이지에서 자바스크립트만큼 쉽게 파이썬 스크립트를 실행할 수 있도록 한다.
파이스크립트를 사용한 예제가 올라왔다.
Ref https://www.ciokorea.com/news/234899
혼란스러운 TS 로그를 사람이 보기 좋은 형태로 보여주는 VSCode 익스텐션이다.
라떼는… 에러 로그도 불친절했다 이말이야
Ref https://github.com/mattpocock/ts-error-translator
한 마디가 아니고 투머치 주의…
Ref https://www.facebook.com/xguru/posts/10227448129370092
nx 를 만든 Nrwl에서 lerna를 이어서 관리한다고 한다.
Ref https://github.com/lerna/lerna/issues/3121
그동안 함수형 프로그래밍에서 종종 보았던 compose()
, pipe()
등의 함수를 만들면서 원리와 flow에 대해 설명한다.
합성의 진정한 아름다움은 코드가 아니라 코드가 우리를 변화시키는데 있습니다. 코드에 대한 새로운 시각을 제공하기 때문입니다.
뭔가 굉장한 세계가 열린 것처럼..!
하지만 처음 접했을 때의 그 새로운 시야의 신비로움(?)은 잊지 못한다. 아직도 혼자 코드 쓰라 하면 못하지만.
Ref https://junghan92.medium.com/번역-자바스크립트-함수-합성-뭐가-그렇게-대단할까-5a2664b7c2b8
벌써 stage3..!
Ref https://github.com/tc39/proposal-decorators
오오.. 눈치채지 못했는데 이번주는 상당히 정보공유글이 많았네. 지난주는 씨가 말랐었는데… 정리하느라 힘들었다. 사실 평일 동안 집중도 잘 안 되고 😬
이번주는 개발을 많이 하지 못한 것 같다. 마크업 정도 하고, 코드리뷰 하고, 그동안 해왔던 프로젝트 장애 대응 (프론트 문제는 아니었지만..!)하고… 사아알짝 지루했던 주였다.
금요일엔 팀 전체 워크샵을 다녀왔다! 우형 오피스의 자랑인 <양평같은 방> 아니고 진짜 양평으로! ㅋㅋㅋ 맛있는 해물 칼국수도 먹고, 강릉이 아닌 양평(서종)의 테라로사에서 존맛탱이었던 까눌레도 먹었다. 입사 4개월 만에 드디어 만난 팀원분들이 엄청 반겨주셔서 행복했당 🥳
빨리 깁스 풀고 싶다 🥺