isLoad.

Gloomy Store

Frontend Developer's portfolio

Introduce

profile

Dae Young, Lee

199X.11.24

010-4343-1354

plum_flower@naver.com

렌더 최적화
메모이제이션, SEO
백엔드 이해까지

Career

icon UI디자이너&퍼블리셔
(2020.04~2021.04)

icon 프리랜서 웹퍼플리셔
(2021.05~2022.10)

icon 프로덕트개발팀 프론트엔드
(2022.10~2023.07)

icon 클라우드서비스팀 프론트엔드
(2023.08~현재)

총 경력 5년 7개월

Specialty

웹사이트 구축 및 운영

완벽한 반응형 웹개발

프론트개발 디자인 시스템 구축

일본어 비즈니스 대화

영어 메일 의사소통

Education (수료증有)

국민대학교 임산생명공학과 졸업 2018.08

이젠컴퓨터아카데미 UI/UX 과정 2020.02

더조은컴퓨터아카데미 PHP/MySQL 프로그래밍 2021.07

이젠컴퓨터아카데미 React.js 자바스크립트 2021.11

이젠컴퓨터아카데미 React Native 앱개발 2022.04

인프런 프론트엔드 개발환경(webpack, babel...) 2023.05

패스트캠퍼스 Java&Spring 웹 개발 종합반 2023.08

패스트캠퍼스 3D 인터랙티브 (R3F & Three.js) 2024.03

패스트캠퍼스 블렌더로 완성하는 3D 캐릭터 2024.06

Certifications

JLPT N1 - 2022

TOEIC 825 - 2021

웹디자인 기능사 - 2020

TOEIC Speaking 140 - 2019

ITQ Internet A급 - 2018

GTQ Photoshop 1급 - 2017

Skills

HTML5 / CSS3 / JS(ES6) / React / Vue / Nextjs

Nodejs(express) / PHP

MySQL / MongoDB

Photoshop / Illustrator / Xd

Premiere Pro

Character

다정다감하고 누구와도 잘 어울립니다.
내가 맡은 임무는 극한의 책임감을 가지고
끝까지 완수하여 팀원으로서 모범이 됩니다.

Skill
(가로모드로 보면 상세내용이 보입니다)

FE Stack

skills

HTML5

웹표준 및 웹접근성을 준수하며, 최상의 SEO를 위한 태그를 작성합니다. 검색노출을 위한 적절한 타이틀 사용과 최적의 HTML구조, 스크린리더를 위한 정확한 태그사용 등 모든 면에 대응합니다.

skills

CSS3

거의 모든 스타일을 자유자재로 다룰 수 있습니다. 주로 BEM 방법으로 클래스명을 작성합니다.

skills

SASS

반복문과 변수사용 및 코드 중복 방지를 위한 모듈입니다. 체계적으로 SASS를 작성할 경우 다크모드나 기타 상황에서 쉽게 color를 변경 가능합니다. SCSS 문법을 사용합니다.

skills

Bootstrap

스타일시트를 처음부터 제작하기 부담스러운 토이 프로젝트에 가끔 사용합니다.

skills

ES6+

화살표함수, 스프레드연산자, const, let 등을 사용하며, this의 바인딩과 TDZ에 유의하며 스크립트를 작성합니다. ES5 및 ES6 이상의 스펙의 스크립트에 대응합니다. 바벨을 사용하지 않는 환경의 경우, 또한 ie까지 대응하는 경우 ES5 스펙으로 작성합니다. 이벤트 루프를 이해하며, 순서에 맞는 스크립트 작성에 유의합니다.
사실 IE가 사라진 이후로 ES5는 의미가 없어졌어요. ES2024, ES2025등 최신 명세 중에 표준으로 채택되어 크롬 정식버전에서 작동하는 것을 공부하면 되지 않을까 합니다.

skills

React.js

