<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_29.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 09 Jul 2025 08:56:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. dev_29.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_29" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[💻 Puppeteer로 프로그래머스 문제 제목 & 링크 전체 긁어오기 (CSV 저장까지!)]]></title>
            <link>https://velog.io/@dev_29/Puppeteer%EB%A1%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%AC%B8%EC%A0%9C-%EC%A0%9C%EB%AA%A9-%EB%A7%81%ED%81%AC-%EC%A0%84%EC%B2%B4-%EA%B8%81%EC%96%B4%EC%98%A4%EA%B8%B0-CSV-%EC%A0%80%EC%9E%A5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@dev_29/Puppeteer%EB%A1%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%AC%B8%EC%A0%9C-%EC%A0%9C%EB%AA%A9-%EB%A7%81%ED%81%AC-%EC%A0%84%EC%B2%B4-%EA%B8%81%EC%96%B4%EC%98%A4%EA%B8%B0-CSV-%EC%A0%80%EC%9E%A5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Wed, 09 Jul 2025 08:56:29 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스 코딩테스트는 문제에 번호가 없다.
그래서 내가 어디까지 풀었는지, 오늘은 어디서부터 어디까지 풀지 계획 세우는 게 쉽지 않았다.</p>
<p>매일 딱 30분만 투자해서 문제를 풀고 싶은데…
일단 코딩 기초 트레이닝은 총 124문제뿐이니까
처음엔 그냥 하나씩 받아쓰기해서 목록 만들까 했었다.</p>
<p>근데 문득 생각났다.</p>
<p>“웹스크롤링으로 긁어오면 되잖아?”</p>
<p>사실 웹스크롤링에 대해서는
“뭔가를 긁어오는 거?” 정도만 알고 있었다.
근데 챗GPT랑 같이 얘기하며 코드 짜봤더니
금방 원하는 결과물이 나왔다.
이게 바로… 바이브코딩인가? 😎</p>
<hr>
<h2 id="🎯-목표">🎯 목표</h2>
<ul>
<li>프로그래머스 코딩 기초 트레이닝 문제 <strong>7페이지(총 124문제)</strong> 긁어오기</li>
<li>제목 + 링크를 모아서 <strong>CSV 파일로 저장</strong></li>
</ul>
<hr>
<h2 id="🧑💻-최종-코드">🧑‍💻 최종 코드</h2>
<pre><code class="language-js">const puppeteer = require(&quot;puppeteer&quot;);
const fs = require(&quot;fs&quot;);

