December 30, 2022 • ☕️☕️ 11 min read
마지막은 또 다른 시작
Tailwind ClassName을 자동으로 sort해주는 headwind라는 익스텐션이 있다. (prettier-plugin-tailwindcss 와 같은 역할)
Tailwind를 다른 스타일 라이브러리(styled-components, emotion) 등과 함께 사용한다면 CSS Cascading 순위에서 밀려 스타일이 원하는데로 적용되지 않을 수 있다.
important
옵션으로 우선순위를 조정할 수 있다.// tailwind.config.js
module.exports = {
important: true,
};
CIDR(Classless Inter-Domain Routing) 은 직역하면 ‘클래스 없는 도메인 간 라우팅 기법’이란 뜻으로, IPv4 대역을 효율적으로 사용하기 위해 네트워크를 class로 구분하지 않고 접두어를 통해서 구분하는 방법이다.
서브넷은 CIDR로 인해서 부분적으로 나눈 부분 네트워크를 가리킨다. 예를 들어, IP주소가 192.168.10.0/24
일 때, 서브넷 마스크가 /24
이므로 앞에서부터 오는 24비트 이후에 오는 4번째 옥텟을 전부 사용할 수 있다. 하나의 옥텟은 8비트기 때문에 2^8 - 2(예약된 ip 주소: 처음과 마지막), 즉 254개의 호스트에 IP를 할당할 수 있다는 뜻이다.
Ref https://kim-dragon.tistory.com/9
playwrightdms e2e 테스트를 위한 도구로, 하나의 API로 모든 최신 브라우저(크로미움, 파이어폭스, 웹킷)에서 빠르고, 안정적인 자동화를 지원하는 MS에서 만든 자동화 도구다. 여러 페이지에 걸친 시나리오를 테스트할 수 있다.
playwright에서는 새로운 페이지가 열릴 때 순차적으로 테스트를 진행하도록 코드를 작성해야 한다.
// 새로운 페이지를 열어서 해당 페이지에서 테스트를 진행하는 코드
const [newPage] = await Promise.all([
context.waitForEvent("page"), // 1
page.click("a[target=_blank]"), // 2
]);
Ref https://ui.toast.com/posts/ko_20210818
git rebase -i HEAD~<number>
명령어로 ㄴHEAD를 포함해서 number
의 커밋만큼 커밋을 수정할 수 있다.
- `r`: 커밋 이름 변경
- `p`: 커밋 그대로
- `s`, `f`: 해당 커밋을 이전 커밋과 합치는 명령어
- `s` - 커밋 메시지를 모두 합쳐서 새로운 메시지 생성
- `f` - 이전 커밋 메시지만 남김
Module Federation은 리모트 앱이 노출(Expose)한 원격 모듈을, 호스트 앱에서 런타임에 비동기 로딩하여 사용할 수 있는 도구다.
Nexus와 Module Federation을 사용하여 배포할 경우 장단점을 알아보자.
🤔 Module Federation이 번들러들에 의해 충분히 지원되고 있는지?
- Webpack v5, rollup, vite, bit 등 적용 완료
- parcel은 아직 안됨.
- esbuild는 계획조차 안하고 있음을 공지함.
FileReader
객체를 통해 base64로 인코딩 한다.new Image()
생성자 함수로 HTMLImageElement
인스턴스를 생성한다 (Image
의 src
에 base64src
를 할당한다.)
Canvas
엘리먼트를 생성하고, getContext('2d')
로 drawing 할 2d 컨텍스트를 가져와서, drawImage
메서드의 매개변수에 base64 이미지와 리사이징할 사이즈를 입력해서 새로운 이미지를 그려준다.
Base64이미지를 다시 File로 변환하려면 중간에 Uint8Array
생성자를 이용해서 ArrayBuffer
로 변환한 다음, new File()
생성자의 매개변수로 넣어주어 변환해준다.
name
을 넣어주는데, .jpg 같은 확장자가 없으면 서버에서는 content-type
을 모든 바이너리 타입을 포함하는 타입인 octet-stream 으로 받아서 이미지가 아니다고 판단해서 튕겨 내는 이슈가 생길수 있기 때문이다.모노레포에서 프로젝트가 커질수록 테스트, 빌드, 린트등의 작업들이 많아진다. 이때 turborepo를 통해 작업(린트, 빌드 테스트)의 결과를 캐시에 저장해서 다음 작업 때 중복되는 작업은 스킵할 수 있다.
turborepo가 중복 작업을 구별하는 방법은 다음과 같다.
./node_modules/.cache/turbo/78awdk123
)또한 remote caching(vercel 제공)을 통해 로컬 파일시스템 캐싱을 벗어나 원격으로 캐시를 제공하여 ci 혹은 팀원의 로컬 빌드 때 빌드 속도를 향상시킬 수 있다.
자바스크립트 웹뷰에서 native 코드를 호출할 때,
window. webkit
객체로 호출해야 한다. (webkit.messageHandlers[MESSAGE_HANDLER_NAME].postMessage(message)
)// window.injectedObject
webView.addJavascriptInterface(new JsObject(), "injectedObject");
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())");
Next.js와 같은 같은 유니버셜 앱에서 SSR이 진행되는 프로세스는
의 순서로 이루어진다.
서버의 렌더링(Node.js에서 html 코드를 만드는 것)과 클라이언트의 렌더링(브라우저에서 자바스크립트로 DOM을 만드는 것) 모두를 진행해야 하기 때문에, 코드가 Node.js와 브라우저에서 모두 평가되어야함
Next.js에서는 _app.tsx
에 서버/클라이언트 공통의 코드를 작성할 수 있는데, 여기서 클라이언트에만 유효한 코드를 작성하면 에러를 던진다.
// _app.tsx
class Foo extends Event {}
Node.js 환경에서는 브라우저 환경에 있는 Event
가 없기 때문에 에러를 던짐
따라서 이런 경우에는 분기처리가 필요하다.
const MaybeEventOrNot =
typeof window === "undefined" ? function () {} : window.Event;
패키지 번들과 사용자에게 전달되는 번들 파일은 구분해야 한다.
웹애플리케이션에서 lottie 파일을 불러온다고 가정하자.
정적 import로 lottie 파일을 가져오면 사용하지 않아도 lottie 파일이 번들에 포함된다. 반면 동적 import를 사용하면 사용하는 시점에 lottie 파일을 불러온다.
이는 빌드 설정에 따라 다를 수 있다. (서드파티 라이브러리를 다시 번들링하거나 dynamic import를 별도 청크로 분리하지 않는 등의 차이)
import(`../../../assets/lottie/checkbox/${type}.json`)
.then(({ default: lottieData }) => setAnimationData(lottieData))
.catch((err) => console.log(err));
Nest.js의 정적 모듈(기본)에서는 환경변수를 사용할 수 없다. process.env
에 정의된 환경 변수들을 정적으로 불러올 수 없기 때문이다. 이때는 DynamicModule
을 사용한다.
Nest.js의 ConfigModule
은 앱이 동작하는 여러 환경에서 필요한 서로 다른 환경변수를 정의하기 위해 사용한다. 한 곳에 config variables를 모아두는 셈이다. ConfigModule
은 ConfigService
를 노출하여 실행환경마다 적합한 .env
파일을 만들어낸다.
registerAs
를 사용하여 configuration 모듈을 namespace화할 수 있다.
// config/database.config.ts
export default registerAs("database", () => ({
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT || 5432,
}));
registerAs
로 선언한 configuration을 load
로 불러온 후,
import databaseConfig from "./config/database.config";
@Module({
imports: [
ConfigModule.forRoot({
load: [databaseConfig],
}),
],
})
export class AppModule {}
dot notation(점 표기법)으로 값을 불러올 수 있다.
const dbHost = this.configService.get<string>("database.host");
Nest.js를 monorepo로 구성했다면, nest-cli.json에 하위 프로젝트들의 설정을 명시할 수 있다.
이때 workspace project의 타입은 2가지로 설정할 수 있다.
Ref https://docs.nestjs.com/cli/monorepo#workspace-projects
Ref
17버전 이전의 React는 native(브라우저)에서 bubble되지 않는 이벤트(ex. blur
, scroll
)들도 모두 SyntheticEvent
로 감싸서 전파시키고 있었는데, 이로 인해 여러 이슈들이 많이 발생해서 17버전부터는 scroll
이벤트를 부모 element로 전파시키지 않는다. (Ref)
SQL로 Pagination을 구현할 때 offset 방식에서는 많은 행을 읽어들여오고, 이후에 삭제하는 과정을 거치기 때문에 성능상 이슈가 발생할 수 있다.
‘pre-major’ 버전 - major 버전의 정식 출시 전, 즉 1.0.0
버전 미만을 일컫는다.
React.memo()
는 기본적으로 넘겨받은 props에 대한 얕은 비교만 수행한다.
export default React.memo(ResultPanel, fastDeepEqual);
mac os에서 etc/hosts
와 그 사용 예시
127.0.0.1 localhost MytoryMP.local
255.255.255.255 broadcasthost
::1 localhost
127.0.0.1 localhost
새로운 mutation API와 개선된 낙관적 UI 기능, 새로운 devTools, 그리고 concurrent 렌더링에 대한 더 나은 지원을 들고 왔다!
Ref https://swr.vercel.app/blog/swr-v2
사내 구성원 분들 사이에서 제일 핫한 주제는 middleware 관련인 것 같다.
Next.js 13.1부터는 미들웨어에서 응답을 리턴받을 수 있으며, 요청에 헤더를 추가할 수 있다고 한다.
원래 됐다가 안됐다가 다시 되는 것으로 돌아왔나보다. 👀
Ref https://nextjs.org/blog/next-13-1
cypress 테스트 코드를 자동으로 만들어준다! 😲 (아직 Experimental 단계)
RWA(Real World App)에서의 테스트코드를 일부 작성하고, 브라우저 환경에서 테스트하고자 하는 시나리오를 추가적으로 실행하면 이 Command들을 기억하여 유저 액션 기반 테스트 코드를 작성해주는 것 같다.
playwright과 비슷한 기능을 제공하는 것 같은데, 복잡한 환경에서 사람의 손 없이 제대로 동작할지는 모르겠다 🤷♀️
Ref
‘탁월한’ 시니어 개발자가 되기 위해
을 추가적으로 계발해야겠다!
그리고 ‘웹 특화 프론트엔드 엔지니어’의 역량에 더해, ‘제품 특화 프론트엔드 엔지니어’의 역량도 쌓아 프로덕트의 UI/UX에도 관심을 갖고 고객만족을 위해 일해야겠다는 생각을 한다.
엔지니어링 레벨을 빡빡하게 평가하는 걸로 유명한 구글에서는, ‘상위 레벨의 역할을 잘 할 것 같은 사람’을 승진시키는 게 아니라 ‘이미 상위 레벨의 역할을 일정 기간 이상 충분히 수행하고 있었던 사람’의 노고를 인정해주는 차원에서 승진시킨다고 한다
Ref https://steady-study.super.site/frontend-engineer-career-roadmap
작년에도 12월 마지막 두 주는 한번에 묶었는데, 올해도 그렇게 되어버렸넹. 여행을 다녀와서 한주씩 쓸 내용이 없었다.
이렇게 또 올 한 해가 끝났다! 알차고 후회없는 2022년이었다. 다가올 2023년도 블로그 화이팅 🤗