2024년 10월 08일
vscode에서 검색 후 방향키를 누르면 검색어에 대한 일괄 변경 기능이 지원된다. 작업 중 .hideOverlay 함수에 대한 일괄 변경을 처리하려는데, a.hideOverlay, b.hideOverlay… 와 같이 앞에 붙어있는 문자가 모두 다른 상황에서는 단순 검색으로는 변경이 불가능하여 정규식 검색 후 그룹화하여 일괄 변경 처리를 진행했다. 우측위에 .* 아이콘을 클릭하여 정규식 검색을 활성화 후 검색어 및 수정단어에 정규식 처리하여 완료 // 검색어 : (this\.[a-zA-Z]*)\.hideOverlay\(\); // this부터 hideOverlay 앞의 값까지 모두 그룹화 지정 this.aaa.hideOverlay(); this.bbb.hideOverlay(); // 수정단어 : if($1) { $1.hideOverlay(); } // 일괄 변경된 결과 if(this.aaa) { this.aaa.hideOverlay(); }; if(this.bbb) { this.bbb.hideOverlay(); };
2024년 03월 09일
lerna를 사용한 간단한 모노레포 설정 1. lerna 환경 구성 npx lerna init 2. lerna.json 수정 yarn workspace 기반으로 작업하기 위해 useWorkspaces 사용 { "version": "independent", "npmClient": "yarn", "useWorkspaces": true, "packages": [ "packages/*" ] } 3. package.json에 workspaces 추가 "workspaces": [ "packages/*" ] 4. 각 패키지 생성 lerna create [PACKAGE_NAME] 5. 공통 패키지 설치 yarn add eslint prettier typescript --dev --ignore-workspace-root-check yarn add dayjs --ignore-workspace-root-check 개별 패키지에 설치방식 yarn workspace frontend add dayjs 6. 각 workspace에 패키지 설치 npx lerna bootstrap 7. workspace 명령어 실행 lerna run dev
2022년 11월 20일
React Native에서 텍스트 에디터로 제작된 공지사항을 그대로 보여주기 위해 html을 렌더링하려고한다. 시행착오 처음에는 react-native-htmlview를 사용하여 html을 출력했다. yarn add react-native-htmlview import HTMLView from 'react-native-htmlview'; ... <StyledContentWrap> <HTMLView value={body} /> </StyledContentWrap> const StyledContentWrap = styled(View)` h1 { font-size: xxx; } h2 { font-size: xxx; } ` html 태그에 맞는 css를 보여주기 위해 styled-components에 태그에 맞는 스타일링을 적용했는데, 여기서 문제가 발생했다. Node of type rule not supported as an inline style StyledNativeComponent react-native에서는 html 태그를 지원하지 않기 때문에 styledComponent 영역에서 작성이 불가능하다고 warning이 계속 뜨는 것이였다. 사용은 가능하지만 다른 방법으로 변경하기로 했다. react-native-render-html npm trends에서도 react-native-htmlview과는 엄청난 차이를 보이는 react-native-render-html를 사용하기로 했다. yarn add react-native-render-html import HTML from 'react-native-render-html'; import { View, useWindowDimensions } from "react-native"; ... const contentWidth = useWindowDimensions().width; ... <View> <HTML source= tagsStyles={htmlTagsStyles} contentWidth={contentWidth} /> </View> contentWidth를 주지 않으면 warn이 뜬다. 라이브러리 Readme를 보니 useWindowDimensions로 width를 가져와 채워주는 코드가 있어서 그대로 가져왔다. 스타일은 아래와 같이 StyleSheet처럼 스타일링하여 tagsStyles로 넣어주면...
2022년 10월 25일
Level3 문제 이번 추석에도 시스템 장애가 없는 명절을 보내고 싶은 어피치는 서버를 증설해야 할지 고민이다. 장애 대비용 서버 증설 여부를 결정하기 위해 작년 추석 기간인 9월 15일 로그 데이터를 분석한 후 초당 최대 처리량을 계산해보기로 했다. 초당 최대 처리량은 요청의 응답 완료 여부에 관계없이 임의 시간부터 1초(=1,000밀리초)간 처리하는 요청의 최대 개수를 의미한다. 해결방법 임의의 한 구간을 선택해서 1s안에 몇 개의 타임라인이 지나가는지 구하는 문제이다. 임의라는게 가장 헷갈리는 부분인데, 단순하게 생각해보면 이미 종료시점에 맞춰서 데이터가 정렬되어서 내려온다. 즉, 데이터를 반복문 돌렸을 때 다음 데이터의 종료시점은 무조건 나보다 뒤에 있다. 그렇다면 시작 시간이 현재 데이터 구간 안에 다음 데이터가 포함되는 지를 확인하면 되고 그게 1s가 된다. 이게 설명을 하려니까 어려운데, 소스코드 내에서 설명하는 편이 편할 것 같다. 소스코드 시작, 종료, 작업시간을 구하는데 split으로 작성하기에는 코드가 길어져서 정규식으로 진행했다. 종료시간을 기준으로 반복문을 돌리며 그 다음 index의 데이터들의 시작시간을 확인한다. 이때, 포함해야하는 기준이 1000ms이기에 해당 값을 빼서 종료시간보다 이전이였는지 체크한다. 일치한다면 개수를 체크한다. 해당...
2022년 10월 25일
Level3 문제 2n명의 사원들을 두 팀으로 나누고 사원마다 무작위 자연수를 받았을 때, B팀이 승리하는 횟수 해결방법 큰 수가 이기는 규칙이기에 내림차순으로 정렬하는게 효율적이다. 게임으로 단순하게 생각하면 A팀의 가장 큰 숫자를 이기지 못하는 상황일 때, B팀의 가장 작은 숫자를 버리는 방향으로 진행하면 된다. ex) A팀 [11, 9, 8, 7], B팀 [10, 9, 8, 7]이라면 B팀에서 11을 이길 수 있는 카드가 없으니까 가장 작은 수를 버리면서 B팀의 가장 큰 수를 유지할 수 있다. 해당 방식으로 tail이라는 변수를 놓고 B팀이 뒤에서 카드를 몇장 버렸는 지 체크하면서 값을 비교한다. 소스코드 function solution(A, B) { const sortA = A.sort((a, b) => b - a); const sortB = B.sort((a, b) => b - a); let tail = 0; let count = 0; sortA.forEach((a, index) => { if (a >= sortB[index - tail]) { tail++; return; } count++; }); return count; } solution([6, 8, 7, 9], [7, 9, 8, 6]); solution([5, 1, 3, 7], [2, 2, 6,...
2022년 10월 02일
검색에서 사용하기 위한 sitemap을 등록할 때 jekyll-sitemap 플러그인을 사용하여 생성된 xml파일을 연결했었다. ( Jekyll Google Search Console 연동하기 ) 최근 블로그를 다시 정리하면서 Analytics를 보고있는데, 유효하지 않은 페이지들이 잡혀서 sitemap.xml 파일을 확인해보았고 jekyll-sitemap에서 post 뿐만 아닌 layout과 같은 불필요한 디렉토리도 사이트맵에 추가되고 있었다. Sitemap 파일 jekyll-sitemap Path 제외 jekyll-sitemap 문서에서는 특정 path를 제외하고 싶다면 아래와 같이 config의 defaults에 sitemap: false를 추가하라고 안내하고 있다. defaults: - scope: path: "author" values: sitemap: false 다만 내 블로그에서는 글을 분리하기 위해 tag, category와 같은 collections을 추가한게 문제인지 category를 셋팅하면 _categories + category path가 둘다 사라지고 pagination number가 path에 추가되는 등 제대로 동작하지 않아서 직접 제작하기로 했따. Sitemap 파일 만들기 Sitemap을 직접 생성하는건 생각보다 어렵지 않았다. 리스트를 그저 sitemap 형식에 맞게 출력해주면 될 뿐이다. 초기 셋팅 !!모든 코드 설명에서 \는 지워주세요. md 파일에서도 렌더링돼서 어쩔 수 없네요. root에 sitemap 파일, posts를 형식에 맞게 출력할 레이아웃 파일을 만들었다. /sitemap.xml /_includes /sitemap_item.xml sitemap.xml은 아래와 같이 기본 틀을...
2022년 10월 01일
만약 특정 날짜에 동작해야하는 기능이라면 앱은 최소 몇일 전까지 배포되어야 유저가 사용할 수 있을까? 앱 스토어에 심사를 거치고 유저에게 도달하기까지 얼마나 걸릴 지 궁금하였다. 유저가 업데이트 버전에 도달하기까지는 심사 / 점진적 배포(선택사항) / 앱 업데이트를 거쳐야한다. 가장 먼저 점진적 배포에 대해서 설명하고 심사기간 스토어 정책에 위반되는 사항, 보안적인 이슈 등의 여부를 확인한다. 구글 스토어 약 2~3시간 정도로 심사가 끝나기에 크게 의미가 없다. 앱 스토어 기존에는 3~4일 정도로 심사기간이 오래 걸렸으나, 최근에는 1~2일만에 처리되고 있다. 긴급심사를 통해 심사기간을 줄일 수 있으나 현재 심사기간이 짧아서 의미가 없을 수 있다. 점진적 배포 구글 스토어 / 앱 스토어에서는 기본적으로 점진적(단계적) 배포라는 기능을 제공하고 있다. 특정 기간동안 일정 비율에게만 새로운 버전의 업데이트를 제공하도록 설정하는 기능이며, 자동 업데이트를 활성화한 유저에게만 적용된다. ( 만일 해당 기능을 설정하지 않았다면 모든 유저가 업데이트가 가능해진다. ) 해당 기능은 일정 유저에게만 신규 버전을 오픈함으로써 앱 크래시와 같은 치명적인 버그 발생 시 최소한의 유저만 경험하고 대응 가능하도록 만들어준다. 구글 스토어와 앱 스토어의...
2022년 05월 08일
Puppeteer를 사용하는 nodejs를 linux 서버에 띄었는데 작업하니 다음과 같은 오류가 났다. Error: Failed to launch the browser process! /home/ubuntu/slack-bot-groupware/node_modules/puppeteer/.local-chromium/linux-938248/chrome-linux/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory 해결방법 아래 명령어를 실행하여 추가 패키지를 설치한다. sudo apt-get install libgtk2.0-0 libgtk-3-0 libnotify-dev sudo apt-get install libgconf-2-4 libnss3 libxss1
2022년 05월 07일
REMOTE HOST IDENTIFICATION HAS CHANGED! 인스턴스 사양을 늘리기 위해 스냅샷으로 새로운 서버를 생성, 다시 접근하는데 다음과 같은 오류가 났다. 현재 PC에서 SSH로 접근하는 서버의 인증 정보를 가지고 있는데, 동일한 IP 서버 인증키가 달라졌기 때문에 경고를 주는 것. 해결방법 해당 서버의 키만 제거하려다가 그냥.. 다 지워버렸다. rm -r /var/root/.ssh/known_hos
2022년 05월 07일
출퇴근 페이지를 개선하면서 도메인을 변경했고, 서버를 이전하기로 했다. 프로젝트 사이즈, 서버 비용을 감안하여 EC2보다는 Lightsail으로 작업을 진행했다. Lightsail 설정 Instance 생성 인스턴스 이미지는 OS만 설치하도록 설정했다. ( Ubuntu 20.04 LTS ) nginx가 설치된 형태도 진행해봤는데, 다른 패키지 설치 과정에서 충돌나거나 nginx.conf 파일에서 추가적인 작업을 하는 등의 이슈로 그냥 OS만 설치하는게 마음이 편했다. Static IP / DNS 생성 도메인을 가비아에서 구매했고, Lightsail 서버에 연동이 필요했다. Network 탭에서 Static IP, DNS zone을 클릭하여 IP, DNS를 발급받았다. 발급받은 후 모습이며, Static IP는 생성한 인스턴스에 연결해야하고 DNS에서는 records를 생성하여 도메인을 추가해야한다. 가비아에서 도메인 설정 방법 도메인 정보 변경 -> 네임서버 설정 DNS 정보 -> DNS 관리 -> A 레코드, IP 입력 서버 설정 서버 접근 Lightsail에서 Connect하면 브라우저 콘솔로 서버에 접근할 수 있지만, iterm이 편하다 보니 ssh key 파일을 다운받아 진행했다. ( pem 파일은 계정 Account 또는 인스턴스 Connect 탭에서 설치 가능하다.) sudo ssh -i "key.pem" [StaticIP] -l ubuntu # Warning이 뜨는 경우, 권한...
2021년 09월 04일
N x N 크기의 2차원 배열을 시계방향으로 90도씩 회전하려 합니다. 다음은 2 x 2 크기의 2차원 배열을 시계방향으로 90도씩 회전하는 예시입니다. // Example ( 2x2 ) [ [1, 2], [3, 4], ][ // After ( 1회 회전 ) ([3, 1], [4, 2]) ][ // Example ( 2x2 ) ([1, 2], [3, 4]) ][ // After ( 2회 회전 ) ([4, 3], [2, 1]) ][ // Example ( 3x3 ) ([4, 1, 2], [7, 3, 4], [3, 5, 6]) ][ // After ( 3회 회전 ) ([2, 4, 6], [1, 3, 5], [4, 7, 3]) ]; 소스코드 !! 정답제출 후 업데이트하지 않은 코드여서 안돌아갈 수 있어요! const rotateMatrix = (matrix, r) => { if (!r) return matrix; let temp = new Array(matrix.length) .fill(0) .map(() => new Array(matrix.length).fill(0)); for (let i = 0; i < matrix.length; i++) { for (let j = 0; j < matrix.length; j++) { if (!temp[i][j]) { temp[i][j]...
2021년 09월 04일
학생정보와 과목 별 점수 데이터가 들어오는데, 해당 과목에서 최고 점수와 최소 점수를 제외하고 등급 순서로 나열한다. const grade = (arr) => { const average = arr.reduce((sum, currValue) => sum + currValue, 0) / arr.length; if (average >= 90) return "A"; if (average >= 80) return "B"; if (average >= 70) return "C"; if (average >= 50) return "D"; return "F"; }; function solution(scores) { const item = scores.map((_, arrIndex) => { let group = scores.map((_, numIndex) => scores[numIndex][arrIndex]); const personNum = group[arrIndex]; if ( personNum === Math.max.apply(null, group) || personNum === Math.min.apply(null, group) ) { group.filter((num) => num === personNum).length === 1 && group.splice(arrIndex, 1); } return grade(group); }); return item.join(""); }
2021년 09월 04일
LV2 문제 function solution(n) { if (n < 3) return `${n || ""}`; if (!(n % 3)) return `${solution(Math.floor(n / 3) - 1)}4`; else return `${solution(Math.floor(n / 3))}${n % 3}`; }
2021년 03월 20일
styled-components를 사용하는 도중 defaultProps 타입 오류가 발생했다. Props 전달에도 이상이 없었고 어떤 오류인가 싶어서 검색해봤다. Type of property 'defaultProps' circularly references itself in mapped type TypeScript Github에 등록된 이슈를 확인해보니, 정확하지는 않지만 Typescript^3.9.0 이후 나타나며 해당 오류는 styled-components에서 5.0.1 버전대에서 fix 되었다. ( 자세한 사항은 하단 참고자료로 이동하여 확인하면 좋을 것 같다. ) yarn upgrade @types/styled-components --latest # or npm install @types/styled-components@latest styled-components의 type을 업데이트하는 방법이 있으며, 어려운 경우에는 styled-components.d.ts를 생성하여 예외처리 하는 방향도 있다. 참고자료 https://github.com/microsoft/TypeScript/issues/37597#issuecomment-628149946
2021년 03월 10일
작업을 스테이지에 올렸다가 릴리즈 날짜에 배포가 불가능하면 해당 기능을 잠시 스테이지에서 빼둬야한다. 이때 develop 브랜치에서 Revert를 생성하여 Merge 하는 작업을 진행한다. 여기까지는 괜찮았으나 작업중인 브랜치에서 devleop을 Pull 받으니 문제가 나타났다. develop에서는 Merge를 통하여 해당 내용들을 전부 삭제했으니 작업중인 브랜치에 있는 내용들도 전부 삭제 시켜버린다. 동일 파일을 작업하던 부분들까지 날려버리니 멘붕이 나버렸다. 여러번의 검색 끝에 간단한 해결방법을 찾았는데 결국 Revert를 Revert하자! 라는게 편한 방법이다. 해결방법 Merge, Revert한 브랜치명을 develop으로 명칭하고 진행한다. Revert Commit SHA Key를 가져오자. develop에서 git log를 확인하여 revert한 커밋 키 값을 가져온다. git checkout develop git log commit [REVERT_COMMIT_SHA_KEY] (tag: ...) Author: Doriri <public.doriri@gmail.com> Date: ... Revert "커밋 메시지" 여기서 REVERT_COMMIT_SHA_KEY 해당 부분을 복사해준다. New Branch & Revert를 Revert 하자. 새로운 브랜치를 생성하고, Revert 커밋을 Revert 해보자. git checkout -b [new_branch] git revert [REVERT_COMMIT_SHA_KEY] 그리고 마무리로 기존 브랜치를 pull 받으면 끝이다. git pull origin [origin_branch] 커맨드 요약 git checkout develop git checkout -b feature/new-branch git revert [SHA_REVERT_COMMIT] git...
2021년 03월 10일
Disqus 계정에서 이메일을 변경하면서 인증하라는 메시지가 나왔다. 인증받기를 눌러도 메일은 한참 지나서오고 들어가보니 연결을 거부당했다. 사이트에 연결할 수 없음 disq.us에서 연결을 거부했습니다. ERR_CONNECTION_REFUSED 도메인이 disq.us인게 url shoutcut으로 사용한 것 같은데, 내 네트워크 문제인지 쟤네 문제인지.. 아무튼 거부당했다. 혹시나 해서 disq.us 부분만 disqus.com으로 바꿨더니 url이라는 사용자의 프로필로 이동했다. URL을 다시 확인해보니 결국은 disq.us에서 url을 파라미터로 받아서 리다이렉트를 하는 방식이다. 해결방법 disq.us/url?url= 여기서 부터 뒷부분을 전부 복사한다. url을 decode 해주자. urlDecoder에서 붙여넣기 후 decode decode 된 url 경로로 이동하자. Your email has been verified successfully!
2021년 03월 09일
Grafana Plugin을 React로 개발하여 배포하는 방법을 설명한다. 작업환경 OS: Mac node: >= 14.0 grafana: >= 7.0 시작하기 Grafana 설치하기 Grafana 설치 가이드 문서 Ubuntu, Docker 등 OS 별 설치방법 문서가 존재한다. brew update brew install grafana Grafana 프로젝트 생성 프로젝트 구조는 grafana-toolkit를 사용한다. grafana-toolkit은 creact-react-app 처럼 초기 프로젝트를 구축하기 위한 CLI이다. 맨 설치하는 과정에서 plugin, author 등은 원하는 형태에 맞춰서 작성하면 되며, 플러그인 이름은 신중하게 입력해보자. npm install -g @grafana/toolkit npx @grafana/toolkit plugin:create [project-name] cd graph-plugin npm install ( 프로젝트를 grafana에 연동하는 부분은 아래에서 진행한다. ) 실행하기 설치한 grafana 서비스를 실행한다. brew services start grafana 기본적으로 localhost:3000로 포트가 열린다. 초기 계정은 admin/admin 이다. 개발셋팅 프로젝트를 생성했고 grafana service 가 동작한다면, 프로젝트를 플러그인에 연동해야한다. grafana ini 설정 grafana 설정파일에서 plugin path를 연결한다. vim /usr/local/etc/grafana/grafana.ini [paths] plugins = [Grafana Project Path] 이때, [paths] 아래에 추가해야한다. 맨 상단 혹은 맨 하단에 작성 시 작동되지 않는다. 실행하기 설치한 grafana 서비스를 재실행한다. brew services restart...
2021년 03월 09일
axios은 기본적으로 api timeout이 설정되어 있지 않다. 따라서 API를 호출하면 서버에서 응답 주기 전까지는 계속 연결되어 았다. axios timeout 설정하기 axios를 생성하여 timeout을 옵션으로 추가하고 해당 인스턴스로 api를 호출하도록 작업을 진행한다. const instance = axios.create({ timeout: 30000, }); export const baseApi = (method, url, params) => { return instance .request({ method, url, data: params, }) .then(axiosResponseToData) .catch(axiosErrorResToData); }; 기존에 ts로 작성되어 있던 부분들인데, 불필요해 보여 제거 후 함수만 등록하였다.
2021년 03월 08일
ERROR: Error installing jekyll-sitemap: ERROR: Failed to build gem native extension. gem으로 jekyll 모듈을 설치하는 과정에서 다음과 같은 오류가 나타났다. 검색해보니 xcode 관련 자료만 나오다가 해당 모듈이 사용 중인 jekyll 버전을 미지원하는 내용이 나왔다. 해당 모듈의 버전 리스트를 검색한다. gem list --remote --all jekyll-sitemap *** REMOTE GEMS *** jekyll-sitemap ( [versions] ) 지원하는 버전을 설치해보자. sudo gem install jekyll-sitemap -v [version] Successfully installed jekyll-sitemap-[version] 사용하려는 jekyll-sitemap은 현재 jekyll 버전에서 v1.2.0까지만 지원한다고 한다. 지원 여부를 깃헙에서 확인해 봤으면 됐을 텐데, 오류만 검색하다가 시간을 많이 소모했다. 이렇게 모듈을 설치하고 빌드하니 gem install을 실행하라고 한다. Gemfile.lock 파일을 삭제하지 않아 의존성 체크가 되었는데, 신기하게 gem install 하니 직접 설치할 때 오류 나던 jekyll-sitemap 1.4.0이 설치되었다. lock 파일의 의존성은 알겠으나 yarn.lock 하고 좀 다르게 동작하는 느낌이다. 아직 gem에 대한 이해가 부족해서 나온 이슈인데, 공부가 필요할 듯하다. 참고 자료 understanding-the-gemfile-lock-file https://stackoverflow.com/questions/4907668/removing-all-installed-gems-and-starting-over/49960935
2021년 02월 04일
공식문서 AOS/iOS 에뮬레이터 설치 https://reactnative.dev/docs/environment-setup error Failed to install the app error Failed to install the app. Make sure you have an Android emulator running or a > device connected. Run CLI with –verbose flag for more details. bash chmod 755 android/gradlew 실행 emulator -list-avds 리스트 뜨는지 확인 ~/.bash_profile 또는 ~/.zshrc 에 path 정상 등록되어있는지 확인 Task :app:stripDebugDebugSymbols UP-TO-DATE Compatible side by side NDK version was not found. Task :app:installDebug FAILED Android Studio -> Configure -> SDK Manager -> SDK Tools -> NDK 설치 Failed to run jetifier yarn yarn add -D jetifier npx jetify npx react-native run-android or react-native run-android --no-jetifier
2020년 01월 17일
채팅과 같이 메시지가 도착하면 최하단으로 계속 이동해야하는 경우나 단순 최하단으로 이동하고 싶을 때 구현하는 방법입니다. 자바스크립트에서 스크롤 하단으로 이동 엘리먼트의 height만큼 scroll 위치를 이동합니다. // overflow 스크롤이 걸려있는 엘리먼트 const ele = document.querySelector("ul"); ele.scrollTop = ele.scrollHeight; React에서 응용하기 React에서 채팅 레이아웃에서 메시지가 들어올 때마다 최하단으로 이동하는 코드입니다. import React, { useRef, useEffect } from 'react'; import { useMessages } from 'Hooks'; ... const messagesRef = useRef<HTMLUListElement>(null); // 메시지 엘리먼트를 저장 const { messages } = useMessages(); // Custom Hooks : 메시지 리스트 useEffect(() => { messagesRef.current!.scrollTop = messagesRef.current!.scrollHeight; }, [messages]); ... return ( <ul className="messages" ref={messagesRef}> {messages.map(message => { return ( <li key={message.key}> ... </li> ); })} </ul>; ) firebase를 사용하고 있으며, 메시지를 구독하면 useMessages에서 messages를 내려줍니다. 이후 messages가 업데이트될 때 마다, ul 엘리먼트를 최하단으로 이동합니다. 만일 특별하게 최하단으로 이동하기 싫으시다면, useEffect 내에 if문으로 조건을 설정하시면 됩니다.
2020년 01월 08일
axios로 개발할 때, API마다 try ~ catch문을 적용하여 에러 처리를 진행해왔습니다. 이번 프로젝트에서는 Token을 관리하며, 서버에서 403에러가 오면 Token을 재발행해야하는 환경이라 더 나은 코드가 없을까 찾아보니 interceptors가 있었습니다. axios.interceptors axios.interceptors 함수를 통해 request, response를 감지할 수 있습니다. // API 호출 전 해당 함수가 먼저 실행됩니다. axios.interceptors.request.use( (config) => { return config; }, (error) => { return Promise.reject(error); } ); // API 실행 후 response를 감지하여 데이터를 return 합니다. axios.interceptors.response.use( (response) => { return response; }, (error) => { return Promise.reject(error); } ); 위 예제처럼 interceptors.response를 통하여 에러를 감지할 수 있게됩니다. 그러면 다시 response에 에러처리를 위해 코드를 작성합니다. const _axios = axios.create({ baseURL: process.env.REACT_APP_API_URL, }); _axios.interceptors.response.use( (response) => response, (error) => { if (error.response && error.response.status === 403) { return Auth.refreshToken() // token 재발행 및 반환 .then((token) => { originalRequest.headers["Authorization"] = token; return _axios.request(error.config); // error.config(origin API 정보)를 다시 요청 }) .catch((error) => { window.location.href = "/login"; }); } return Promise.reject(error);...
2020년 01월 08일
HTML Event 키보드 관련 이벤트 ( keyup ) document.addEventListener("keyup", (event: KeyboardEvent) => { console.log(event.keyCode); }); React React.cloneElement type ReactText = string | number; type ReactChild = ReactElement<any> | ReactText; return React.cloneElement(child as React.ReactElement<any>, { width: this.props.width, height: this.props.height, }); react-router-dom history import { RouteComponentProps } from 'react-router-dom'; interface Props extends RouteComponentProps<any> {} const Component : React.FC<Props> = ({ history }) => ();
2020년 01월 08일
HTML에서 세로 정렬은 다들 까다로워하는 부분입니다. vertical-align: middle;으로 알고 사용하지만, 특정한 환경(Table 등)이 아니라면 세로 정렬이 되지 않는 문제 때문입니다. 이번 글에서는 CSS flex와 align-items를 사용하여 쉽게 세로정렬하는 방법을 알아봅니다. 세로/가로 가운데 정렬 <div class="login-page"> <div class="center"> <h3>Login</h3> <form> <input /> <input /> <input /> </form> </div> </div> 위 예제에서 로그인 페이지 내에 내용을 가로/세로 정렬을 진행합니다. .login-page { display: flex; // flex 사용 height: 100vh; // 세로 높이를 화면 크기에 맞춤 align-items: center; // 세로 정렬 justify-content: center; // 가운데 정렬( 아래서 추가 설명 ) margin: 0 auto; // 가운데 정렬 } justify-content 속성은 flex-direction 속성의 진행 축 정렬에 영향을 받는데, flex-direction: row | row-reverse 인 경우 x축 정렬을 제어합니다. flex-direction: column | column-reverse 인 경우 y축 정렬을 제어합니다.
2020년 01월 07일
스코프(Scope, 유효범위)에 대해서는 여러분들은 이미 사용하고 있을 것 입니다. 다만, 정확한 정의와 상세한 정보에 대해서 글을 통해 상세하게 알고 넘어가겠습니다. 스코프란? 특정한 변수(identifier)에 접근이 가능한가에 대한 규칙(범위)입니다. var x = "global scope"; function foo() { var x = "function scope"; console.log(x); } foo(); // function scope console.log(x); // global scope 위 예제에서 함수 foo 내 선언된 변수 x에 대해서는 foo 내에서만 참조가 가능하고 외부에서는 참조가 불가능하다. 이와같은 규칙들을 스코프라고 합니다. 스코프의 구분 스코프는 전역 스코프와 지역 스코프로 나눠집니다. 전역 스코프(Global Scope) 전역 변수(Global variable), 코드 어디에서든 참조할 수 있습니다. var로 선언한 전역 변수는 전역 객체(Global Object) window의 프로퍼티가 됩니다. 지역 스코프 (Local scope or Function-level scope) 지역 변수(Local variable), 지역(함수) 내에서 선언되어 함수 내에서 자신과 하위 함수에서만 참조 가능합니다. 자바스크립트 스코프 특징 자바스크립트는 함수 레벨 스코프(function-level scope)(함수 코드 블록 내에서 선언된 변수는 함수 코드 블록 내에서만 유효)를 따르고 있습니다. var x = 1; // 전역변수 (function () { var y...
2020년 01월 06일
이전 프로젝트에서는 webpack을 eject하여 CSS module을 사용했지만, 이번 프로젝트에서는 eject 작업을 하지 않고 진행하기 때문에 방법을 찾아보았다. CSS Module 적응 전에는..? Module을 적용하지 않는다면, 최상단 App.jsx 또는 컴포넌트에서 scss 파일을 호출합니다. // index.tsx or App.tsx import "./index.scss"; 또한 클래스명이 기존 html처럼 class=”container” 형태로 들어가기 때문에 css/scss 파일을 컴포넌트별로 생성했음에도 스타일 명이 충돌하는 불편함이 있습니다. 그렇다면 CRA에서 CSS Module은 어떻게 적용하지? css/scss 파일명을 module.css, module.scss로 변경합니다. 예를들어 index.scss는 index.module.scss 가 됩니다. 이후 컴포넌트에서는 다음과 같이 사용합니다. import React from "react"; import styles from "./index.module.scss"; ... return ( <div id={styles.container}> <div className={styles.messageWrap}> </div> </div> ) ... scss는 기존처럼 사용하시면 되며, id, class의 컴파일 결과를 확인하시면 scss 파일의 이름 혹은 폴더 이름으로 유니크하게 생성된 것을 확인할 수 있습니다. 아래는 컴파일 결과의 예시입니다. // components/Pages/index.module.scss #loginPage { display: block; } // components/Pages/LoginPage.tsx import styles from "./index.module.scss" ... return ( <div id={styles.loginPage}> ); => <div class="Pages_LoginPage__2Jrev" />
2019년 12월 23일
자바스크립트는 프로토타입 기반 객체지향 언어라고 불립니다. 그리고 여러분들은 한번 쯤은 __proto__라는 Object를 본 적이 있을 것이고 그냥 지나치는 경우가 대다수일 것 입니다. 그러한 __proto__가 무엇이고 자바스크립트가 prototype 기반 언어라는 이유를 알아보도록 하겠습니다. Prototype 자바스크립트에서 모든 객체는 부모(객체 원형)와 연결되어 있습니다. 그리고 객체 지향에서 상속 개념과 동일하게 부모의 프로퍼티와 메소드를 상속받아 사용할 수 있게 됩니다. 여기서 부모 객체를 Prototype 객체 또는 Prototype이라고 부릅니다. 간단한 예제를 통해 알아봅니다. var item = { key: "key", }; console.log(item); // { // key: "key" // __proto__: { // item 객체의 Prototype(부모 객체) 정보 // constructor: ƒ Object() // hasOwnProperty: ƒ hasOwnProperty() // toString: ƒ toString() // valueOf: ƒ valueOf() // ... // } // } console.log(item.hasOwnProperty("key")); // true item 객체를 출력하여 __proto__ 프로퍼티를 열어보면 자바스크립트의 Object 객체가 부모이며, item 객체에서 선언하지 않은 hasOwnProperty 메소드를 상속받아 사용이 가능합니다. proto ? 위에서 생각할 수 있는 부분은 ‘아 __proto__ 프로퍼티를 통하여 부모 객체에 접근할 수 있구나’라는 것을 알...
2019년 12월 19일
Google Search Console에서는 Google 검색에 콘텐츠를 표시하기 위한 실행 가능 보고서, 도구, 학습 리소스를 제공합니다. Link Google Search Console에서 봇이 데이터를 가져가기 위해 sitemap과 robots의 설정이 필요하며, 먼저 설명드리겠습니다. 작성 당시 jekyll 버전은 3.8.6 입니다. Jekyll Sitemap 설치 gem jekyll-sitemap 설치 gem install jekyll-sitemap Gemfile 설정 # GemFile group :jekyll_plugins do gem "jekyll-sitemap" _config.yml 수정 # _config.yml plugins: - jekyll-sitemap 이제 도메인 뒤에 /sitemap.xml를 붙여 설정된 것을 확인합니다. ex) https://minhyeong-jang.github.io/sitemap.xml robots.txt 설정 Bot에게 현재 사이트의 sitemap과 권한 설정 등을 제공합니다. User-agent: * Allow: / Sitemap: https://minhyeong-jang.github.io/sitemap.xml Google Search Console 생성 이제 마지막으로 Google Search Console 홈페이지에서 속성을 생성합니다. 도메인 / URL 접두어로 나눠져있는데, 따로 Github Pages에 도메인을 설정하지 않은 경우 URL 접두어를 선택합니다. 선택 후에는 설명에 따라 인증을 진행합니다. ( 이전에 작성한 anlytics를 진행하신 분은 바로 인증이 가능합니다. ) Sitemaps 탭으로 이동하여 새 사이트맵에 생성한 sitemap.xml URL을 입력하여 제출합니다. 제출에 성공한 경우 정상적으로 완료된 것 입니다.
2019년 12월 19일
Google에서 제공하는 Google Analytics라는 툴을 사용하여 웹 로그를 분석할 수 있습니다. Google Analytics는 앱 또는 웹의 이용자를 분석하여 통계로 제공해주고 있으며, 예로들어 방문 페이지, 이탈률, 세션 시간 등이 있습니다. 또한 Google Ads, Google Search Console 등 관련 서비스와 통합하여 확인할 수 있습니다. Google Analytics 설정 우선 Google Analytics에 접속하여서 계정을 생성합니다. 계정은 여러개 생성이 가능하며, ‘속성 및 앱’에 페이지 별로 생성이 가능합니다. 저는 Blog라는 계정 하위에 Tistory, Github Page의 링크를 별도로 등록했습니다. 등록이 완료되면 추적 코드가 나타나게 되며, 해당 페이지에서 추적 ID, 태그(js)를 제공하고 있습니다. 추적 코드 탭이 나타나지 않는다면, 좌측 하단 관리 -> 속성 -> 추적정보 -> 추적코드로 이동합니다. Jekyll 설정 위에서 나온 js를 복붙하셔도 상관 없지만, 저같은 경우에 _config.yml에 추적 ID 값을 넣었습니다. google_analytics_id: 추적 ID 그리고 analytics 파일을 생성하여 Google Analytics에서 제공하는 js를 삽입하고 추적 ID 값을 불러옵니다. 아래 코드는 추적 ID 값을 _config에서 가져오도록 수정한 코드입니다. <!-- analytics.html --> {% if site.google_analytics_id %} <script async src="https://www.googletagmanager.com/gtag/js?id={{...
2019년 12월 12일
Nextjs에서 styled-components (이하 SC) 사용하면 CSS 로딩이 늦게 되어 발생하는 깜빡임 현상이 발생합니다. 개인적인 생각으로는 HTML은 SSR로 미리 렌더링 시켜 보내지만 SC의 스타일들은 사용자가 접속 시 변환된다고 생각합니다. css를 미리 적용할 수 있을까? 참고 자료 Next.js와 SC를 검색한 결과, ServerStyleSheet라는 함수를 SC에서 제공하고 있었고 Next.js에서 샘플 코드를 제공하고 있었습니다. 해당 페이지에서 제공하는 코드는 다음과 같습니다. import Document from "next/document"; import { ServerStyleSheet } from "styled-components"; export default class MyDocument extends Document { static async getInitialProps(ctx) { const sheet = new ServerStyleSheet(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />), }); const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: ( <> {initialProps.styles} {sheet.getStyleElement()} </> ), }; } finally { sheet.seal(); } } } _document.js 란? HTML Document를 관리하는 부분으로 이 외에도 '_app.js, _error.js' 등이 있습니다. 위 코드에서 에러가 나신다면..? 시간이 지나고 작성하는 글이라 정확하게 기억은 안나지만, 위에 코드를 사용해도...
2019년 12월 12일
ol, li 태그를 사용하면 옆에 숫자가 기본적으로 나타나는데, 해당 숫자에 bold 처리하는 방법입니다. 단순 font-weight 처리 방법 기본적으로 list-style에 bold 처리를 하려면 ol 태그에 적용하면 됩니다. 이후 li 내 태그를 생성하여 normal을 적용합니다. <ol> <li> <p>test</p> </li> <li> <p>test2</p> </li> <li>not work</li> </ol> <style> ol { font-weight: bold; } ol li p { font-weight: normal; } </style> 위 방법의 문제점은 마지막 li처럼 태그 적용이 안되어있으면 같이 bold 처리가 됩니다. count-increment count-increment 방법을 사용하여 list-style을 사용하지 않고 카운터를 작성할 수 있습니다. <ol> <li> <p>test</p> </li> <li> <p>test2</p> </li> <li>not work</li> </ol> <style> ol { margin: 0 0 1.5em; padding: 0; counter-reset: item; } ol > li { margin: 0; padding: 0 0 0 2em; text-indent: -2em; list-style-type: none; counter-increment: item; } ol > li:before { display: inline-block; width: 1em; padding-right: 0.5em; font-weight: bold; text-align: right; content: counter(item) "."; } </style> counter를 사용하여 li:before에 숫자를 직접 작성하는 방법입니다. 단점으로는 list-style처럼 다양한 스타일이...
2019년 12월 12일
Jekyll에서 Disqus를 연동하는 방법을 살펴보도록 하겠습니다. Disqus 설정 Disqus 홈페이지에 접속해서 회원가입을 진행합니다. 로그인 후 상단에 Get Start -> I want to install Disqus on my site를 선택합니다. 정보를 입력 후 확인을 누른 후 플랫폼 선택에서 jekyll를 선택합니다. ( 만약 화면이 나타나지 않는 경우, admin -> Settings -> Installation ) 설명 2번에 있는 Universal Embed Code 링크 클릭 홈페이지 첫 동영상 밑에 있는 1번의 Disqus to load 코드를 post Layout에 추가합니다. 중간 주석 부분에는 Disqus thread가 중복되어 생성되는 것을 방지하기 위해 page_url, identifier를 추가하라고 적혀있습니다. 해당 부분은 아래와 같이 site 정보를 설정해주시면 됩니다. this.page.url = "https://minhyeong-jang.github.io/2019/12/12/jekyll-disqus"; // minhyeong-jang.github.com/2019/12/... this.page.identifier = "/2019/12/12/jekyll-disqus"; // /2019/12/... 홈페이지에서 두번째 동영상 밑에 있는 count.js 스크립트를 body 맨 아래 선언하면 댓글 수가 체크됩니다. 적용 후 새로고침 하시면 로컬에서도 정상적으로 Disqus가 보이게 됩니다.
2019년 12월 11일
2019년 초에 Redux를 사용하다가 불편함이 많아 useContext를 사용법을 찾아봤을 때 자료가 생각보다 많지 않아 헤맸던 기억이 있습니다. 늦었지만, useContext의 활용법을 공유 드립니다. createContext로 생성하자 import React, { createContext } from "react"; export const AppContext = createContext(); 우선 Context를 생성합니다. 초기화는 바로 할 필요 없으며, export하는 이유는 Redux처럼 다른 파일에서 접근하기 위해 정의합니다. context에 함수와 데이터를 저장하자 const App = () => { const [text, setText] = useState("test"); const logText = (text) => { console.log("test"); }; return ( <AppContext.Provider value=> <ViewLayout /> </AppContext.Provider> ); }; export default App; Provider를 선언하게 되면, 해당 Provider의 자식들은 value에 선언된 부분들을 props로 넘겨주지 않아도 사용할 수 있습니다. ViewLayout에서 useContext를 사용하여 데이터 및 함수 실행을 진행합니다. useContext로 호출하자 import React, { useContext } from "react"; // App에 선언 된 context 호출 import { AppContext } from "./App"; const ViewLayout = () => { const { text, setText, logText } = useContext(AppContext); return ( <div> <div>{text}</div> <button...
2019년 12월 11일
동영상 플레이어 중 영상의 비율을 맞춰주기 위해 영상의 세로가 긴 화면은 양쪽에 검은색 여백이, 영상의 가로가 긴 화면은 상하단에 검은색 여백이 생성되는 플레이어들이 있습니다. 검은색 여백은 video 태그에 width: 100% or height:100% 중 어떤 속성인지로 적용됩니다. 여기서 video 태그를 감싸고 있는 div보다 video 태그의 height가 높아지면 height를 100%로 고정하여 양 옆에 여백을 생성하고, width가 높아지면 width를 100%로 고정하여 상하에 여백을 생성합니다. 동영상의 비율을 수정하자 useRef를 사용해도 무방합니다. useLayoutEffect를 사용하여 화면의 resize를 감지하고 함수를 실행합니다. updateSize 함수에서 video 사이즈와 video-wrap 사이즈를 비교하고 클래스를 적용합니다. contains로 현재 클래스를 비교한 이유는 이미 적용되어있기 때문에 if문을 거쳐도 변화가 없기 때문입니다. import React, { useLayoutEffect } from "react"; const Video = () => { const updateSize = () => { const videoWrap = document.querySelector("#video-wrap"); const video = document.querySelector("#video"); if ( !video.classList.contains("is-vertical") && video.offsetHeight > videoWrap.offsetHeight ) { video.classList.add("is-vertical"); } else if ( video.classList.contains("is-vertical") && video.offsetWidth > videoWrap.offsetWidth ) { video.classList.remove("is-vertical"); } }; useLayoutEffect(() => {...
2019년 12월 11일
typescript 환경에서 console.log를 입력하면 상단에 import console = require('console');가 자동으로 import 생성된다. 해당 문제가 VSCode, Typescript 중 어디서 생성되는지 모르지만 해결방법은 있습니다. 해결방안 구글에서 해결방안 중 node_modules 내 파일을 수정하는 방안도 있었지만, 팀원들도 동일한 증상을 겪을 것 같아 declare 방법으로 진행하였습니다. 프로젝트 root 디렉토리에 console.d.ts를 생성 후 아래 코드를 추가합니다. ( 기존에 사용중이신 d.ts가 있으시다면 그걸 사용하셔도 됩니다. ) declare module 'console' { export = typeof import("console"); } 문제가 해결되지 않으면 command + shift + p 후 TypeScript: Restart to Server를 실행해주세요. tsconfig에서 baseUrl을 추가하신 경우, baseUrl의 경로가 root가 됩니다.
2019년 12월 09일
Jekyll을 사용하며 나타난 오류를 정리합니다. Scss Import Error + Tip Conversion error: Jekyll::Converters::Scss encountered an error while converting 'assets/css/index.scss': File to import not found or unreadable: filename. on line 1 Conversion error: Jekyll::Converters::Scss encountered an error while converting 'assets/css/index.scss': Invalid CSS after "": expected selector, was "---" on line 1 Conversion error: Jekyll::Converters::Scss encountered an error while converting 'assets/css/index.scss': Invalid CSS after "@import "theme"": expected "{", was ";" on line 3 scss 파일은 빌드 후 css + minify 형태로 제공해주기 때문에 head에서는 src=”index.css” 형태로 작성하게 됩니다. 파일 수 만큼 css를 import하면 속도가 느려 index.scss 파일 하나에서 모든 scss 파일을 import 하는 방법으로 bundle 작업을 진행하는게 좋습니다. jekyll은 scss에서 상단에 아래 문구가 적혀있으면 css로 빌드 작업을 진행합니다. --- --- index.scss 파일에서만 위에 문구를 추가한 후 나머지 파일을 import 해줍니다. 만일 index.scss에서 호출하는 scss 파일들은 상단에 --- 문구가 존재하면 에러가 나타납니다. 호출하기 위한 파일을 구분하기 위해 _theme.scss 처럼 파일명 앞에 _를 붙여줍니다....
2019년 12월 02일
Github에서 리액트 앱을 공유할 때, 서버 없이 간단하게 Github Page로 공유가 가능합니다. gh-pages 모듈 설치 yarn add --dev gh-pages package.json 수정 gh-pages 모듈을 설치 후 package.json에서 아래 내용을 추가해주세요. { ... "homepage": "/${path}", "scripts": { ... "predeploy": "yarn build", "deploy": "gh-pages -d build" } } gh-pages 배포 yarn run deploy 만약 deploy 명령어로 배포 시 gh-pages 브랜치를 생성하는 과정에서 오류가 발생할 수도 있다. git branch로 조회해도 없는 gh-pages가 이미 존재한다는 오류는 새롭다.. 이럴 때는 당황한 뒤에 gh-pages 브랜치를 직접 생성한 후 push 해보자. git checkout -b gh-pages git push --set-upstream origin gh-pages yarn run deploy 확인 배포가 완료되면, gh-pages branch가 생성되어 있습니다. Github에서 해당 프로젝트로 이동 후 Settings -> 하단 GitHub Pages 메뉴를 보시면 배포 된 깃헙 페이지 링크를 확인할 수 있습니다.
2019년 06월 03일
문제 N개의 아파트가 일렬로 쭉 늘어서 있습니다. 이 중에서 일부 아파트 옥상에는 4g 기지국이 설치되어 있습니다. 기술이 발전해 5g 수요가 높아져 4g 기지국을 5g 기지국으로 바꾸려 합니다. 그런데 5g 기지국은 4g 기지국보다 전달 범위가 좁아, 4g 기지국을 5g 기지국으로 바꾸면 어떤 아파트에는 전파가 도달하지 않습니다. 예를 들어 11개의 아파트가 쭉 늘어서 있고, [4, 11] 번째 아파트 옥상에는 4g 기지국이 설치되어 있습니다. 만약 이 4g 기지국이 전파 도달 거리가 1인 5g 기지국으로 바뀔 경우 모든 아파트에 전파를 전달할 수 없습니다. (전파의 도달 거리가 W일 땐, 기지국이 설치된 아파트를 기준으로 전파를 양쪽으로 W만큼 전달할 수 있습니다.) 초기에, 1, 2, 6, 7, 8, 9번째 아파트에는 전파가 전달되지 않습니다. 1, 7, 9번째 아파트 옥상에 기지국을 설치할 경우, 모든 아파트에 전파를 전달할 수 있습니다. 3개의 아파트보다 더 많은 아파트 옥상에 기지국을 설치할 경우에도 모든 아파트에 전파를 전달할 수 있습니다. 이때, 우리는 기지국을 최소로 설치하면서 모든 아파트에 전파를 전달하려고 합니다. 해결방법 및 소스코드 처음에는 N개의 아파트를...
2019년 05월 29일
문제 xx 회사의 2xN명의 사원들은 N명씩 두 팀으로 나눠 숫자 게임을 하려고 합니다. 두 개의 팀을 각각 A팀과 B팀이라고 하겠습니다. 숫자 게임의 규칙은 다음과 같습니다. 먼저 모든 사원이 무작위로 자연수를 하나씩 부여받습니다. 각 사원은 딱 한 번씩 경기를 합니다. 각 경기당 A팀에서 한 사원이, B팀에서 한 사원이 나와 서로의 수를 공개합니다. 그때 숫자가 큰 쪽이 승리하게 되고, 승리한 사원이 속한 팀은 승점을 1점 얻게 됩니다. 만약 숫자가 같다면 누구도 승점을 얻지 않습니다. 전체 사원들은 우선 무작위로 자연수를 하나씩 부여받았습니다. 그다음 A팀은 빠르게 출전순서를 정했고 자신들의 출전 순서를 B팀에게 공개해버렸습니다. B팀은 그것을 보고 자신들의 최종 승점을 가장 높이는 방법으로 팀원들의 출전 순서를 정했습니다. 이때의 B팀이 얻는 승점을 구해주세요. A 팀원들이 부여받은 수가 출전 순서대로 나열되어있는 배열 A와 i번째 원소가 B팀의 i번 팀원이 부여받은 수를 의미하는 배열 B가 주어질 때, B 팀원들이 얻을 수 있는 최대 승점을 return 하도록 solution 함수를 완성해주세요. 제한사항 A와 B의 길이는 같습니다. A와 B의 길이는 1 이상...
2019년 05월 27일
fatal: refusing to merge unrelated histories 로컬 저장소에서 Git Repo 생성 후 push 하는 경우, 프로젝트 충돌로 나타나는 오류이다. git pull origin main --allow-unrelated-histories
2019년 05월 24일
Typescript? Typescript는 프로그래밍 언어로 Javascript + Type의 합성어이다. 컴파일 시 Javascript로 변환된다. Javascript가 유명한 건 엄격한 규칙이 없기 때문에 사용하기 쉽고, 우리가 원하는 방향으로 수정하기도 쉽다. 하지만 큰 프로젝트에서 일을 하거나 버그를 최소화하고 싶다면 위의 장점이 단점이 된다. Typescript로 작성하면 기능 예측이 가능하며, 코드를 읽기 쉬워지게 된다. 설치 yarn add typescript yarn add tsc-watch --dev yarn add crypto-js 참고 : yarn global add typescript 로 설치하는 경우, tsc-watch가 인식하지 못하는 오류가 있습니다. 설정 tsconfig.json Typescript => Javascript 변환할 떄 반영하는 설정 { "compilerOptions": { "module": "commonjs", "target": "ES2015", "sourceMap": true, "outDir": "dist" } } "module": "commonjs" node.js 평범하게 import, export 한다. "target": "ES2015" ES5 버전으로 컴파일 한다. "sourceMap": true Sourcemap을 설정한다. ( Sourcemap 이란? ) "outDir": "dist" dist 파일로 컴파일된 파일을 출력한다. "include": ["src/**/*"] 컴파일 과정에서 포함할 파일 ( src 폴더 내 전체 파일 ) "excude": ["node_modules"] 컴파일 과정에서 미포함 파일 tsc-watch 소스코드 수정 시 자동으로 컴파일을 진행한다. 기존 스크립트...
2019년 05월 24일
1. Sourcemap 이란? 많은 개발 환경은 Webpack 등으로 빌드 과정을 거치고있다. 만일 빌드 후 취합되거나 변환 된 CSS, JavaScript 파일들이 오류가 발생한다면, 개발자 도구에서는 빌드 된 파일에서 오류를 출력하고 있을 것이다. 하지만 우리가 원하는 것은 빌드 전 오류난 파일 및 라인을 알고싶은 것이다. 예를 들면, SCSS에 오류가 있고 Webpack으로 빌드를 진행하면 웹페이지에서 오류를 알려주는 부분은 빌드가 완료된 CSS를 출력한다. JavaScript도 마찬가지로 오류가 나면 취합하고 minify된 JS를 출력하고있다. 이럴때 Soucemap을 설정하면, 코드상의 위치를 기억하고 알려주기 때문에 빌드 전 어떤 파일, 라인에서 오류가 났는지 확인할 수 있다. 2. 설정 2.1 Webpack Dev 환경에서만 작동하도록 설정하였다. { "devtool": env.mode === "development" ? "source-map" : "" } 2.2 Typescript { "compilerOptions": { "sourceMap": true } }
2019년 05월 22일
React Native & Expo 특징 React Native div, span 등 웹 태그 사용이 불가능하다. CSS 사용이 가능하다. ( 100% 동일하지는 않으며, Flexbox 사용이 가능 ) 리액트 네이티브가 지원하는 태그는 빌드 시 Android / iOS에 맞게 변환해준다. 오류를 엄격하게 체크한다. CSS shorthand property가 작동하지 않는다. Expo Android, IOS 테스트가 가능하다. 모바일에서 코드를 스캔하여 앱을 다운받고 실시간으로 수정사항 반영이 가능하다. ( Live Reload ) 배포 시 앱을 업데이트 하는 것이 아닌 서버에 코드를 업데이트하는 방식이다. 따라서 앱 스토어의 승인 절차가 필요없고, 유저는 서버에서 코드를 다운받는다. Online Coding : snack.expo.io 설치 Expo Learn npm install expo-cli --global expo init react-native-weather ? Choose a template: expo-template-blank ? Choose which workflow to use: managed ✔ Please enter a few initial configuration values. Read more: https://docs.expo.io/versions/latest/workflow/configuration · 100% completed ? Yarn v1.13.0 found. Use Yarn to install dependencies? Yes Expo 회원가입 및 로그인 expo 회원가입 expo login ? Username/Email Address: ? Password: [hidden] 실행 cd react-native-weather...
2019년 05월 22일
계속 업데이트 되는 문서입니다. LinearGradient 배경색이 그라데이션으로 출력되는 View import { LinearGradient } from "expo"; ... <LinearGradient colors={["red","blue"]} /> Vector-Icons expo 에서 제공하는 여러 폰트의 아이콘 모음이다. 아래 링크에서 아이콘 및 라이브러리를 확인하고 import하면 작동한다. vector-icons import { Ionicons, AntDesign } from "@expo/vector-icons"; ... <Ionicons color="white" size={144} name="ios-rainy" /> Text 태그 내 사용 시 배경색을 투명으로 변경한다. {backgroundColor: "transparent"}
2019년 05월 19일
문제 게임 캐릭터를 4가지 명령어를 통해 움직이려 합니다. 명령어는 다음과 같습니다. U: 위쪽으로 한 칸 가기 D: 아래쪽으로 한 칸 가기 R: 오른쪽으로 한 칸 가기 L: 왼쪽으로 한 칸 가기 캐릭터는 좌표평면의 (0, 0) 위치에서 시작합니다. 좌표평면의 경계는 왼쪽 위(-5, 5), 왼쪽 아래(-5, -5), 오른쪽 위(5, 5), 오른쪽 아래(5, -5)로 이루어져 있습니다. 이때, 우리는 게임 캐릭터가 지나간 길 중 캐릭터가 처음 걸어본 길의 길이를 구하려고 합니다. 예를 들어 위의 예시에서 게임 캐릭터가 움직인 길이는 9이지만, 캐릭터가 처음 걸어본 길의 길이는 7이 됩니다. (8, 9번 명령어에서 움직인 길은 2, 3번 명령어에서 이미 거쳐 간 길입니다) 단, 좌표평면의 경계를 넘어가는 명령어는 무시합니다. 명령어가 매개변수 dirs로 주어질 때, 게임 캐릭터가 처음 걸어본 길의 길이를 구하여 return 하는 solution 함수를 완성해 주세요. 제한사항 dirs는 string형으로 주어지며, ‘U’, ‘D’, ‘R’, ‘L’ 이외에 문자는 주어지지 않습니다. dirs의 길이는 500 이하의 자연수입니다. 해결방법 처음 걸어본 길만 구한다는 것을 중점으로 개발하면 손쉽게 풀린다. 똑같은 길을 걷는 조건은...
2019년 05월 17일
문제 피보나치 수는 F(0) = 0, F(1) = 1일 때, 1 이상의 n에 대하여 F(n) = F(n-1) + F(n-2) 가 적용되는 수 입니다. F(2) = F(0) + F(1) = 0 + 1 = 1 F(3) = F(1) + F(2) = 1 + 1 = 2 F(4) = F(2) + F(3) = 1 + 2 = 3 F(5) = F(3) + F(4) = 2 + 3 = 5 2 이상의 n이 입력되었을 때, n번째 피보나치 수를 1234567으로 나눈 나머지를 리턴하시오. n은 1이상, 100000이하인 자연수입니다. 해결방법 피보나치 함수에서는 인자값으로 들어온 n만큼 재귀호출을 진행한다. F(n) = F(n-1) + F(n-2) 공식을 적용하여 i-1, i-2 를 더하는 공식이다. 재귀 호출방식은 속도가 너무 느리기 때문에 배열에 push하여 계산하는 방식으로 변경하였다. 이때, 조건의 1234567로 나눈 나머지라는 조건을 만족시키기 위해 %1234567을 수식에 넣는다. 소스코드 function fibonacci(num) { let arr = [0, 1]; for (let i = 2; i <= num; i++) { arr.push((arr[i - 1] + arr[i -...
2019년 05월 17일
문제 H-Index는 과학자의 생산성과 영향력을 나타내는 지표입니다. 어느 과학자의 H-Index를 나타내는 값인 h를 구하려고 합니다. 위키백과1에 따르면, H-Index는 다음과 같이 구합니다. 어떤 과학자가 발표한 논문 n편 중, h번 이상 인용된 논문이 h편 이상이고 나머지 논문이 h번 이하 인용되었다면 h가 이 과학자의 H-Index입니다. 어떤 과학자가 발표한 논문의 인용 횟수를 담은 배열 citations가 매개변수로 주어질 때, 이 과학자의 H-Index를 return 하도록 solution 함수를 작성해주세요. 과학자가 발표한 논문의 수는 1편 이상 1,000편 이하입니다. 논문별 인용 횟수는 0회 이상 10,000회 이하입니다. citations : [3, 0, 6, 1, 5], return : 3 이 과학자가 발표한 논문의 수는 5편이고, 그중 3편의 논문은 3회 이상 인용되었습니다. 그리고 나머지 2편의 논문은 3회 이하 인용되었기 때문에 이 과학자의 H-Index는 3입니다. 해결방법 사실 문제를 더 이해하는데 오래걸렸다. h라는 값을 배열 내 데이터에서 찾고있었는데 아니였다. 단순 내림차순 후 반복문을 돌렸을 때 index와 해당 배열의 값을 비교하는 문제였다. 문제를 다시 설명하자면 h편의 논문은 h회 이상, 나머지는 h회 이하 인용이라는 부분은 index를 통하여...
2018년 06월 20일
들어가며 WordPress 란 일반 사용자들도 웹사이트를 구축하고 관리할 수 있도록 도와주는 도구입니다. 워드프레스를 사용하는 경우 두가지로 구분됩니다. 가입형 ( wordpress.com ) 설치형 ( wordpress.org ) 가입형 ( wordpress.com ) 워드프레스가 제공하는 서버 및 DB를 사용하여 웹사이트를 구축합니다. 무료를 포함하여 요금제에 따라 성능이 달라집니다. wordpress 가입형 페이지 - 장점 서버 및 DB 환경이 기본적으로 제공되어 간편하게 사용이 가능합니다. 무료 사용이 가능합니다. 속도가 빠릅니다. 서버관리 및 보안에 신경쓰지 않아도 됩니다. - 단점 워드프레스 규정을 따라야합니다. 플러그인 및 테마에 제약이 있습니다. CSS 수정에 제약이 있습니다. 위 기능을 사용하기위해 요금제를 높이는 경우 많은 요금을 부과해야합니다. wordpress 가입형 요금 설치형 ( wordpress.org ) 사용자가 서버에 직접 워드프레스를 설치하여 웹사이트를 구축합니다. 웹사이트 소유자이기 때문에 제약이 없습니다. wordpress 설치형 페이지 - 장점 테마 및 플러그인을 설치하여 적용이 가능합니다. 모든 기능을 무료로 사용합니다. - 단점 서버 호스팅 및 설치해야하는 불편함이 있습니다. 서버비용이 지출됩니다. 주관적 생각 번거롭더라도 설치형으로 진행하시는 것을 추천합니다. 워드프레스로 블로그 또는 포트폴리오를 제작하는데 있어서, ‘플러그인 및...
2017년 09월 11일
Python 2.x, 3.x # string to int s = "123" n = int(s) # string to float s = "123.456" n = float(s) # string to long s = "1234567890123" n = long(s) 참고사항 위 게시물은 기존에 운영한 Tistory에서 가져온 자료입니다. 시간이 흐름에 따라 오류가 발생하거나 참고사항으로 첨부한 자료가 없을 수 있습니다.
2016년 04월 11일
Python에서 진수 변환을 어떻게 작업하는지를 설명합니다. 10진수 -> 2, 8, 16 진수 변환 2진수 bin( 정수 ) 8진수 oct( 정수 ) 16진수 hex( 정수 ) ex) bin(12345) x진수 -> 10진수 변환 int( 정수, 진수 ) ex) int( 12345, 7 ) -> 7진수 12345를 10진수로 변환 소스코드 if __name__ == "__main__" : num = 12345 print bin(num) # 10진수 -> 2진수 변환 : 0b11000000111001 print oct(num) # 10진수 -> 8진수 변환 : 030071 print hex(num) # 10진수 -> 16진수 변환 : 0x3039 print int(bin(num),2) # 2진수 -> 10진수 변환 : 12345 print int(hex(num),16) # 16진수 -> 10진수 변환 : 12345 참고사항 위 게시물은 기존에 운영한 Tistory에서 가져온 자료입니다. 시간이 흐름에 따라 오류가 발생하거나 참고사항으로 첨부한 자료가 없을 수 있습니다.
2016년 02월 01일
기상청 API를 사용하려면 일반적인 위도, 경도가 아닌 행정구역을 나누는 X, Y (GRID) 좌표를 사용하고 있습니다. 따라서 위도, 경도를 변환해야하는데 기상청에서 제공하는 Open API를 활용하여 변환 작업을 진행합니다. Open API http://www.kma.go.kr/weather/forecast/digital_forecast.jsp ex) http://www.kma.go.kr/weather/forecast/digital_forecast.jsp?x=60&y=127 소스코드 import math def grid(v1, v2) : RE = 6371.00877 # 지구 반경(km) GRID = 5.0 # 격자 간격(km) SLAT1 = 30.0 # 투영 위도1(degree) SLAT2 = 60.0 # 투영 위도2(degree) OLON = 126.0 # 기준점 경도(degree) OLAT = 38.0 # 기준점 위도(degree) XO = 43 # 기준점 X좌표(GRID) YO = 136 # 기1준점 Y좌표(GRID) DEGRAD = math.pi / 180.0 RADDEG = 180.0 / math.pi re = RE / GRID; slat1 = SLAT1 * DEGRAD slat2 = SLAT2 * DEGRAD olon = OLON * DEGRAD olat = OLAT * DEGRAD sn = math.tan(math.pi * 0.25 + slat2 * 0.5) / math.tan(math.pi * 0.25 + slat1 * 0.5) sn = math.log(math.cos(slat1) / math.cos(slat2)) / math.log(sn) sf = math.tan(math.pi *...