함수형 컴포넌트를 사용합니다. 주로 관심사별로 묶는 스크립트를 작성하며, 개발팀의 코딩 컨벤션에 맞춰서 코드를 만듭니다. 생명주기를 이해하며, 기능이 정확하게, 또 알맞는 타이밍에 작동하도록 스크립트를 작성합니다. 모든 동작은 state로 제어합니다.
물론, useCallback이나 useMemo와 같은 memoization기법을 최대한 활용해서 필요없는 재렌더를 막아 성능최적화도 생각하며 제작합니다. 대량의 reflow로 인해 버벅거릴 정도로 최적화가 필요한 화면에는 useTransition이 조금이나마 도움이 되기도 합니다.

skills

Next.js

SSG, SSR의 장점을 살려, 최대한 Server side에서 많은 정보를 제공하도록 스크립트를 작성합니다. 경우에 따라 SSG나 ISR 활용이 가능합니다.
app router의 경우, client component와 server component가 완전히 분리된 점이 조금 불편하긴 합니다. server component라고는 해도 결국 프론트는 react인데, react hook을 못쓰면 개발 편의성이 떨어지거든요. 그래서 거의 반강제로 Presentational & Container 디자인 패턴으로 가는 것 같아요.

skills

Vue.js

주로 options api를 사용합니다. composition api는 실무에서 사용하는 곳을 아직 경험해보지 못했으나, toy project로 간단하게 다뤄봤습니다. react와 마찬가지로, state로 모든 동작을 제어합니다. vue2 및 vue3 모두 대응합니다.
react의 custom hook 대신, custom directive를 사용하거나, Vue.prototype 혹은 globalProperties에 custom util을 넣어서 사용한다는 점이 차이가 있는 것 같아요. 사실 react나 vue나 프론트 입장에서는 비슷비슷합니다.

skills

Typescript

엄격한 타입 적용을 위해, 컴파일 단계에서 에러를 잡기 위해 사용합니다. 되도록 any를 사용하지 않도록 노력하고 있습니다.

skills

React-query

이제는 tanstack으로 알려진 React query를 서버상태 관리 및 관찰용으로 넣었습니다. fetch의 성공/실패/로딩중 등 관측이 가능하고, 언제 시도했는지, 몇 번째 시도인지 등 서버와의 통신상태를 점검할 수 있습니다.
쿼리변화에 따른 자동fetch나 주기적fetch 등 다양한 기능이 있지만, 일반 프로젝트에서는 사실 fetch만 하고 아무 것도 안할 때도 많으니 오버스펙이라 느껴지기도 합니다.

skills

Redux

전역 상태 관리를 위해 사용하고 있습니다. props가 전달되는 범위가 넓어질 때, redux로 상태관리를 진행합니다.

skills

Recoil

Redux보다 가독성이 훨씬 좋아서 자주 사용합니다. 거의 useState와 비슷하죠. App이 켜질 때 browser storage를 읽어서 상태 초기값을 설정할 수 있다는 점도 매력적입니다.

skills

JQuery

legacy 프로젝트 외에는 크게 사용할 일이 없으나, 종종 jsp로 제작된 프로젝트에 jquery가 사용되고 있어 이 때 사용합니다. 기본적인 ui메소드와 ajax를 사용합니다.

BE Stack

skills

PHP

기본적인 CRUD를 알고있습니다. 게시판 제작 경험이 있으며, 실제 자체 제작 블로그에 PHP가 사용됐던 적이 있습니다. SSR의 개념을 알게해준 고마운 언어입니다.

skills

Node.js

express를 사용하여, 클라이언트에서 오는 각종 요청에 대해 처리합니다. 기본적으로는 PHP와 같이 간단한 CRUD를 처리하며, 클라이언트사이드 언어인 자바스크립트로 서버사이드까지 다룰 수 있는 점에 주목하고 있습니다.
NextJS 등장 이후로는 손이 잘 안가고있습니다.

skills

MySQL

간단한 쿼리문 작성은 스스로 가능합니다.

skills

mongoDB