(async () =&gt; {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();

  const allTitles = [];
  const totalPages = 7;

  for (let currentPage = 1; currentPage &lt;= totalPages; currentPage++) {
    const url = `https://school.programmers.co.kr/learn/challenges/training?order=acceptance_desc&amp;languages=javascript&amp;page=${currentPage}`;
    console.log(`📄 페이지 ${currentPage} 로딩 중...`);

    await page.goto(url, {
      waitUntil: &quot;networkidle2&quot;,
      timeout: 120000,
    });

    await new Promise((resolve) =&gt; setTimeout(resolve, 2000));

    const titles = await page.$$eval(&quot;td.title a&quot;, (elements) =&gt;
      elements.map((el) =&gt; ({
        title: el.innerText.trim(),
        link: el.href,
      }))
    );

    console.log(`✅ 페이지 ${currentPage}에서 ${titles.length}개 수집`);
    allTitles.push(...titles);
  }

  console.log(`\n📦 모든 문제 제목 (총 ${allTitles.length}개):`);
  allTitles.forEach((title, index) =&gt; {
    console.log(`${index + 1}. ${title.title}`);
  });

  await browser.close();

  const csvHeader = &quot;번호,제목,링크\n&quot;;
  const csvContent = allTitles
    .map((p, i) =&gt; `${i + 1},&quot;${p.title}&quot;,&quot;${p.link}&quot;`)
    .join(&quot;\n&quot;);
  fs.writeFileSync(&quot;programmers_problems.csv&quot;, csvHeader + csvContent, &quot;utf-8&quot;);

  console.log(`💾 CSV 저장 완료: programmers_problems.csv`);
})();</code></pre>
<hr>
<h2 id="😅-삽질의-시작">😅 삽질의 시작</h2>
<h3 id="🐛-npm-init에서-에러-터짐">🐛 npm init에서 에러 터짐</h3>
<p>처음 <code>npm init -y</code> 했더니 이러더라.</p>
<pre><code>npm ERR! Invalid name: &quot;코딩202507&quot;</code></pre><p>한글 폴더명 때문에 npm이 삐짐…
바로 폴더명을 <code>coding-2507</code>으로 바꿔서 해결했다.</p>
<hr>
<h3 id="🐌-페이지-로딩-timeouterror">🐌 페이지 로딩 TimeoutError</h3>
<p>첫 실행 때 이 에러가 떴다.</p>
<pre><code>TimeoutError: Navigation timeout of 60000 ms exceeded</code></pre><p>Puppeteer가 페이지의 모든 요청이 끝나길 기다리느라 타임아웃 걸림.
해결법은 간단했다.</p>
<ul>
<li><code>waitUntil: &quot;networkidle0&quot; → &quot;networkidle2&quot;</code></li>
<li><code>timeout: 120000</code>으로 늘림</li>
<li>그리고 <code>headless: false</code>로 실제 브라우저 켜서 동작 확인</li>
</ul>
<hr>
<h3 id="📄-페이지-1번만-긁힘">📄 페이지 1번만 긁힘</h3>
<p>아무리 돌려도 1페이지 20문제만 긁힘.
URL에 <code>page=1</code>이 박혀있던 걸 발견하고 for문으로 1~7페이지 순회하도록 수정했다.</p>
<pre><code class="language-js">for (let currentPage = 1; currentPage &lt;= totalPages; currentPage++) {
  const url = `...page=${currentPage}`;
  await page.goto(url, ...);
}</code></pre>
<hr>
<h3 id="❌-csv에-undefined-뜸">❌ CSV에 undefined 뜸</h3>
<p>이번엔 CSV 결과가 이 모양:</p>
<pre><code>&quot;문제제목&quot;,&quot;function link() { [native code] }&quot;</code></pre><p>원인은 두 가지였다.</p>
<ul>
<li><code>el.textContent</code>가 동작 안 함 → 동적 페이지라서</li>
<li><code>el.getAttribute(&quot;href&quot;)</code> 대신 함수 참조가 찍힘</li>
</ul>
<p>고친 방법:</p>
<pre><code class="language-js">title: el.innerText.trim(),
link: el.href,</code></pre>
<p>바꿨더니 깔끔하게 제목+링크 출력됨.</p>
<hr>
<h3 id="🚨-referenceerror-fs-is-not-defined">🚨 ReferenceError: fs is not defined</h3>
<p>마지막으로 <code>fs.writeFileSync()</code> 썼더니:</p>
<pre><code>ReferenceError: fs is not defined</code></pre><p>fs 모듈을 import 안 해서 생긴 실수였다. 상단에 추가로 해결.</p>
<pre><code class="language-js">const fs = require(&quot;fs&quot;);</code></pre>
<hr>
<h2 id="📦-결과물">📦 결과물</h2>
<p>최종적으로 나온 <code>programmers_problems.csv</code></p>
<table>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>링크</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>문자 리스트를 문자열로 변환하기</td>
<td><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181941">https://school.programmers.co.kr/learn/courses/30/lessons/181941</a></td>
</tr>
<tr>
<td>2</td>
<td>홀짝에 따라 다른 값 반환하기</td>
<td><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181944">https://school.programmers.co.kr/learn/courses/30/lessons/181944</a></td>
</tr>
</tbody></table>
<p>엑셀로 열면 바로 링크 클릭 가능 👍</p>
<hr>
<h2 id="✨-배운-것">✨ 배운 것</h2>
<ul>
<li>Puppeteer에서 동적 페이지는 <code>innerText</code>, <code>href</code>로 접근해야 안전</li>
<li><code>networkidle2</code> + <code>setTimeout</code> 조합으로 로딩 안정화</li>
<li>페이지네이션은 쿼리 파라미터로 간단히 처리 가능</li>
<li>npm 패키지 이름은 영어 소문자 + 숫자 + 하이픈만</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/dev_29/post/7a6d826e-cd3b-4c9d-91ed-e7c5bb13a656/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/31e002a8-043f-466b-ac23-ebf65db5831a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[`filter()`랑 `find()`가 함께 나오는 구조]]></title>
            <link>https://velog.io/@dev_29/filter%EB%9E%91-find%EA%B0%80-%ED%95%A8%EA%BB%98-%EB%82%98%EC%98%A4%EB%8A%94-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@dev_29/filter%EB%9E%91-find%EA%B0%80-%ED%95%A8%EA%BB%98-%EB%82%98%EC%98%A4%EB%8A%94-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Fri, 27 Jun 2025 08:40:47 GMT</pubDate>
            <description><![CDATA[<h2 id="✅-예제-고양이-중에서-나이가-3살-이상인-고양이만-뽑기">✅ 예제: 고양이 중에서 나이가 3살 이상인 고양이만 뽑기</h2>
<pre><code class="language-js">const cats = [
  { name: &quot;나비&quot;, age: 2 },
  { name: &quot;미미&quot;, age: 4 },
  { name: &quot;초코&quot;, age: 3 },
  { name: &quot;망고&quot;, age: 1 }
];

const targetNames = [&quot;초코&quot;, &quot;미미&quot;, &quot;망고&quot;];

function checkAge(names, minAge) {
  return names.filter(name =&gt; {
    const cat = cats.find(c =&gt; c.name === name);
    return cat &amp;&amp; cat.age &gt;= minAge;
  });
}

console.log(checkAge(targetNames, 3)); // [&quot;초코&quot;, &quot;미미&quot;]</code></pre>
<hr>
<h3 id="🧠-구조-다시-설명">🧠 구조 다시 설명</h3>
<pre><code class="language-js">names.filter(name =&gt; {
  const cat = cats.find(c =&gt; c.name === name); // 이름으로 고양이 찾고
  return cat &amp;&amp; cat.age &gt;= minAge;             // 나이가 조건보다 크면 OK
});</code></pre>
<hr>
<p>책이든 사람 목록이든 <strong>&quot;이름 배열 + 실제 정보 배열&quot;</strong> 구조일 때 자주 나오는 패턴</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[find함수]]></title>
            <link>https://velog.io/@dev_29/find%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@dev_29/find%ED%95%A8%EC%88%98</guid>
            <pubDate>Fri, 27 Jun 2025 07:24:39 GMT</pubDate>
            <description><![CDATA[<p><code>find()</code>는:</p>
<blockquote>
<p><strong>배열에서 조건을 &quot;처음으로&quot; 만족하는 딱 하나만 찾아줌!</strong></p>
</blockquote>
<hr>
<h2 id="✅-기본-문법">✅ 기본 문법</h2>
<pre><code class="language-js">배열.find(요소 =&gt; 조건)</code></pre>
<hr>
<h2 id="✅-예제-1-짝수-중-첫-번째-찾기">✅ 예제 1: 짝수 중 첫 번째 찾기</h2>
<pre><code class="language-js">const numbers = [1, 3, 4, 6, 8];

const firstEven = numbers.find(num =&gt; num % 2 === 0);

console.log(firstEven); // 👉 4 (처음으로 짝수인 값)</code></pre>
<hr>
<h2 id="✅-예제-2-이름이-지민인-사람-찾기">✅ 예제 2: 이름이 &#39;지민&#39;인 사람 찾기</h2>
<pre><code class="language-js">const people = [
  { name: &quot;태형&quot;, age: 25 },
  { name: &quot;지민&quot;, age: 24 },
  { name: &quot;정국&quot;, age: 23 }
];

const person = people.find(p =&gt; p.name === &quot;지민&quot;);

console.log(person); // 👉 { name: &quot;지민&quot;, age: 24 }</code></pre>
<hr>
<h2 id="✅-filter랑-차이점은">✅ filter랑 차이점은?</h2>
<table>
<thead>
<tr>
<th>함수</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td><code>find()</code></td>
<td>조건 맞는 <strong>하나(첫 번째)</strong> 객체</td>
</tr>
<tr>
<td><code>filter()</code></td>
<td>조건 맞는 <strong>모두</strong>를 배열로</td>
</tr>
</tbody></table>
<hr>
<h2 id="✅-요약-한-줄">✅ 요약 한 줄</h2>
<blockquote>
<p><code>find()</code>는 &quot;첫 번째 조건 일치하는 것&quot; <strong>딱 하나만</strong> 찾아줌!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[filter문법]]></title>
            <link>https://velog.io/@dev_29/filter%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@dev_29/filter%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Fri, 27 Jun 2025 07:22:10 GMT</pubDate>
            <description><![CDATA[<h2 id="✅-filter란">✅ filter란?</h2>
<p><strong>배열에서 &quot;조건을 만족하는 애들만 골라서&quot; 새 배열로 만드는 함수</strong></p>
<hr>
<h2 id="✅-기본-문법">✅ 기본 문법</h2>
<pre><code class="language-js">배열.filter(요소 =&gt; 조건)</code></pre>
<hr>
<h2 id="✅-예제">✅ 예제</h2>
<pre><code class="language-js">const numbers = [1, 2, 3, 4, 5];

const even = numbers.filter(num =&gt; num % 2 === 0);

console.log(even); // 👉 [2, 4]</code></pre>
<p>🧠 <code>num % 2 === 0</code> → 짝수인 애들만 남긴다</p>
<hr>
<h2 id="✅-예제-2-이름이-민으로-끝나는-친구만-남기기">✅ 예제 2: 이름이 &quot;민&quot;으로 끝나는 친구만 남기기</h2>
<pre><code class="language-js">const names = [&quot;지민&quot;, &quot;태형&quot;, &quot;유민&quot;, &quot;정국&quot;];

const filtered = names.filter(name =&gt; name.endsWith(&quot;민&quot;));

console.log(filtered); // 👉 [&quot;지민&quot;, &quot;유민&quot;]</code></pre>
<hr>
<h2 id="✅-핵심-정리">✅ 핵심 정리</h2>
<table>
<thead>
<tr>
<th>개념</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>filter</td>
<td>배열에서 <strong>원하는 것만 고르기</strong></td>
</tr>
<tr>
<td>결과</td>
<td><strong>원본 배열은 그대로</strong>, 새 배열을 만들어 줌</td>
</tr>
<tr>
<td>언제 쓰냐?</td>
<td>&quot;이 중에 ○○만 남기고 싶다!&quot; 할 때</td>
</tr>
</tbody></table>
<hr>
<p>한 문장 요약:
👉 <strong>&quot;필터는 배열 거르기!&quot;</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Day02]배열의 마지막 숫자를 꺼내는 공식+반복문 복습]]></title>
            <link>https://velog.io/@dev_29/Day02%EB%B0%B0%EC%97%B4%EC%9D%98-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%88%AB%EC%9E%90%EB%A5%BC-%EA%BA%BC%EB%82%B4%EB%8A%94-%EA%B3%B5%EC%8B%9D%EB%B0%98%EB%B3%B5%EB%AC%B8-%EB%B3%B5%EC%8A%B5</link>
            <guid>https://velog.io/@dev_29/Day02%EB%B0%B0%EC%97%B4%EC%9D%98-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%88%AB%EC%9E%90%EB%A5%BC-%EA%BA%BC%EB%82%B4%EB%8A%94-%EA%B3%B5%EC%8B%9D%EB%B0%98%EB%B3%B5%EB%AC%B8-%EB%B3%B5%EC%8A%B5</guid>
            <pubDate>Thu, 26 Jun 2025 02:53:58 GMT</pubDate>
            <description><![CDATA[<pre><code>const arrays = [
  [10],     // 0번
  [30, 21], // 1번
  [50],     // 2번
  [80]      // 3번
];
</code></pre><p>🧱 먼저 arrays[i]만 보면?
arrays[0] → [10]
arrays[1] → [30, 21]
arrays[2] → [50]
arrays[3] → [80]</p>
<p>즉, arrays[i]는 i번째 배열을 말하는 거야.</p>
<p>🧱 그다음 arrays[i].length
배열의 길이를 말함</p>
<p>예: arrays[1] = [30, 21] → length = 2</p>
<p><strong>🧱 arrays[i].length - 1</strong>
배열에서 마지막 위치의 인덱스를 찾는 공식이야
왜냐면 배열 인덱스는 0부터 시작하니까!</p>
<pre><code>[30, 21]  // 인덱스는 0, 1
length = 2 → 마지막 인덱스는 2 - 1 = 1</code></pre><p><strong>arrays[i][arrays[i].length - 1]</strong>
i번째 배열(0부터 시작)의
마지막 숫자를 꺼내는 공식!</p>
<h3 id="🎯-문제">🎯 문제</h3>
<p>다음과 같은 2차원 배열이 있어:</p>
<pre><code>const arrays = [
  [10],
  [30, 21],
  [50, 12, 34],
  [80, 56, 78, 90]
];</code></pre><p>각 배열에서 마지막 숫자만 꺼내서 출력하는 코드를 작성해보세요.</p>
<p>출력 결과는 이렇게 되어야 합니다:</p>
<pre><code>10
21
34
90</code></pre><h3 id="✅-예시-답안">✅ 예시 답안</h3>
<pre><code>const arrays = [
  [10],
  [30, 21],
  [50, 12, 34],
  [80, 56, 78, 90]
];

for (let i = 0; i &lt; arrays.length; i++) {
  const lastNumber = arrays[i][arrays[i].length - 1];
  console.log(lastNumber);
}</code></pre><h3 id="💡-핵심-포인트-복습">💡 핵심 포인트 복습</h3>
<p>arrays[i]는 i번째 배열
arrays[i].length - 1은 그 배열의 마지막 인덱스
arrays[i][arrays[i].length - 1]은 마지막 숫자!</p>
<h3 id="반복문-복습">반복문 복습</h3>
<hr>
<h4 id="✅-1-기본-형태부터">✅ 1. 기본 형태부터!</h4>
<pre><code class="language-js">for (초기값; 조건식; 증가식) {
  // 반복할 코드
}</code></pre>
<hr>
<h4 id="✅-2-가장-단순한-예제">✅ 2. 가장 단순한 예제</h4>
<pre><code class="language-js">for (let i = 0; i &lt; 5; i++) {
  console.log(i);
}</code></pre>
<h5 id="결과">결과:</h5>
<pre><code>0
1
2
3
4</code></pre><hr>
<h5 id="🔍-작동-순서">🔍 작동 순서</h5>
<ol>
<li><code>let i = 0</code> → i를 0으로 시작(초기값)</li>
<li><code>i &lt; 5</code> → 조건 검사 (맞으면 블록 실행)(조건문)</li>
<li><code>console.log(i)</code> → i를 출력</li>
<li><code>i++</code> → i 값을 1 증가(증가식)</li>
<li>조건 검사로 다시 돌아감 → 계속 반복</li>
</ol>
<hr>
<h4 id="✅-3-다른-증가-방법">✅ 3. 다른 증가 방법</h4>
<h5 id="2씩-증가">2씩 증가</h5>
<p>i += 2</p>
<pre><code class="language-js">for (let i = 0; i &lt; 10; i += 2) {
  console.log(i); // 0, 2, 4, 6, 8
}</code></pre>
<h5 id="거꾸로-감소">거꾸로 감소</h5>
<p>i--</p>
<pre><code class="language-js">for (let i = 5; i &gt; 0; i--) {
  console.log(i); // 5, 4, 3, 2, 1
}</code></pre>
<hr>
<h4 id="✅-4-배열-요소-하나씩-출력하기">✅ 4. 배열 요소 하나씩 출력하기</h4>
<pre><code class="language-js">const fruits = [&#39;apple&#39;, &#39;banana&#39;, &#39;cherry&#39;];

for (let i = 0; i &lt; fruits.length; i++) {
  console.log(fruits[i]);
}</code></pre>
<p>결과:</p>
<pre><code>apple
banana
cherry</code></pre><hr>
<h4 id="✅-5-배열의-길이를-직접-써도-되지만">✅ 5. 배열의 길이를 직접 써도 되지만…</h4>
<pre><code class="language-js">for (let i = 0; i &lt; 3; i++) {
  console.log(fruits[i]); // 가능은 하지만 비효율적
}</code></pre>
<p>보통은 <code>fruits.length</code> 같이 배열의 길이를 써야
배열이 몇 개든 자동으로 처리됨!</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA["IT 5분 잡학사전" 2주 완독 챌린지]]></title>
            <link>https://velog.io/@dev_29/IT-5%EB%B6%84-%EC%9E%A1%ED%95%99%EC%82%AC%EC%A0%84-2%EC%A3%BC-%EC%99%84%EB%8F%85-%EC%B1%8C%EB%A6%B0%EC%A7%80-mqltnxy3</link>
            <guid>https://velog.io/@dev_29/IT-5%EB%B6%84-%EC%9E%A1%ED%95%99%EC%82%AC%EC%A0%84-2%EC%A3%BC-%EC%99%84%EB%8F%85-%EC%B1%8C%EB%A6%B0%EC%A7%80-mqltnxy3</guid>
            <pubDate>Fri, 13 Jan 2023 14:12:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_29/post/f913c7e4-1871-4251-9293-496b3bde24c2/image.png" alt=""></p>
<h2 id="일정">일정</h2>
<table>
    <tr>
        <th>금</th>
        <th>토</th>
        <th>일</th>
        <th>월</th>
        <th>화</th>
        <th>수</th>
        <th>목</th>
    </tr>
    <tr>
        <td>책 인증</td>
        <td>📚1~5</td>
        <td>📚6~10</td>
        <td>🙋🏻 퀴즈</td>
        <td>📚11~15</td>
        <td>📚16~21</td>
        <td>📚22~25</td>
    </tr>
    <tr>
        <td>🙋🏻 퀴즈</td>
        <td>📚26~29</td>
        <td>📚30~34</td>
        <td>🔥 미션 </td>
        <td>📚35~38</td>
        <td>📚39~45</td>
        <td>🔥 미션</td>
    </tr>
</table>

<h2 id="목표">목표</h2>
<ul>
<li>노마드 강의 5% 할인 쿠폰</li>
<li>TIL 매일 적기</li>
<li>리프레시!</li>
</ul>
<p>#코딩 #개발자 #북클럽 #노마드북클럽</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[VSCode 터미널 색상 바꾸기 + 이름 바꾸기]]></title>
            <link>https://velog.io/@dev_29/VSCode-%ED%84%B0%EB%AF%B8%EB%84%90-%EC%83%89%EC%83%81-%EB%B0%94%EA%BE%B8%EA%B8%B0</link>
            <guid>https://velog.io/@dev_29/VSCode-%ED%84%B0%EB%AF%B8%EB%84%90-%EC%83%89%EC%83%81-%EB%B0%94%EA%BE%B8%EA%B8%B0</guid>
            <pubDate>Mon, 02 Jan 2023 09:59:01 GMT</pubDate>
            <description><![CDATA[<h2 id="색상-바꾸기">색상 바꾸기</h2>
<p>settings - color검색 - workbench - apperance - Edit in settings.json</p>
<pre><code>&quot;workbench.colorCustomizations&quot;: {
    &quot;terminal.background&quot;:&quot;#090300&quot;,
    &quot;terminal.foreground&quot;:&quot;#A5A2A2&quot;,
    &quot;terminalCursor.background&quot;:&quot;#A5A2A2&quot;,
    &quot;terminalCursor.foreground&quot;:&quot;#A5A2A2&quot;,
    &quot;terminal.ansiBlack&quot;:&quot;#cfc9c6&quot;,
    &quot;terminal.ansiBlue&quot;:&quot;#A5A2A2&quot;,
    &quot;terminal.ansiBrightBlack&quot;:&quot;#5C5855&quot;,
    &quot;terminal.ansiBrightBlue&quot;:&quot;#A5A2A2&quot;,
    &quot;terminal.ansiBrightCyan&quot;:&quot;#B5E4F4&quot;,
    &quot;terminal.ansiBrightGreen&quot;:&quot;#5C5855&quot;,
    &quot;terminal.ansiBrightMagenta&quot;:&quot;#A16A94&quot;,
    &quot;terminal.ansiBrightRed&quot;:&quot;#DB2D20&quot;,
    &quot;terminal.ansiBrightWhite&quot;:&quot;#F7F7F7&quot;,
    &quot;terminal.ansiBrightYellow&quot;:&quot;#FDED02&quot;,
    &quot;terminal.ansiCyan&quot;:&quot;#B5E4F4&quot;,
    &quot;terminal.ansiGreen&quot;:&quot;#5C5855&quot;,
    &quot;terminal.ansiMagenta&quot;:&quot;#A16A94&quot;,
    &quot;terminal.ansiRed&quot;:&quot;#DB2D20&quot;,
    &quot;terminal.ansiWhite&quot;:&quot;#A5A2A2&quot;,
    &quot;terminal.ansiYellow&quot;:&quot;#FDED02&quot;
  },</code></pre><p>여기서 커스텀 변경</p>
<h2 id="이름-바꾸기">이름 바꾸기</h2>
<ol>
<li>vscode에서 터미널 열기</li>
<li><code>vi ~/.zshrc</code> 입력</li>
<li>맨 아래로 내려가서 다음 추가하기<pre><code>prompt_context() {
prompt_segment black default &quot;&quot;
}</code></pre>내용 복사 후 o -&gt; cmd + v -&gt; esc -&gt; :wq + enter</li>
</ol>
<h4 id="vi-사용법을-알아야-함">vi 사용법을 알아야 함!</h4>
<p><code>o</code> (open) 입력모드로 들어감: 커서가 위치한 행의 다음행에 입력
<code>esc</code> 입력모드 빠져나옴
<code>:wq + enter</code> 작업 내용 저장 후 종료</p>
<p><a href="https://jitolit.tistory.com/27">https://jitolit.tistory.com/27</a></p>
<h4 id="참고">참고</h4>
<p><a href="https://velog.io/@dding_yull/VScode-%ED%84%B0%EB%AF%B8%EB%84%90-%EA%BE%B8%EB%AF%B8%EA%B8%B0%EC%95%84%EC%9D%B4%EC%BD%98%EB%84%A3%EA%B8%B0">https://velog.io/@dding_yull/VScode-%ED%84%B0%EB%AF%B8%EB%84%90-%EA%BE%B8%EB%AF%B8%EA%B8%B0%EC%95%84%EC%9D%B4%EC%BD%98%EB%84%A3%EA%B8%B0</a>
<a href="https://glitchbone.github.io/vscode-base16-term/#/atelier-heath-light">https://glitchbone.github.io/vscode-base16-term/#/atelier-heath-light</a>
<a href="https://kangyb.tistory.com/23">https://kangyb.tistory.com/23</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프론트엔드 인턴십]세션1_ 후기]]></title>
            <link>https://velog.io/@dev_29/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%B8%ED%84%B4%EC%8B%AD%EC%84%B8%EC%85%981-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@dev_29/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%B8%ED%84%B4%EC%8B%AD%EC%84%B8%EC%85%981-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Tue, 20 Dec 2022 06:19:17 GMT</pubDate>
            <description><![CDATA[<h3 id="기업-과제-평가-방식에-따른-셀프-피드백">기업 과제 평가 방식에 따른 셀프 피드백</h3>
<p>1️⃣ 기한 내 과제 제출 여부
➡️ ⭕️
2️⃣ GitHub URL, 배포된 결과물 등 과제 확인에 필요한 요소들의 정상 제출, 접근 가능 여부 ‼
➡️ ⭕️
3️⃣ 과제가 요구하는 기능들 구현 완성도
➡️ 🔺(4/5)
4️⃣ README 파일의 완성도
➡️ 🔺(2/5)
5️⃣ Git commit message &amp; history 관리의 완성도
➡️ 🔺(2/5)
6️⃣ 프로젝트의 구조, 코드의 가독성 등 전체 프로젝트의 구현 퀄리티
➡️ 🔺(3/5)</p>
<h3 id="보완-결과">보완 결과</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[프리온보딩 프론트엔드 인턴십 커리큘럼]]></title>
            <link>https://velog.io/@dev_29/%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%B8%ED%84%B4%EC%8B%AD-%EC%BB%A4%EB%A6%AC%ED%81%98%EB%9F%BC</link>
            <guid>https://velog.io/@dev_29/%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%B8%ED%84%B4%EC%8B%AD-%EC%BB%A4%EB%A6%AC%ED%81%98%EB%9F%BC</guid>
            <pubDate>Fri, 16 Dec 2022 07:39:04 GMT</pubDate>
            <description><![CDATA[<p>22년 12월 19일 - 23년 1월 20일
(5주 100h 이상 소요)</p>
<p>강의 : 화, 금
화, 금 : 14:00 - 17:00</p>
<h4 id="week-1-1-과제를-하기에-앞서-알아야-할-팀으로-일하는-법-개발자의-기본기">Week 1-1. 과제를 하기에 앞서 알아야 할 팀으로 일하는 법, 개발자의 기본기</h4>
<p>Git &amp; GitHub / ESLint / Prettier / husky / Git hook</p>
<p>강사/교육파트너 소개 / 코스 커리큘럼 및 학습 목표 소개
선발 과제 피드백
Git &amp; GitHub을 사용하면서 지켜야 할 것
ESLint와 Prettier, Git hook을 이용한 팀의 능률 올리기&quot;
[아하!모먼트] Agile이 필요하다고 느낀 순간</p>
<h4 id="week-1-2-프로젝트를-지속적으로-통합하고-배포하는-법">Week 1-2. 프로젝트를 지속적으로 통합하고 배포하는 법</h4>
<p>AWS / AWS S3 / CRA / CI/CD / GitHub Actions</p>
<p>온 프레미스와 클라우드, 그리고 AWS
프론트엔드 배포하기 with AWS S3
CI/CD를 구축해야 하는 이유
GitHub Actions를 통한 배포 파이프라인 구축하기
[아하!모먼트] 프론트엔드가 배포까지 해야 할까?</p>
<h4 id="week-2-프리온보딩-커리어-챌린지">Week 2. 프리온보딩 커리어 챌린지</h4>
<p>채용 트렌드 분석 / 이력서 작성 / 면접 &amp; 비즈니스 매너 / 현직자 Q&amp;A</p>
<p>2주차에는 커리어 챌린지에 참여하여 이력서 작성 및 Q&amp;A 시간을 갖습니다.
현직자 Q&amp;A는 Google Meet에서 그룹 별로 진행됩니다.
이력서 특강을 통해 그동안의 경험을 올바르게 담아내는 방법을 살펴봅니다.
커리어 챌린지를 통해 앞으로의 취업 계획을 효과적으로 수립합니다.
링크) 프리온보딩 커리어 챌린지 2022</p>
<h4 id="week-3-1-react-hook의-심층-활용">Week 3-1. React Hook의 심층 활용</h4>
<p>의존성 배열 / useEffect / React.memo / useCallback / useMemo / Context API</p>
<p>리액트에서 렌더링 최적화를 수행하는 법
React.memo를 이용해 컴포넌트 렌더링 최적화하기
메모이제이션을 통한 최적화 수행하기
useEffect의 의존성 배열 올바르게 다루기
Context API로 컴포넌트에 맥락 전달하기
[아하!모먼트] 최적화를 해야하는 시기는 언제일까?</p>
<h4 id="week-3-2-clean-code와-소프트웨어를-유연하고-확장성있게-만드는-법">Week 3-2. Clean Code와 소프트웨어를 유연하고 확장성있게 만드는 법</h4>
<p>Clena Code / SRP / DIP / 횡단 관심사 / Custom Hook / Context API</p>
<p>관심사의 분리와 SRP
리액트에서 관심사를 분리하는 법
HTTP 통신의 횡단 관심사 처리하기
의존성 역전을 통해 소프트웨어 유연하게 만들기
컴포넌트에 의존성 주입하기 with Context API
[아하!모먼트] 소프트웨어 아키텍쳐를 왜 신경써야 할까?</p>
<h4 id="week-4-1-typescript로-런타임에-안전한-웹-앱-작성하기">Week 4-1. TypeScript로 런타임에 안전한 웹 앱 작성하기</h4>
<p>TypeScript / 타입 가드 / 타입 추론 / 제네릭</p>
<p>TypeScript를 사용해야 하는 이유
제네릭을 사용하여 타입 재사용하기
d.ts 파일을 통해 타입 구조 파악하기
타입 가드를 통해 더욱 정확한 타입 사용하기
[아하!모먼트] 타입스크립트가 편하게 느껴진 순간</p>
<h4 id="week-4-2-redux로-알아보는-react-전역-상태-관리">Week 4-2. Redux로 알아보는 React 전역 상태 관리</h4>
<p>전역 상태 관리 / Redux / Flux</p>
<p>Redux를 이용한 전역 상태 관리
Redux와 middleware란?
middleware의 원리
middleware 직접 만들고 적용해보기
[아하!모먼트] 신기술의 홍수에서 살아남는 법</p>
<h4 id="week-5-1-프론트엔드에서의-테스트">Week 5-1. 프론트엔드에서의 테스트</h4>
<p>Software Testing / Unit Test / TDD / Jest</p>
<p>소프트웨어 테스트란?
Jest를 활용한 JavaScript 테스트
TDD를 이용한 소프트웨어 개발 방식
Redux에 테스트 적용하기
[아하!모먼트] 테스트가 중요하다고 느낀 순간</p>
<h4 id="week-5-2-advanced-javascript---실행-컨텍스트">Week 5-2. Advanced Javascript - 실행 컨텍스트</h4>
<p>실행 컨텍스트 / 클로저 / 스코프 / 호이스팅</p>
<p>JavaScript의 실행 컨텍스트
스코프 &amp; 호이스팅을 실행 컨텍스트 관점에서 이해하기
클로저를 이용해 React Hook 직접 만들어보기
[아하!모먼트] 개발은 과연 어떻게 공부해야 할까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useNavigate가 안먹히는 현상]]></title>
            <link>https://velog.io/@dev_29/useNavigate%EA%B0%80-%EC%95%88%EB%A8%B9%ED%9E%88%EB%8A%94-%ED%98%84%EC%83%81-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@dev_29/useNavigate%EA%B0%80-%EC%95%88%EB%A8%B9%ED%9E%88%EB%8A%94-%ED%98%84%EC%83%81-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Tue, 13 Dec 2022 14:22:42 GMT</pubDate>
            <description><![CDATA[<pre><code>로그인 여부에 따른 리다이렉트 처리를 구현해주세요
로컬 스토리지에 토큰이 있는 상태로 / 페이지에 접속한다면 /todo 경로로 리다이렉트 시켜주세요
로컬 스토리지에 토큰이 없는 상태로 /todo페이지에 접속한다면 / 경로로 리다이렉트 시켜주세요</code></pre><p>위 과제조건을 만족시키기 위해 처음에는 </p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/fc9d9d3d-5be9-47ea-91e0-0ac52dd59f56/image.png" alt=""></p>
<p>이렇게 app.js에서 로컬스토리지에 액세스 토큰이 있으면 /todo로 이동하도록 짰다.</p>
<p>문제는 이렇게 할 경우, todolist에서 로그아웃 버튼을 클릭했을 때 홈으로 이동하도록 navigate를 하면 새로고침을 해야만(window.location.reload()) 이동이 되는 현상이 나왔다.</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/38b62383-b23f-48d6-8c6a-a11224bea8f8/image.png" alt=""></p>
<p>정확히는 모르겠지만, 로컬스토리지의 변화가 바로바로 반영이 안되고, app.js에서 route가 고정되어 나타나는 현상 같았다.</p>
<p>그래서 app.js에 있는 라우트를 분기하지 않고, 각 페이지마다 useEffect를 사용하여 처음 렌더링될 때 로컬스토리지에 액세스토큰이 있는지를 확인하도록 바꾸었다.</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/cd4521b8-9998-4e7e-ab74-2564b8bfbf52/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/9551344e-05f2-4e98-8980-0c212f85dae4/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/a6bef6ab-2814-4ed8-87a9-002e4d4330dc/image.png" alt=""></p>
<p>그런데 처음 썼던 방식도 navigate 뒤에 window.location.reload()만 더해주면 이동을 했기 때문에... 바꾼 방식이 더 나은것인지는 확신하지 못하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[return; return false;의 차이]]></title>
            <link>https://velog.io/@dev_29/return-return-false%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@dev_29/return-return-false%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 13 Dec 2022 12:56:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_29/post/1c65001a-ed36-43d8-881b-18e8133b7d36/image.png" alt=""></p>
<p>axios 요청을 하다가 위 3가지 경우가 궁금해져서 찾아봤다.</p>
<p>일반적으로 함수에서 return;로 리턴값 없이 끝내버리면, 함수의 동작이 멈춘다.</p>
<p><code>return; is the same as return undefined;, which is the same as having a function with no return statement at all.</code>
(출처: <a href="https://stackoverflow.com/questions/5596404/return-false-the-same-as-return">https://stackoverflow.com/questions/5596404/return-false-the-same-as-return</a>)</p>
<p>즉 리턴값이 없이 끝내버리면 그 함수는 undefined를 반환하는 것과 같다.</p>
<p>그렇다면
return; 보다 return false를 사용하는 것이 더 좋은걸까?</p>
<p><code>I would recommend always return something, in this case false because if your function doesn&#39;t have return statement then it will always return undefined. So for sake of easier debugging, it&#39;s better to return false rather than undefined, because you will imminently know that return statement was indeed executed, while with undefined you have 1 more step to check.</code>
(출처: <a href="https://stackoverflow.com/questions/47597864/difference-between-return-and-return-false">https://stackoverflow.com/questions/47597864/difference-between-return-and-return-false</a>)</p>
<p>디버깅을 위해서 return;으로 끝내는 것보단 return false로 리턴값을 명확히 하는 것이 더 좋다는 답글이 많다.</p>
<p><a href="https://yongblog.tistory.com/entry/onclick-%EC%97%90%EC%84%9C-return-false-%EC%9D%98-%EC%9D%98%EB%AF%B8">https://yongblog.tistory.com/entry/onclick-%EC%97%90%EC%84%9C-return-false-%EC%9D%98-%EC%9D%98%EB%AF%B8</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[원티드 프리온보딩 프론트엔드 인턴십] 참가 에세이 - 박민경]]></title>
            <link>https://velog.io/@dev_29/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%B8%ED%84%B4%EC%8B%AD-%EC%B0%B8%EA%B0%80-%EC%97%90%EC%84%B8%EC%9D%B4-%EB%B0%95%EB%AF%BC%EA%B2%BD</link>
            <guid>https://velog.io/@dev_29/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%9D%B8%ED%84%B4%EC%8B%AD-%EC%B0%B8%EA%B0%80-%EC%97%90%EC%84%B8%EC%9D%B4-%EB%B0%95%EB%AF%BC%EA%B2%BD</guid>
            <pubDate>Mon, 12 Dec 2022 10:41:07 GMT</pubDate>
            <description><![CDATA[<h3 id="1-최종합격까지-몇-개-이상의-이력서-작성이-필요할까요">1. 최종합격까지 몇 개 이상의 이력서 작성이 필요할까요?</h3>
<p>최소 20개 이상의 이력서 작성이 필요하다. 하지만 보다 많은 기회를 얻기 위해서 적어도 100개 이상의 이력서를 쓸 각오가 되어있다.</p>
<h3 id="2-프리온보딩-인턴십에서-숏에세이-작성제도를-시행하는-목적">2. 프리온보딩 인턴십에서 숏에세이 작성제도를 시행하는 목적</h3>
<p>주최측 입장에서는 수많은 참가자 중에서 해당 참가자가 무분별하게 지원하는 것인지 아니면 진정성을 가지고 지원하는지를 파악할 수 있다. 반면 참가자 입장에서는 숏에세이를 통해 지원하고 싶은 참가기업을 확인하고 자신에게 정말 필요한 기회인지를 생각해볼 수 있다. 또한 참가기업 입장에서는 지원을 희망하는 신입개발자들의 공개 에세이를 통해 직간접적으로 자신의 회사를 알릴 수 있는 효과를 얻을 수 있기 때문에 숏에세이 작성제도를 시행한다고 생각한다.</p>
<h3 id="3-지원하고-싶은-참가기업은-어디인지">3. 지원하고 싶은 참가기업은 어디인지</h3>
<ol>
<li><p>에듀템</p>
<p> 리얼타임 쉐도잉 개발을 통해 좋은 평가를 받고 있는 에듀템은 인공지능 기반의 에듀테크를 연구, 개발 회사이다. 인터넷 테크놀로지를 통해 가장 급격하게 변화한 업계 중 하나가 교육계이다. 하지만 교육계는 아직도 더 많은 성장가능성을 가지고 있다고 생각한다. 특히 온라인 교육의 효과성, 효율성, 비용절감성 등에서 한발 더 나아가 개인맞춤형 교육서비스로 성장한다면 지금보다 더 큰 시너지를 낼 수 있다고 생각한다. 
 전공이 교육이었기 때문에 개발을 하면서도 교육서비스 쪽으로 자연스럽게 관심을 가지게 되었고, 가장 최근에 진행했던 프로젝트 역시 교육관련 커뮤니티 서비스였기 때문에 즐겁게 개발할 수 있을 것 같다.</p>
</li>
<li><p>젠스타메이트</p>
<p> 젠스타메이드는 국내 최대 상업용 부동산 종합 서비스 회사이다. 평소에 부동산에 관심이 있어서 부동산 업계에서 일해보고 싶다는 생각을 했다. 일반인의 입장에서 부동산 정보를 찾다보면 결국은 객관적인 지표와 함께 종합적인 전문 서비스가 필요하다는 생각을 했다. 부동산 서비스에서 제공하는 정보는 그 양이 방대하고 복잡하기 때문에 적절하게 시각화해야 하고, 실시간 정보제공이 원활해야 한다고 생각한다. 관심있는 부동산 분야에서 개발자로서 함께 성장하고 싶다.</p>
<ol start="3">
<li><p>렉시냅틱스</p>
<p>렉시냅틱스는 법률산업의 디지털 혁신을 추구하는 기업이다. 예전에는 법적인 내용을 상담하려면 무조건 변호사를 찾아가야 했지만, 이제는 법조계 역시 많이 변화하고 있다. 법적 당사자는 모든 것을 변호사에게 맡겨두기 보다는 자신의 법률문제를 스스로 관리하려고 노력하며, 나홀로 전자소송과 같이 변호사를 선임하지 않고 소송을 진행하기도 한다. 
몇 년 전에 집안에 민사소송이 있어 법률적인 조언이 필요했던 적이 있는데, 렉시냅틱스는 아니었지만 다른 디지털 법률 서비스를 이용한 경험이 있다. 법적 문제는 일반인이 처리하게에는 그 절차와 내용이 어렵고 그 비용 역시 천문학적인데, 디지털 법률 서비스를 통해 소송비용도 줄일 수 있고 억울한 마음 역시 전문적인 상담을 받으며 객관적으로 바라볼 수 있었다. 기회가 된다면 이렇게 귀중한 가치를 지닌 디지털법률 서비스가 더욱 발전할 수 있도록 자부심을 가지고 일하고 싶다.</p>
</li>
</ol>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Can't resolve 'redux' in...]]></title>
            <link>https://velog.io/@dev_29/Cant-resolve-redux-in</link>
            <guid>https://velog.io/@dev_29/Cant-resolve-redux-in</guid>
            <pubDate>Sun, 23 Oct 2022 07:11:19 GMT</pubDate>
            <description><![CDATA[<p>npm 최신버전을 설치하면 된다</p>
<p><code>npm install redux@latest react-redux@latest</code></p>
<p><a href="https://bobbyhadz.com/blog/react-module-not-found-cant-resolve-redux">https://bobbyhadz.com/blog/react-module-not-found-cant-resolve-redux</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[블로깅]]]></title>
            <link>https://velog.io/@dev_29/%EB%B8%94%EB%A1%9C%EA%B9%85</link>
            <guid>https://velog.io/@dev_29/%EB%B8%94%EB%A1%9C%EA%B9%85</guid>
            <pubDate>Fri, 07 Oct 2022 07:49:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_29/post/74a15ae5-4f24-44f3-a499-23081dbb2709/image.png" alt=""></p>
<h3 id="defer-offscreen-images">Defer offscreen images</h3>
<p><img src="https://velog.velcdn.com/images/dev_29/post/d20c17af-ad57-42a1-9782-49d1b8777db8/image.png" alt=""></p>
<p>&lt;문제&gt; 오프스크린 이미지 
&lt;해결책&gt; </p>
<ul>
<li>지연 해결을 위한 lazy-load 플러그인, 모듈을 설치
오프스크린 이미지란? 
사용자가 보고 있는 화면에 보이지 않는 이미지
레이지로드란? 
오프스크린 이미지를 로딩하지 않고 있다가, 사용자가 스크롤을 움직여서 해당 이미지가 보여야 할 시점에 이미지를 로딩하는 기술</li>
<li>lazysizes를 사용하여 오프스크린 이미지를 지연 로드
<code>&lt;script src=&quot;lazysizes.min.js&quot; async&gt;&lt;/script&gt;</code>
<code>&lt;img data-src=&quot;images/flower3.png&quot; class=&quot;lazyload&quot; alt=&quot;&quot;&gt;</code></li>
</ul>
<h3 id="reduce-unused-javascript">Reduce unused JavaScript</h3>
<p><img src="https://velog.velcdn.com/images/dev_29/post/4e3ecd44-7065-4a11-968d-541b51e3c279/image.png" alt=""></p>
<p>&lt;문제&gt; 사용하지 않는 자바스크립트
&lt;해결책&gt; 사용하지 않는 JavaScript를 제거</p>
<ol>
<li><p>사용하지 않는 자바스크립트 감지 
Chrome DevTools 의 Coverage 탭 에서는 사용하지 않는 코드를 한 줄씩 분석
막대의 빨간색 부분은 사용되지 않은 바이트
<img src="https://velog.velcdn.com/images/dev_29/post/aa23080d-0418-4efc-ae00-e34134f2a4cd/image.png" alt=""></p>
</li>
<li><p>사용하지 않는 코드 제거 지원을 위한 빌드 도구 (리액트)</p>
</li>
</ol>
<ul>
<li>서버 측 렌더링이 아닌 경우 JavaScript 번들을 React.lazy()로 분할<pre><code>import React, { lazy } from &#39;react&#39;;
</code></pre></li>
</ul>
<p>const AvatarComponent = lazy(() =&gt; import(&#39;./AvatarComponent&#39;));</p>
<p>const DetailsComponent = () =&gt; (
  <div>
    <AvatarComponent />
  </div>
)</p>
<p>```</p>
<ul>
<li>loadable-components 와 같은 타사 라이브러리를 사용하여 코드를 분할 </li>
</ul>
<h3 id="serve-images-in-next-gen-formats">Serve images in next-gen formats</h3>
<p><img src="https://velog.velcdn.com/images/dev_29/post/3184f544-40a4-48b4-a230-e557fe4eb5d2/image.png" alt=""></p>
<p>&lt;문제&gt; 이전 형식의 이미지 사용
&lt;해결책&gt; 이미지를 AVIF 또는 WebP 형식으로 제공
AVIF 및 WebP는 이전 JPEG 및 PNG 형식에 비해 압축 및 품질 특성이 우수한 이미지 형식입니다. JPEG 또는 PNG가 아닌 이러한 형식으로 이미지를 인코딩하면 더 빠르게 로드되고 더 적은 셀룰러 데이터를 소비합니다.
AVIF는 Chrome, Firefox 및 Opera에서 지원되며 동일한 품질 설정의 다른 형식에 비해 작은 파일 크기를 제공합니다. AVIF에 대한 자세한 내용은 AVIF 이미지 제공 Codelab 을 참조하세요.
WebP는 최신 버전의 Chrome, Firefox, Safari, Edge 및 Opera에서 지원되며 웹의 이미지에 대해 더 나은 손실 및 무손실 압축을 제공합니다. WebP에 대한 자세한 내용은 A New Image Format For Web 을 참조하십시오.</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/e3b7be55-7e12-4f0b-be47-0f4819bf3f13/image.png" alt=""></p>
<h3 id="efficiently-encode-images">Efficiently encode images</h3>
<p><img src="https://velog.velcdn.com/images/dev_29/post/7332e6c8-1832-4c4d-b5d1-11bf21bdb949/image.png" alt=""></p>
<p>&lt;문제&gt; 이미지를 효율적으로 인코딩
&lt;해결책&gt; 이미지를 최적화하는 방법 </p>
<ul>
<li>이미지 CDN 사용</li>
<li>이미지 압축</li>
<li>애니메이션 GIF를 비디오로 대체</li>
<li>이미지 로딩 지연</li>
<li>반응형 이미지 제공</li>
<li>올바른 크기의 이미지 제공</li>
<li>WebP 이미지 사용</li>
</ul>
<h3 id="use-http2">Use HTTP/2</h3>
<p><img src="https://velog.velcdn.com/images/dev_29/post/716022ec-da1f-418b-b70b-444d5784621c/image.png" alt=""></p>
<p>&lt;문제&gt; 모든 리소스에 HTTP/2를 사용하지 않음
&lt;해결책&gt; HTTP/2는 유선을 통해 이동하는 데이터를 줄여 페이지 리소스를 더 빠르게 제공합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[깃 배포 404오류]]></title>
            <link>https://velog.io/@dev_29/%EA%B9%83-%EB%B0%B0%ED%8F%AC-404%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@dev_29/%EA%B9%83-%EB%B0%B0%ED%8F%AC-404%EC%98%A4%EB%A5%98</guid>
            <pubDate>Tue, 27 Sep 2022 02:25:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_29/post/1d514774-3dd9-4c27-995e-b11529f50dee/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[블로깅]웹팩 설치 및 적용]]></title>
            <link>https://velog.io/@dev_29/%EB%B8%94%EB%A1%9C%EA%B9%85%EC%9B%B9%ED%8C%A9-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%A0%81%EC%9A%A9</link>
            <guid>https://velog.io/@dev_29/%EB%B8%94%EB%A1%9C%EA%B9%85%EC%9B%B9%ED%8C%A9-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%A0%81%EC%9A%A9</guid>
            <pubDate>Tue, 27 Sep 2022 01:27:42 GMT</pubDate>
            <description><![CDATA[<p>*<em>----js파일 번들링-----
*</em></p>
<ol>
<li><p>src폴더 하나 만들어서
js, html, css파일 모두 넣기</p>
</li>
<li><p>js파일이 2개면, 
메인 js파일에 합칠 수 있도록
require, exports 하기</p>
</li>
</ol>
<blockquote>
<p>메인파일
<code>const 어쩌구 = require(&#39;./보조파일명.js&#39;);</code>
보조파일
<code>module.exports = agoraStatesDiscussions;</code></p>
</blockquote>
<ol start="3">
<li><code>npm init -y</code>
package.json 파일이 생성</li>
</ol>
<p>4.
<code>npm install -D webpack webpack-cli</code>
웹팩 설치</p>
<ol start="5">
<li>웹팩 config파일 만들기
webpack.config.js 만들고 내용 작성<pre><code>const path = require(&#39;path&#39;);
</code></pre></li>
</ol>
<p>module.exports = {
  entry: &#39;./src/메인파일명.js&#39;,
  output: {
    path: path.resolve(__dirname, &#39;dist&#39;), // &#39;./dist&#39;의 절대 경로를 리턴합니다.
    filename: &#39;출력할파일명.js&#39;,
  },
  mode: &#39;development&#39;,
};</p>
<pre><code>
  mode: &#39;development&#39; -&gt; 개발자 옵션 추가하기

6.
번들링 명령어 입력
`npx webpack`
dist폴더가 생성되고, 그 안에 파일이 생성되면 성공

7. 
package.json 파일에서
script에 명령어 추가
`&quot;build&quot;: &quot;webpack&quot;,`
이제 npm run build 명령어 사용가능

![](https://velog.velcdn.com/images/dev_29/post/7dd41929-6457-4ed8-8258-725e38d5d072/image.png)



**----css파일 번들링(합치기)----
**



html파일을 src폴더에서 dist폴더로 옮긴 후,
html파일에서 script 태그에 src를 dist에 생성된 파일명으로 바꾸기

`  &lt;script src=&quot;main.js&quot;&gt;&lt;/script&gt;
`
html파일을 열어보면, css가 적용되지 않은 모습이 나온다

![](https://velog.velcdn.com/images/dev_29/post/176e6fcc-071d-464a-8920-4f42479f3a0f/image.png)

8. src에 있는 script파일에 
require로 src폴더에 있는 css파일 불러오기

`require(&#39;./style.css&#39;);`


9. 
로더 설치
`npm i -D css-loader style-loader
`

10. 
webpack.config.js에 모듈 추가</code></pre><p>// webpack.config.js
const path = require(&quot;path&quot;);</p>
<p>module.exports = {
  entry: &quot;./src/메인파일명.js&quot;,
  output: {
    path: path.resolve(__dirname, &quot;dist&quot;),
    filename: &quot;출력할파일명.js&quot;,
  },
  mode: &#39;development&#39;,
  module: {
    rules: [
      {
        test: /.css$/,
        use: [&quot;style-loader&quot;, &quot;css-loader&quot;],
        exclude: /node_modules/,
      },
    ],
  },
};</p>
<pre><code>
11. 
`npm run build`를 입력하여 번들링

**
------html파일 번들링---------**

dist폴더에 있던 html파일을 다시 src폴더로 옮기기(왜? 플러그인을 통해서 dist폴더에 번들링한 html파일을 생성할 거임)


12. 
html 플러그인 설치
`npm i -D html-webpack-plugin`

13.
webpack.config.js 파일에 해당 플러그인을 적용
첫번째 줄에 require하는 것도 잊지말기!!
</code></pre><p>...생략...
const HtmlWebpackPlugin = require(&#39;html-webpack-plugin&#39;)</p>
<p>module.exports = {
 ...생략...
  plugins: [new HtmlWebpackPlugin({
    template: path.resolve(__dirname, &quot;src&quot;, &quot;index.html&quot;)
  })]
};</p>
<pre><code>14.
`npm run build`로 번들링 결과 확인
-&gt; dist/index.html 파일을 새로 생성되면 성공

dist에 생성된 index.html 파일을 보면,
플러그인이 `&lt;script defer=&quot;defer&quot; src=&quot;app.bundle.js&quot;&gt;&lt;/script&gt;` 스크립트 요소를 자동으로 추가한 것을 볼 수 있다.

15. dist에 생성된 html파일을 라이브서버로 열어서 확인

// 참고자료
코드스테이츠 
https://study-ihl.tistory.com/137
https://inpa.tistory.com/entry/NODE-%F0%9F%93%9A-require-%E2%9A%94%EF%B8%8F-import-CommonJs%EC%99%80-ES6-%EC%B0%A8%EC%9D%B4-1</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[emmet 사용법]]></title>
            <link>https://velog.io/@dev_29/emmet-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@dev_29/emmet-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Fri, 23 Sep 2022 07:35:57 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@rain98/VSCode-Emmet-%EC%82%AC%EC%9A%A9%EB%B2%95">https://velog.io/@rain98/VSCode-Emmet-사용법</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[섹션3 회고]]></title>
            <link>https://velog.io/@dev_29/%EC%84%B9%EC%85%983-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@dev_29/%EC%84%B9%EC%85%983-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 19 Sep 2022 11:58:49 GMT</pubDate>
            <description><![CDATA[<h2 id="목표-상기하기">목표 상기하기</h2>
<blockquote>
<p>나는 5년 이내에 외국계 회사에서 일하는 디지털 노마더가 되고 싶다🙏”</p>
</blockquote>
<blockquote>
<p>“그 이후엔 10년 이내에 재미있게 개발공부를 할 수 있는 어린이용 교육프로그램을 만들고 싶다”</p>
</blockquote>
<blockquote>
<p>“그 이후엔 끊임없이 무언가를 하고 싶어하는 마음을 잃지 않는 열정 있는 개발자가 되고 싶다”</p>
</blockquote>
<h2 id="keep">Keep</h2>
<ul>
<li>알고리즘 스터디에 참여하게 되었는데, 스터디가 강제성을 주어 좀더 공부를 하게 된다.</li>
<li>일주일에 2~3번 운동은 유지하고 있다. 필라테스를 하니까 허리 부담이 덜 가는 것 같다.</li>
</ul>
<h2 id="problem">Problem</h2>
<ul>
<li>자는 시간이 자꾸 늦어지고, 일어나는 시간도 늦어진다.</li>
<li>확실히 섹션1, 2 보다 지치고 버겁다. 해이해졌다기 보다는 버거워서 많은 양을 소화하지 못한 것 같다. 특히 데일리코딩</li>
</ul>
<h2 id="try">Try</h2>
<ul>
<li>필라테스, 등산 외에 유산소 운동도 주1회 이상 하기</li>
<li>11시에 자기</li>
<li>스터디에 더 참여하기</li>
<li>독서시간 가지기</li>
<li>사이드 프로젝트</li>
<li>데일리코딩 주말에 꼭 복습</li>
<li></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준]2주차_]]></title>
            <link>https://velog.io/@dev_29/%EB%B0%B1%EC%A4%802%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dev_29/%EB%B0%B1%EC%A4%802%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 05 Sep 2022 12:03:14 GMT</pubDate>
            <description><![CDATA[<p>1    1330    두 수 비교하기</p>
<p>두 정수 A와 B가 주어졌을 때, A와 B를 비교하는 프로그램을 작성하시오.</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/9d8f74fb-3eeb-4c01-967d-f5c93618521a/image.png" alt=""></p>
<p>2    9498    시험 성적</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/bea7a5f1-00ee-471f-a1ea-e754694a5224/image.png" alt=""></p>
<p>3    2753    윤년</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/75d207cf-55fc-4aa1-8ff3-09cd8eaaeae5/image.png" alt=""></p>
<p>4    14681    사분면 고르기</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/386d8164-cf8d-4842-b9ce-f190b4637b5e/image.png" alt=""></p>
<p>5    2884    알람 시계</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/0a9c70d0-91e4-462b-b61a-8d7d80e120c5/image.png" alt=""></p>
<p>6    2525    오븐 시계</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/7e01e0e3-6dba-45f7-8647-36838d5af29b/image.png" alt=""></p>
<p>7    2480    주사위 세개</p>
<p><img src="https://velog.velcdn.com/images/dev_29/post/7c4f38fb-8d95-4f4c-a716-46a4d2d42b97/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[<input> 인풋태그]]></title>
            <link>https://velog.io/@dev_29/input-%EC%9D%B8%ED%92%8B%ED%83%9C%EA%B7%B8</link>
            <guid>https://velog.io/@dev_29/input-%EC%9D%B8%ED%92%8B%ED%83%9C%EA%B7%B8</guid>
            <pubDate>Tue, 30 Aug 2022 00:43:48 GMT</pubDate>
            <description><![CDATA[<p>HTML <code>&lt;input&gt;</code> 요소
웹 기반 양식에서 사용자의 데이터를 받을 수 있는 대화형 컨트롤을 생성
다양한 종류의 입력 데이터 유형과 컨트롤 위젯이 존재
입력 유형과 특성의 다양한 조합 가능성으로 인해, <code>&lt;input&gt;</code> 요소는 HTML에서 제일 강력하고 복잡한 요소 중 하나</p>
<p>(예시)</p>
<pre><code>&lt;input 
   type=&quot;text&quot; 
   id=&quot;name&quot; 
   name=&quot;name&quot; 
   required 
   minlength=&quot;4&quot; 
   maxlength=&quot;8&quot; 
   size=&quot;10&quot;&gt;
</code></pre><p><code>&lt;input&gt;</code> 요소의 동작 방식은 type 특성에 따라 현격히 달라지므로, 각각의 유형은 별도의 참고 문서에서 더 자세히 확인할 수 있습니다. 특성을 지정하지 않은 경우, <code>기본값은 text</code>입니다.</p>
<h3 id="input-유형"><code>&lt;input&gt;</code> 유형</h3>
<p><code>&lt;input type=&quot;text&quot;&gt;</code>
<input type="text">
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text">https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text</a>
<code>&lt;input type=&quot;date&quot;&gt;</code>
<input type="date">
<code>&lt;input type=&quot;password&quot;&gt;</code>
<input type="password">
<code>&lt;input type=&quot;search&quot;&gt;</code>
<input type="search">
<code>&lt;input type=&quot;submit&quot;&gt;</code>
<input type="submit"></p>
<h3 id="속성">속성</h3>
<p><code>type</code>: input 양식 컨트롤의 유형
<code>value</code>: 양식 컨트롤의 현재 값. (name/value pair)의 일부로서 양식과 함께 전송된다
<code>name</code>: input 양식 컨트롤의 이름. 이름/값 짝(name/value pair)의 일부로서 양식과 함께 전송된다
<code>placeholder</code>
<code>maxlength</code>: value의 최대 길이 (문자수)
<code>minlength</code>: value의 최소 길이 (문자수)
<code>max</code>
<code>min</code>
<code>checked</code>
<code>autocomplete</code></p>
<h3 id="a-common-form">A common form</h3>
 <!-- A common form that includes input tags -->
<form action="getform.php" method="get">
    <label>First name: <input type="text" name="first_name" /></label><br />
    <label>Last name: <input type="text" name="last_name" /></label><br />
    <label>E-mail: <input type="email" name="user_email" /></label><br />
    <input type="submit" value="Submit" />
</form>



<p><a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/Input">https://developer.mozilla.org/ko/docs/Web/HTML/Element/Input</a></p>
]]></description>
        </item>
    </channel>
</rss>