서론사이드 프로젝트에서 카카오톡 공유하기 기능을 구현해야 하는 경우가 생겼는데, 경험을 기록해둡니다.어떤 UI (버튼, 이미지) 를 클릭하면, 카카오톡 API를 통해 카카오톡 앱이 열리고 친구에게 메시지를 공유할 수 있는데요. API를 호출할 때, 특정 정보를 전달하고 이 정보를 메시지 링크에 붙여줍니다.메시지 링크가 열리면 저희 서비스로 이동해서, 서비스에서 이 정보로 특정 액션을 할 수 있습니다. 카카오톡 공유하기 플로우 카카오톡 공유하기 API카카오에 대한 타입정의가 없기 때문에, kakao.d.ts 파일을 만들어 다음과 같은 타입정의를 하였습니다.kakao.d.ts는 tsconfig.json에서 넣어줘서 컴파일러가 타입을 정의할 수 있도록 했습니다. // kakao.d.ts/** ..
전체 글
자기계발을 좋아하는 개발자.반응형
이슈발생사이드 프로젝트 팀에서 사용하는 디자인 시스템을 Tailwind config에 적용해주었습니다.색상도 커스텀한 이름으로 적용해두었고요. Turborepo + Next.js + Tailwind 스타터킷 프로젝트를 사용했기에, Tailwind 유틸함수를 자연스럽게 사용했는데요.Tailwind에서는 텍스트 사이즈 조정을 할 때도, 텍스트 색상을 조정할 때도 유틸리티 클래스 이름이 text-로 시작합니다. Tailwind 유틸함수 cn (내부에 tailwind-merge 및 clsx 사용)을 이용해 아래와 같이 스타일을 입힐 수 있는데요.그러면, text-로 시작한 클래스를 여러개 적용해두면 마지막 클래스만 남게 되는 현상이 발생했습니다. // 커스텀-폰트크기, 커스텀-색상className={cn('..
연결 리스트 편 (Linked List) 1. 러너 기법을 이용하는 패턴2개의 러너 slow와 fast, 2개의 포인터를 이용하여 연결 리스트를 순회하는 기법 빠른 러너(fast)는 느린 러너보다 두 배로 이동합니다. fast가 끝에 도달하면, slow는 중간 노드에 위치하는데요. 이런 특성을 이용해서, 중간 위치를 찾아 낼 수 있습니다. 예시) 1) 값을 비교하기 2) 뒤집기 3) 팰린드롬 찾기 2. node.next != null && node.next.next !== null 인 조건을 체크하기node 다음 노드를 a, node 다음+다음 노드를 b라고 할 때, node와 a, b 를 이용해서, 현재 노드와 다음 노드, 다다음 노드를 Swap 하는 등의 작업을 할 수 있습니다. let node = ..
부동 소수점의 의미영어로 floating point라고 하며, 소수점이 떠다닌다는 의미를 가지고 있습니다.컴퓨터에서 실수를 표현하는 방법으로 소수점의 위치를 고정하지 않아, 사용하는 비트 수 대비 넓은 범위의 숫자를 표현한다는 장점이 있습니다.IEEE 754에서 부동 소수점의 개념을 표준화하였습니다. 고정 소수점과의 차이고정 소수점에서는 정수와 소수 부분의 영역을 나눠서 수를 표현하지만, 부동 소수점에서는 유동적으로 소수점을 이동시킬 수 있습니다.32비트만큼을 사용해서 실수를 표현한다고 가정할 때, 고정 소수점을 부호 1비트, 정수 부분을 8비트, 소수 부분을 23비트로 표현한다고 합시다. (1+8+23 = 32) 그런데, 정수 부분은 8비트만큼만 사용할 수 있어서 -2^8 ~ 2^8 (-256 ..
문제 발생사이드 프로젝트를 진행하고 있는데, 팀 메신저로 Discord를 사용하고 있습니다.Vercel에 Next.js 웹 애플리케이션을 배포하면, 배포 완료되었다는 알림을 Discord 채널에 보내고 싶은데요.마땅한 방법을 찾지 못해, 삽질을 많이 했습니다. Vercel에서 다른 앱과 통합할 수 있는 기능을 제공하는데, Slack과의 연동은 제공해주는 것 같으나 Discord는 없는 것 같더라고요. Integrations에서 -> Browse Market 버튼을 클릭하면, Vercel과 통합할 수 있는 앱들을 보여줍니다. Slack은 있지만 Discord는 없습니다... 계속 구글 검색 + 챗GPT로 정보를 찾다가, Discord Pro Plan의 경우 웹훅을 Account 에서 설정할 ..
객체를 얕은 복사할 때, 전개 연산자(...)를 많이 사용합니다. 객체 전개 연산자 (Object Spread) 라는 단어처럼 연산자 앞에 객체만 가능할 것이라고 생각했는데요. 아니었습니다. 포스팅 제목과 같은 고민을 하게 된 계기는, 객체 전개 연산자를 특이하게 사용한 코드를 이해하려고 했기 때문인데요. 검색 기능을 제공하는 사이트에서, 필터링 기능을 구현할 때 쿼리 스트링 (URL 파라미터)을 많이 사용하는데, 특정 쿼리를 넘기고 싶지 않을 때가 있습니다. // 쿼리스트링 const query = { name: name, age: age, ...(isCategory && { category: category }) // isCategory 값에 따라 category 쿼리 유무를 결정 }; // 쿼리스트..
제네릭 타입을 선언해서, 문자열 리터럴 타입으로 추론하도록 하고 싶은 상황이 발생해서 이것저것 시도하다가 찾은 방법을 정리해봅니다. 세 가지 경우를 예시로 정리해보려고 합니다. 1) 함수에 단일값을 받는 경우 2) 함수에 배열 한 개를 받기 3) 함수에 배열 한 개를 받되, 제네릭 타입을 문자열 타입으로 제한하는 경우 1) 함수에 단일값을 받는 경우 // 단일값 function getValue(param: T) { return param } const v1 = getValue('string') // 'string' 타입 const v2 = getValue('ABC') // 'ABC' 타입 단일값을 제네릭으로 지정한 경우, 문자열 리터럴 타입으로 타입 추론을 잘하고 있습니다. 2) 함수에 배열 한 개를 받..
이터러블 Symbol.iterator를 프로퍼티 키로 사용한 메서드를 구현하거나 프로토타입 체인을 통해 상속받은 객체. - for ... of 문으로 순회할 수 있습니다. - 스프레드 문법, 배열 디스트럭처링 할당을 사용할 수 있습니다. const arr = [1, 2, 3]; // Symbol.iterator 메서드 console.log(Symbol.iterator in arr) // true; // for .. of 문 for (const val of arr) { console.log(val); } // 스프레드 문법 const arr2 = [...arr]; // 배열 구조분해 할당 const [val1, val2] = arr; 이터레이터 이터러블 객체의 Symbol.iterator 메소드를 호출하면..
정리하는 이유 실무에서 사용하거나 알고리즘 테스트를 볼 때, 매번 정규표현식 사용법을 까먹어서 다시 구글링을 하는 경우가 많습니다. 정규표현식 사용법을 찾기 위한 시간적인 비용을 줄이기 위해 자주 사용되는 패턴을 정리해보았습니다. 정규표현식의 정의 일정한 패턴을 가진 문자열의 집합을 표현하기 위해 사용하는 형식 언어 (formal language). 위의 정의는 표현이 어렵게 되어 있는데, 쉽게 말해서 문자열에서 특정 패턴을 찾아서 검색, 치환 등의 작업을 처리할 수 있는 방법이라고 생각하면 될 것 같습니다. 정규표현식과 관련된 자바스크립트 Prototype 메서드 1. RegExp.prototype.xxx - exec : 패턴에 매칭되는 문자들을 배열로 반환, 매칭하지 않으면 null 반환 - test..
두 차례 성능 최적화를 진행하고 측정했던 성능 점수입니다. 지난 이야기... 👇 [Next.js] 페이지 성능 개선하기 2 - 번들 사이즈 개선, Tree Shaking 지난 시간에 측정했던 성능 점수입니다. (모바일 기준) 지난 시간에 성능 개선을 시도했던 흔적 👇 [Next.js] 페이지 성능 개선하기 1 - Next/image, CSS 프리로드 최근 들어 성능 최적화에 대한 고민을 cheolsker.tistory.com 이번 포스팅으로 이번 시리즈(?)를 마무리해볼까 합니다. 배너 이미지(LCP)가 늦게 렌더링 되는 원인은 API 호출 후, 이미지 링크를 받아오기 때문인데요. 이 API를 사전에 호출하면 LCP를 개선해볼 수 있을 것 같습니다. 이 프로젝트는 React-Query를 사용하고 있고, ..
지난 시간에 측정했던 성능 점수입니다. (모바일 기준) 지난 시간에 성능 개선을 시도했던 흔적 👇 [Next.js] 페이지 성능 개선하기 1 - Next/image, CSS 프리로드 최근 들어 성능 최적화에 대한 고민을 많이 해보고 싶어서, 성능 최적화를 해봐야 겠다는 생각이 들었습니다. 예전에 진행했던 프로젝트 중 하나가, Lighthouse 점수가 낮게 나와서 몇 가지 개선을 cheolsker.tistory.com 번들 사이즈를 개선할 필요가 있을 것 같습니다. @next/bundle-analyzer를 설치하고, next.config.js에 적용하였습니다. @next/bundle-analyzer 설치 // 터미널에서 설치 yarn add -D @next/bundle-analyzer 또는 pnpm a..
최근 들어 성능 최적화에 대한 고민을 많이 해보고 싶어서, 성능 최적화를 해봐야 겠다는 생각이 들었습니다. 예전에 진행했던 프로젝트 중 하나가, Lighthouse 점수가 낮게 나와서 몇 가지 개선을 통해 성능 개선을 하려고 합니다. 이 프로젝트는 Next 12 버전을 이용하여 개발되었고, HTTP/2 프로토콜을 사용하고 있습니다. 앱 서비스이기 때문에, Lighthouse에서 모바일 기준으로 성능 검사를 진행하였습니다. Lighthouse를 이용한 성능 점수 확인 이 페이지는 이미지가 굉장히 많습니다. 상단에 배너 슬라이드를 통해 여러 개의 이미지가 보여지고, 뷰포트 아래에도 섹션별로 많은 이미지를 로드합니다. LCP도 무려 15.8초가 걸립니다.. 일단은 이미지 로드에 대한 개선이 확실히 필요할 것 ..
웹 스토리지 유틸 함수에 대한 테스트 코드를 작성하다가 조금 헤매고 난 후에 해결해서 그 과정을 글로 남기고자 합니다. 스토리지 유틸 함수를 만든 이유 스토리지 API를 이용해서 바로 특정 값을 가져올 수도 있을 텐데요. 그럼에도 불구하고, 유틸 함수를 별도로 만드는 이유는 스토리지가 문자열 값만 저장하기 때문입니다. 특히 스토리지에 객체를 JSON 형태의 문자열로 저장하는 것이 유용할 텐데요. 객체를 바로 스토리지에 저장하게 되면 [object Object] 형태의 문자열로 변환되어 저장되기 때문에 유틸 함수에서 JSON 문자열로 변환시켜서 스토리지에 저장하려는 것입니다. (toString의 동작방식 때문) // 스토리지 유틸 함수 예시 export const getSessionStorageItem =..
문제 발생 웹 서비스를 개발하던 중에, 다음과 같이 특정 API를 호출하고 실패했을 때 window.alert로 사용자에게 오류 메시지를 보여주는 기능을 구현했습니다. 버튼을 클릭하면 로딩이 보이면서, API 호출이 마무리될 때까지 기다렸다가 성공하면 다음 페이지로 이동하고, 실패하면 오류 메시지를 보이는 형태입니다. 위의 기능과 관련된 컴포넌트에 대한 테스트 코드를 작성하고 있던 중이었습니다. API를 모킹해서 실패하도록 처리한 후, 오류 메시지를 보이는 것. 즉, window.alert가 실행되었는 지 검증하는 중이었는데요. 다음과 같은 오류가 발생했습니다. Jest의 테스트 환경 (testEnviroment)는 jest-environment-jsdom 으로 셋팅되어 있는데요. JSDOM 환경에는 w..
컴포넌트 구현을 안 해본 FE 개발자는 없을 것입니다. 개발자마다 각자의 기준에 의해 컴포넌트 단위를 결정하고 컴포넌트의 형태, 기능을 정의합니다. 컴포넌트 구현 방법은 명확한 정답은 없다고 생각합니다. - 컴포넌트마다도 형태, 기능이 다르기도 하고, - 어느 곳에서 사용하는 지, - 개발 기한이 얼마나 주어졌는지에 따라 컴포넌트 설계에 대한 고민의 시간이 달라지기 때문입니다. 다만, 컴포넌트를 잘 구현해놓으면 개발 생산성이 높아지기 때문에 많은 고민이 필요한 것은 사실인 것 같습니다. 저는 주로 신규 프로젝트에 많이 참여했었고, 프로젝트들 별로 디자인이 달랐습니다. 그래서 아토믹 디자인 패턴을 사용하지 않았고, 회사 내에 디자인 시스템도 만들 필요가 없었는데요. 이런 환경의 기준 (소규모 프로젝트) 으..
Storybook 이란?스토리북(Storybook)은 컴포넌트의 다양한 경우를 정리할 수 있도록 도와주는 시각화 도구(tool)입니다. 예를 들어, 버튼 컴포넌트가 있다고 하면 상태(데이터)에 따라서 UI나 액션이 달라질 수 있습니다.variant 값이 primary이면 일반 버튼, dashed이면 점선이 있는 버튼으로 버튼 UI를 표현할 수 있습니다. 스토리북과 같은 도구 없이도 컴포넌트를 개발할 수 있지만, 점점 늘어나는 컴포넌트들을 한 눈에 정리하는 것은 쉽지 않습니다.스토리북은 컴포넌트들을 시각적으로 정리할 수 있게 도와줄 뿐만 아니라, 컴포넌트의 구현 코드를 문서화해줍니다. 디자이너와 협업할 때 컴포넌트의 UI가 잘 구현되었는지 피드백을 받을 수 있으며,다른 개발자와 협업할 때는 컴포넌트를 어떻..
이슈 발생 Storybook에서 SVG 아이콘을 사용하는 컴포넌트로 스토리를 만들고 있었는데요. 갑자기 위와 같은 오류가 발생했습니다. Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. 구글링도 해보고, Github Issue를 여러 개 살펴본 뒤에 file-loader 관련 이슈라는 것을 알게 되었습니다. Storybook은 Webpack을 사용하고 있고 기본적으로 file-loader가 사용되고 있는데, SVG 파일을 import하는 과정에서 file-loader가 객체 형태로 변환한 것으로 보입니다. File-lo..
간단한 웹 페이지 기능 소개 쇼핑몰 기능 중 하나인 장바구니 기능을 구현한 웹 페이지입니다. 장바구니에 등록된 상품 중에서 결제할 상품을 선택하고, 상품 갯수에 따라 최종 금액을 유저에게 보여줍니다. 리액트 컴포넌트 설명 컴포넌트 2개가 있습니다. 1. 상품 컴포넌트 : 장바구니 상품 정보를 보여주는 컴포넌트 2. 상품 리스트 컴포넌트 : 상품 컴포넌트들을 보여주고, 필요한 비즈니스 로직을 제공합니다. 2번 컴포넌트는 컨테이너 - 프레젠테이션 패턴의 컨테이너라고도 볼 수 있을 텐데요. 컨테이너를 별도로 구별하려면, ~ 컨테이너라는 코드컨벤션이 생기고 별도의 디렉토리 폴더를 관리해줘야 하는데 개인적인 생각으로는 코드의 양이 늘어나고, 비즈니스 로직을 가지고 있는 컴포넌트들을 컨테이너로 엄격하게 구분하기 어..
Github이나 Gitlab 등의 원격저장소에 git push 하거나 git fetch or git pull하는 경우가 많습니다. 그런데 로컬저장소의 브랜치가 원격저장소의 브랜치를 추적하지 않으면 위의 명령어를 사용할 수 없습니다. git push 원격저장소명 브랜치명 형태로 사용해야 합니다. 조금 귀찮을 수도 있습니다. 그래서 로컬 브랜치가 원격저장소 브랜치를 추적할 수 있는 방법을 찾아보았습니다. 편의상 로컬저장소의 브랜치를 로컬 브랜치, 원격저장소의 브랜치를 원격 브랜치로 부르겠습니다. git clone 시 git clone을 이용하면 main브랜치는 자동으로 원격저장소의 main브랜치를 추적합니다. 원격 브랜치를 추적하는 로컬 브랜치를 생성할 경우 git fetch를 통해서 원격 브랜치를 가져왔다..
BFS에 대한 소개 BFS는 Breadh-First-Search의 약자로 너비우선탐색이라고 합니다. 그래프가 주어졌을 때, 노드(Vertex)를 가까운 노드부터 탐색하는 알고리즘입니다. BFS 알고리즘을 구현할 때는 큐와 배열을 사용합니다. 큐는 현재 노드로부터 인접한 노드들을 담아주는 역할을 해줍니다. 배열은 현재 노드를 방문했는지 체크하는 역할로 사용됩니다. 가까운 노드(인접 노드)부터 탐색하기 때문에 A노드에서 B노드까지의 최단거리를 구할 수 있습니다. DFS 알고리즘과 마찬가지로 그래프, 현재노드, 방문여부 정보를 넘겨줌으로써 알고리즘을 구현할 수 있습니다. 알고리즘 1. 시작 노드를 큐에 삽입합니다. 2. 방문하지 않았다면 방문했다고 체크합니다. 3. 큐에서 노드를 제거한 후, 해당 노드의 모든..
반응형