데이터가 json 그 자체이며, nodejs서버 상에서 객체를 자유롭게 다룰 수 있기 때문에 SQL과 마찬가지로 간단한 CRUD가 가능합니다. SQL과는 달리 별도로 쿼리문을 만들어도 되지 않아서 편리합니다.

skills

Spring

Java 및 Spring 기초교육을 수강한 적이 있어 간단한 Spring 코드는 직접 수정이 가능합니다.

APP Stack

skills

React Native

React Native 컴포넌트를 사용하여 간단한 UI제작이 가능합니다.

Collaboration

skills

Git

github앱이나 git bash, 혹은 fork로 작업물을 관리합니다. 되도록 conflict가 일어나지 않도록 최신 소스를 주기적으로 pull 합니다.

skills

Confluence

프론트 소스의 관리를 위해, 중요 내용은 Confluence에 작성해둡니다. 혹은, 문서를 업로드 해놓습니다.

skills

Github

skills

Jira

모든 작업에 대해 Jira에 내용을 작성 후 진행합니다. 전사적으로 HR이 어떻게 관리되는지 알기 쉽게 하기 위해 되도록 자세한 내용을 작성해 넣어둡니다.

skills

Gitlab

Design Stack

skills

Photoshop

사진사, 디자이너 업무 등으로 포토샵은 10년 이상 다루어 전문가 수준입니다.

skills

Illustrator

벡터그래픽 제작 시 사용합니다.

skills

XD

주로 웹사이트/앱 UI제작 시 사용합니다. 금융권 프로젝트에서 UI제작 시 사용했습니다.

skills

Zeplin

디자이너들이 작업해놓은 UI를 보고 개발에 옮깁니다.

skills

Figma

기능과 UI가 XD와 흡사하여, 어렵지 않게 기능을 다룰 수 있습니다.

Deployment

skills

개인서버

본 포트폴리오 및 모든 작업물은 자택 개인서버에 띄워져 있습니다. nginx로 리버스 프록시를 적용하여, domain.com/ 은 프론트 서버에, domain.com/api/는 api 서버에 연결되도록 포트번호를 지정합니다.
Javascript 프로젝트의 경우, 프론트와 서버 둘 다 pm2로 띄워져있습니다.

skills

Jenkins

배포 자동화 구축 경험이 있습니다. 예를 들면, SVN 커밋을 감지하고 변동내역이 있으면 5분에 한 번씩 배포한다던지, 특정 Git Branch를 매개변수로 배포하면 mv로 작업물을 덮어씌운 뒤 pm2 reload로 프로세스를 다시 띄우거나 하는 것 말이죠.

Gloomy Blog

img
Concept풀스택 개발 블로그, 싸이월드
FrontendNext.js 15(app router), React 19, typescript
BackendNext.js 15(app router), typescript
Deployment개인서버, pm2
제작참여도100%
사용하는 법블로그에 들어가서 다양한 프론트엔드 기술을 구경합니다.
원한다면, 댓글을 남기거나 좋아요를 누를 수 있습니다.

광고제거 extension을 키고 접근하시는 것을 권장합니다.
포트폴리오 설명

프론트엔드

content image이제는 볼 수 없는, 그리운 싸이월드를 되살린 컨셉의 개발 블로그 입니다.

명색이 개발자인데, 네이버나 티스토리같은 기성품보다는 블로그 시스템 자체를 제가 만들어보고 싶었어요.

content image글쓰기 기능이 생각보다 어려웠던 기억이 납니다. 코드에디터와 코드 하이라이팅 기능이 들어가야하는데, 에디터 자체를 만드는 것은 상당히 시간을 많이 잡아먹는 일이었기에 summernote라는 WISYWIG editor로 구현을 했습니다.

다만 커스텀해야할 기능이 많이 있었기에 (code highlighter 포함) 글 작성 기능에 상당한 시간이 걸렸습니다.

이미지는 첨부하자마자 바로 webp로 변환하여 서버에 저장합니다.

content image블로그에 존재하는 모든 내용은 ServerSide Rendering으로 구현됩니다.

이미 클라이언트에 도착한 시점에 모든 HTML이 완성되어 있으니,
검색엔진 최적화에 큰 도움이 될거라 생각하고 있습니다.

content imagePC버전 기준으로, lighthouse로 채점해본 web vital은 거의 만점에 가깝습니다.
다들 성능최적화 한다고 쉽게 말은 해도,
어떤걸 최적화하는지, 구체적으로 뭘 해야 하는지 모르는 경우가 많으니깐요.

제가 아는 FE최적화 지식은 다 욱여넣은 것 같아요.
거의 모든 코드에 Memoization을 적용시켜서 웬만하면 재렌더는 일어나지 않습니다.
폭풍같은 작업량이었지만, 즐거웠습니다.

자택 서버가 좀 더 성능이 우수한 고가 제품이었다면, 점수가 더 잘나왔을지도 모르겠습니다.

백엔드

CRUD: 글 작성, 댓글 작성으로 INSERT INTO를, 글 수정, 댓글 수정으로 UPDATE SET을, 임시글이 정식 포스트가 될 때 임시글 DELETE를, 거의 모든 데이터 조회에 SELECT를, 쿼리문은 원없이 사용해본 것 같습니다.

이외에 이미지 첨부시 바로 webp로 전환해서 temp 이미지 폴더에 넣는기능, 임시 저장글이 정작글로 포스팅 될 때 temp image dir에서 정식 이미지 dir 옮기는 기능, 정규식으로 포스팅 내용의 <img> 태그를 읽어서 정식 이미지 dir로 src 내용을 바꾸는 기능이 들어가 있습니다.

JWT: 로그인 기능 개발을 위해 도입했습니다. 토큰이 이상하면 400을 보내고, 토큰이 파기날짜가 되었으면 403을 보냅니다.
어느 쪽이든, 프론트에서는 자동 로그아웃 기능을 적용시킵니다.

게시판이라는 것이 생각보다 복잡하고
경우의 수가 너무나도 많다는 것에 놀랐습니다.

조금 아쉬웠던 점은, 블로그라는 것은 실시간 데이터를 보여주는 시스템이다보니
SSG, ISR 같은 캐싱 전략을 활용할 기회가 적었습니다.

Dark Theme Force Maker

img
Concept다크모드 강제 적용
Frontendvanilla script
DeploymentChrome Webstore
제작참여도100%
실시간 사용자0 (천 단위 집계)
사용하는 법
https://chromewebstore.google.com/detail/dark-theme-force-maker/pelncmdhgomdkkfnjoljamoepofllaln?authuser=0&hl=ko
에 접속하여 확장 프로그램을 설치합니다.
(chromium 기반 모든 브라우저 사용 가능)

개요

기본적으로 다크모드로 생활을 하는 사람들이 있습니다.
바로 제가 그러한 경우이죠.

핵심은 lightness를 계산하는 기능입니다.
#000 => rgb(0, 0, 0) => hsl(0, 0, 0)로 변경해서, 배경이 어두우면 그대로 두고, 밝으면 어둡게 바꿉니다.

// 16진수 색상을 RGB로 변환하는 함수
      function hexToRgb(hex) {
        hex = hex.replace('#', '');
        if (hex.length === 3) {
          hex = hex.split('').map(x => x + x).join('');
        }
        const bigint = parseInt(hex, 16);
        return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
      }

      // RGB를 HSL로 변환하는 함수
      function rgbToHsl(r, g, b) {
        r /= 255;
        g /= 255;
        b /= 255;
        
        const max = Math.max(r, g, b);
        const min = Math.min(r, g, b);
        const l = (max + min) / 2;
        let h, s;
        
        if (max === min) {
          h = s = 0; // 무채색
        } else {
          const d = max - min;
          s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
          switch (max) {
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
          }
          h /= 6;
        }
        
        return [h, s, l];
      }
      


return 값을 [h, s, l]로 빼낼 필요는 없지만(l만 이용하기 때문),
추후 색상은 살리고 밝기만 어둡게 하는 기능을 추가할 예정이기 때문에 hue와 saturation도 return하게 제작했습니다.

content image

위와 같이 동작합니다.
한 번 동작을 일으키면, localStorage에 다크모드 적용 여부를 저장해둡니다.

manifest.json은 PWA에도 사용되지만,
이렇게 크롬 웹스토어에서 이 APP이 어떤 APP인지 정보를 담는 역할도 합니다.

브라우저 엔진으로 chromium을 사용하는 모든 브라우저에 대응합니다.
(chrome 객체 사용 가능한 브라우저 - chrome.runtime, chrome.tabs 등)

단, DOM 요소 중 iframe이나 shadowDom이 다른 도메인을 가지고 있다면,
Cross Origin 보안 작동으로 인해 적용이 안됩니다.

react-tag-maker

img
Concept태그 만들기
FrontendESModule, typescript, react
DeploymentNPM Library
제작참여도100%
다운로드 수1235
사용하는 법
npm i react-tag-maker
로 설치합니다.
import GloomyTags from 'react-tag-maker';
      
react에서는 해당 예시와 같이 사용할 수 있습니다.
Module 설명

개요

요즘 게시판이나 커뮤니티 등에는 전부 태그가 들어가죠?
useState를 선언하는 것만으로 쉽게 태그를 배열로 받을 수 있습니다.

import GloomyTags from 'react-tag-maker';

      function App() {
        const [state, setState] = useState([]);

        return (
          <GloomyTags
            state={state}
            setState={setState}
          />
        );
      }

      export default App;
      


props는 매우 간단합니다.
그냥 state와 setState 두 개만 넣으세요.

react-tag-maker

결과물은 ['show', 'me', 'the', 'money'] 와 같은 배열로 만들어집니다.



배포

npm publish로 배포합니다.

npm i react-tag-maker


Reactjs는 물론, Nextjs client component도 대응합니다.
typescript, 일반 js 둘 다 대응합니다.

자매품으로 vue-tag-maker(다운로드 수: 1765)도 만들었어요.



체험해보기

Portfolio - 글루미채팅

img
ConceptwebRTC 영상통화 + websocket채팅 + OAuth 로그인
FrontendNext.js 13
BackendNode.js(express, socket.io)
DatabasemongoDB
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(10%)
사용방법한 명은 id: admin, pw: admin으로 로그인,
한 명은 id: admin2, pw: admin2으로 로그인,
서로 영상통화와 채팅을 즐겨봅시다.

원한다면 google이나 github 소셜 로그인도 가능합니다.
포트폴리오 설명

프론트엔드

채팅: 채팅 기능의 핵심은 웹소켓입니다. 소켓에 메세지를 emit하면, 웹소켓 서버에서 해당 방에 참여한 모든 이들에게 broadcast해주고, broadcast 받은 클라이언트들은 모두 새로운 메세지를 받게되는 형태입니다.

화상통화: 2개의 PEER, 시그널 서버, TURN서버가 주 핵심요소입니다. 최초 동작시, 웹소켓으로 만들어진 시그널 서버에 sdp정보를 보내어 PEER끼리 서로 정보를 주고받습니다. 이후 서로 주고받은 sdp를 토대로 STUN서버 (stun:stun.google.com:19302)에 중계요청을 보내며, 중계기로부터 받은 영상데이터 혹은 PEER에게 직접 받은 영상데이터를 video태그에 재생시킵니다.

백엔드

채팅: 서버에서는 웹소켓 connection이 일어나면 클라이언트에서 받은 uuid를 토대로 방을 생성합니다. 이제 그 uuid로 전달된 메세지를 해당 방에 참가한 사람들에게 broadcast해줍니다.

화상통화: 시그널 서버는 클라이언트로부터 받은 sdp 정보를 상대방 peer에게 전송하여, 서로 연결을 잘 수립할 수 있도록 합니다. 이후 STUN서버나 TURN서버를 통해 Interaction Connection Establishment 후보를 찾고, 서로의 PEER간 연결이 수립되면, 그 이후부터는 서버의 역할이 매우 작아집니다.
단, TURN서버의 경우 직접 구축하는 것이 어려웠기 때문에 google 공개도메인을 사용했습니다.

OAuth: NextAuth 라이브러리를 통해 구현합니다. 사용자(Resource Owner)는 현 프로젝트의 인증서버에 인증 요청을 보냅니다. 그후 인증서버는 구글의 Resource 서버에 요청을 보내게 되고, Resource Owner의 인증을 위임받은 구글서버에 의해 인증서버에는 사용자의 정보(이름, 메일)이 도착하여 토큰화되어 사용할 수 있게 됩니다.

Portfolio - 글루미투표

img
ConceptPWA(Progressive Web App), react query, mysql, nextjs13, 쿠키, 카카오 공유
FrontendNext.js 13, React-query(서버상태관리)
BackendNext.js 13
DatabaseMariaDB (MySQL)
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(100%)
사용방법사용자의 정보는 접속해서 쿠키를 허용하는 순간부터 고유한 아이디로 저장됩니다.
이제 투표를 만들고, 카카오톡으로 공유해보세요!

정말 쉽습니다. 그냥 투표를 제작하고, 링크를 뿌려보세요.

자유로운 익명투표의 시작입니다.
포트폴리오 설명

프론트엔드

content image우선 getServerSideProps로 해당 투표의 uuid를 토대로, 투표 데이터가 있는지 확인 후 없으면 custom 404페이지로 안내합니다.

content image존재한다면 실제 투표페이지로 안내합니다.
투표 데이터는 React Query를 통해서 fetch 하며, 데이터가 정상적으로 송/수신 되고 있는지 React-query devtool을 통해 관찰할 수 있습니다.

이 프로젝트는 Build하지 않고, React Query devtool을 보여주기 위해 pm2 - npm run dev로 .env.development 환경으로 돌리고 있는 상태입니다. (꽃 이미지)

content image투표를 간편하게 생성 가능하며, 언제든지, 자유롭게 생성 가능합니다.

content image투표를 하면, 바로 DB에 내용이 업데이트 되고, react query에 설정된 의존성 배열에 의해 한 번 더 fetch를 거치게 됩니다. 이후 투표 결과 화면이 송출됩니다.

나의 데이터는 쿠키에 저장되어있으며, (랜덤으로 배정된 고유한 uuid를 마치 id처럼 사용) 내가 이미 투표를 했으면 투표 결과를 보여줍니다.

content imagecontent image복사하기 및 카카오 공유가 가능합니다.
모바일, PC 어느쪽이든 쉽게 투표 URL을 공유할 수 있습니다.

백엔드

content imagecontent imageDB: 비록 백엔드 전문가는 아니나, 나름대로 DB를 설계도 해보고 효율적인 환경을 구축하기 위해 연구했습니다.

vote table: 투표의 개요를 저장합니다.
votemenu table: 해당 투표의 보기를 저장합니다. parentid로 vote table의 uuid를 추적합니다.
voter table: 투표자들이 어떤 보기에 투표했는지 저장합니다. 몇 번 보기의 index를 선택했는지만 저장하면 됩니다.

백엔드에서는 이를 정제하지 않고 전부 클라이언트로 보내서, 클라이언트에서 알아서 데이터를 정제해서 map으로 뿌려줍니다.

Nextjs API: 크게 네 가지 기능으로 나뉩니다.

1. 단순히 투표 DB내용을 클라이언트로 쏴주는 기능
2. 쿠키 데이터가 있는 사용자에 한해서, 내가 만든 투표방을 보여주고, 내가 선택한 투표 보기에 [선택함]을 노출시켜 줍니다.
다만 쿠키가 제거되면 이는 모두 사용할 수 없게 됩니다.
3. 투표 삭제하기 기능: bcrypt를 사용해서 암호화 및 verify를 실행합니다. 올바른 비밀번호를 입력하면, 투표가 실제로 삭제됩니다.
특정 Flag를 만들어서 투표를 비노출 시키는 방법도 있으나, 투표 row가 무한이 늘어나는 것을 방지하기 위해 실제 row를 삭제하는 방법을 채택했습니다. 집에 비싼 서버가 있고 전기세 감당이 된다면 전자의 방법을 택할 수도 있습니다.
4. 투표 관측기간이 지나면, scheduler가 24시간에 한 번씩 실제 row를 삭제하여 더이상 투표를 볼 수 없게 합니다.
node-cron vs node-schedule 둘 중에 고민을 많이 했으나, 사용자가 많은 후자를 택했습니다.

ES Module - GloomyDate

img
Concept손쉬운 날짜계산
FrontendES Module
DeploymentNPM, 자택 개인서버(NAS)
제작참여도100%
다운로드 수1453
사용하는 법
npm i gloomydate
로 설치합니다.

      import {gloomyDate} from 'gloomydate'
      useEffect(()=>{
        gloomyDate.date('2022-05-10 08:40:20') 
          // expected returns string '1년 전'
      },[])
      
react에서는 해당 예시와 같이 사용할 수 있습니다.
Module 설명

개요

게시판, 댓글 등에서 일일이 날짜를 계산하기 어려웠을 경우, string을 gloomyDate.date(str)에 담는 것만으로 이 게시글이 며칠전에 작성됐는지 return합니다.

개발자는 간편하게 날짜를 bind할 수 있습니다!


      function App() {
        const [data,setData] = useState([
          { title: 'title1', date:  gloomyDate.date('2022-05-10 10:55:40')}, 
          { title: 'title2', date:  gloomyDate.date('2023-02-11 15:50:30')},
          { title: 'title3', date:  gloomyDate.date(new Date())},
          { title: 'title4', date:  gloomyDate.date(Number(new Date()) + 1000)},
        ])

        return (
          <div className='list'>
            {
              data.map((elm,idx)=>
              <div key={idx}>
                <p className='title'>{elm.title}</p>
                <p className='date'>{elm.date}</p> {/* expected: XX 전 */}
              </div>
              )
            }
          </div>
        );
      }
      


예상 출력결과

title1
      1년 전

      title2
      2달 전

      title3
      방금 전

      title4
      잠시 후
      



배포

npm publish로 배포합니다.

npm i gloomydate

로 설치할 수 있습니다.

모듈 번들러(웹팩 등)에 대응하기 위해 es module형태로 제작했으며, tree shaking에 대응하기위해 추후 모듈의 기능이 늘어날 경우 named export로 제작할 예정입니다.

(현재는 모듈 기능이 하나뿐이라 tree shaking이 크게 의미를 가지지 않음)

일반 HTML 프로젝트의 경우

<script src='https://cdn.gloomystore.com/gloomyDate/gloomyDate.js'></script> 
      

로 commonJS에 대응합니다.

react의 예시와 동일하게 사용가능합니다.



3개 국어에 대응하며, 3가지 타입의 데이터 input을 지원합니다.

gloomyDate.date('2023-04-26 08:10:22','en') // formatted string
      gloomyDate.date('20230426081022','jp') // string
      gloomyDate.date(1723722833597,'ko') // number
      gloomyDate.date((new Date()),'ko') // Date
      

'ko', 'jp', 'en'
3개 국어에 대응합니다.

예상되는 결과:

2days ago
      2日前
      2일 전
      방금 전
      

아무 인자도 넣지 않을 경우 'ko'가 default로 작동합니다.

14 length의 string, number에 대응하며,
'YY-mm-dd H:i:s' 형태의 string에도 대응합니다.

Portfolio - 글루미스토어

img
ConceptNext.js Hydrating
FrontendNext.js 15, Typescript, App Router
BackendNext.js 15, Typescript, MySQL
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%)
포트폴리오 설명

프론트엔드

기존의 CSR형식의 SPA는 검색노출이 어렵고, 설령 구글 검색로봇이라 하더라도 웹서버상에서 index.html을 받았을 때 빈문서 이외에는 내용이 나오지 않습니다.

이러한 점을 해결하기 위해 Next.js의 SSG에 주목했으며, JSX가 서버사이드상에서 이미 html태그로 렌더된 상태로 전송이 되기 때문에 현 포트폴리오의 검색 노출이 더 잘될 것으로 기대하고 있습니다.

최하단 Today, Total은 pages/api 폴더 내에 제작해둔 api를 page에서 GetServerSideProps로 받아오며, DB에 오늘날짜의 테이블이 없다면 오늘 방문자 0명으로 INSERT합니다.
아! app router에서는 fetch action을 GetServerSideProps로 하지는 않겠군요.
cache 설정을 하지 않았으니 pages router의 GetServerSideProps와 유사하게 동작합니다.

이미지, 폰트 등 모든 컨텐츠가 로딩되고, ajax에서 return을 받아오면 비로소 로딩화면이 사라집니다.
(개발자 도구에서 네트워크를 3G로 하고 강력 새로고침을 하면 로딩화면을 볼 수 있습니다.)

백엔드

서버에서 사용하는 것은 오늘 날짜의 today hit, total hit을 구하는 것입니다.

시간 기준은 클라이언트 기준이 되어야하기 때문에, 클라이언트에서 한국시간을 구해줍니다.
(new Date()에서 9 * 60 * 60 * 1000를 더함)

시간은 보안정보가 아니기 때문에 get요청으로 parameter에 붙여서 보내줍니다.


      const [rows] = await pool.query<RowDataPacket[]>('SELECT * FROM visitor_today WHERE REGDATE='${'todayDate'}'');
      const [rows2] = await pool.query<RowDataPacket[]>('SELECT * FROM visitor_total WHERE REGDATE='${'todayDate'}'');
      // const count = rows;
      res.status(200).json([...rows,...rows2]);
      



api에서는 DB에 오늘날짜의 테이블이 없다면 오늘 방문자 0명으로 INSERT합니다. 만약 존재한다면 오늘 방문자의 배열을 가져와서 클라이언트로 return합니다.





Experimental...

가볍게 만들어보고 있는 토이프로젝트입니다.

img
Concept풀스택 쇼핑몰(MERN스택)
FrontendReact.js
BackendNode.js, PHP
DatabasemongoDB
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(100%), 호스팅(100%), 도메인 구매, 검색광고등록(100%)
사용방법실제 쇼핑몰입니다. 결제까지 전부 진행됩니다. 구매가 완료되면, SMS와 이메일로 구매내역이 날아갑니다. (PHP mailer 및 naver SMS API)
img
Concept풀스택 호텔예약
FrontendReact.js
BackendPHP
DatabaseMariaDB (MySQL)
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(100%)
사용방법id: admin, pw: admin으로 로그인 후,
호텔 예약을 진행해봅니다. 이메일을 본인 메일로 넣을 경우, 예약 내역이 전송됩니다.
img
ConceptCSS 3D Effect, Mouse Pointer Offset
FrontendNext.js 13
제작참여도100%
img
Concept실시간 온라인 게임
FrontendReact, vite, R3f
BackendExpress, socket.io
Deployment자택 개인서버(NAS)
제작참여도100%

오픈소스 기여

Fix incorrect Korean translation for MULTIPLE_ERRORS string

설명 Adobe Brackets(전신) 였던 피닉스 에디터입니다. 국제화 관련 코드를 수정하여 PR을 올렸고, 승인 되었습니다.
상태 MERGED
날짜 2025-03-26 20:18:06.000Z
github https://github.com/phcode-dev/phoenix/pull/2189