<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hwang-eunji.log</title>
        <link>https://velog.io/</link>
        <description>TIL 기록 블로그 ::  문제가 있는 글엔 댓글 부탁드려요!</description>
        <lastBuildDate>Wed, 09 Sep 2020 23:08:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hwang-eunji.log</title>
            <url>https://images.velog.io/images/hwang-eunji/profile/841902c0-60d8-4807-a1bd-a3669ef7c443/70BB3466-5086-43F0-8B47-1BC173F158D9.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hwang-eunji.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hwang-eunji" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[express 라우팅]]></title>
            <link>https://velog.io/@hwang-eunji/express-%EB%9D%BC%EC%9A%B0%ED%8C%85</link>
            <guid>https://velog.io/@hwang-eunji/express-%EB%9D%BC%EC%9A%B0%ED%8C%85</guid>
            <pubDate>Wed, 09 Sep 2020 23:08:57 GMT</pubDate>
            <description><![CDATA[<h1 id="express-라우팅">express 라우팅</h1>
<p>쿼리파라미터와 패스파라미터?</p>
<h2 id="url-파라미터-사용하기">url 파라미터 사용하기</h2>
<pre><code class="language-js">// 클라이언트 &gt; 패치 url  http://localhost:3030/orange

router.get(&#39;/:username&#39;, isLogined, async (req, res, next) =&gt; {

  console.log(req.params) // { username : orange }

}
</code></pre>
<ul>
<li>패스파라미터? url 파라미터 라고 부르는드~읏</li>
<li>경로에 <code>:파라미터이름</code> 을 지정해주고, <code>req.params</code>를 확인하면 지정 이름은 <code>key</code>, 클라이언트에서 전달한 이름은 <code>value</code>로 주어진다.</li>
</ul>
<h2 id="query-string-사용하기">query string 사용하기</h2>
<pre><code class="language-js">// 클라이언트 &gt; 패치 url  http://localhost:3030/?username=orange

router.get(&#39;/&#39;, isLogined, async (req, res, next) =&gt; {

  console.log(req.query) // { username : orange }

}</code></pre>
<ul>
<li>클라이언트에서 api요청을 할때 <code>?keyName=value</code> 형태로 요청하게 되면 <code>req.query</code>에서 확인할 수 있다.</li>
<li><strong>🎈 주의 : query string은 말그대로 문자열이다. DB 조회할때 숫자를 사용한다면 꼭 변환해주고 사용하기</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[sequelize config 파일과 raw 옵션]]></title>
            <link>https://velog.io/@hwang-eunji/sequelize-config-%ED%8C%8C%EC%9D%BC%EA%B3%BC-raw-%EC%98%B5%EC%85%98</link>
            <guid>https://velog.io/@hwang-eunji/sequelize-config-%ED%8C%8C%EC%9D%BC%EA%B3%BC-raw-%EC%98%B5%EC%85%98</guid>
            <pubDate>Tue, 08 Sep 2020 16:19:31 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-js">const dotenv = require(&#39;dotenv&#39;);

dotenv.config();

// 모든 모델(테이블)에 적용할 옵션 작성
// 모든 모델(테이블)에 공통 반영된다
const common = {
  charset: &#39;utf8mb4&#39;, // utf8 + 이모티콘 
  collate: &#39;utf8mb4_general_ci&#39;,  // utf8 + 이모티콘 getneral 또는 unicode 적용
  logging: true,
  // query: {
  //   raw: true, // ! 이 옵션 넣으면 result.get에러 발생! 넣지말기^^
  // },
  underscored: true,
  dialectOptions: {
    useUTC: true, //for reading from database
    dateStrings: true, // ! 데이터 로드시 문자열로 가저옴
    typeCast: true, // ! 타임존을 역으로 계산하지 않음
  },
  timezone: &#39;+09:00&#39;, //for writing to database
};
module.exports = {
  development: {
    username: process.env.DB_USER,
    password: process.env.DB_PW,
    database: process.env.DB_NAME,
    host: &#39;localhost&#39;,
    dialect: &#39;mysql&#39;,
    ...common,
  },
  test: {
    username: process.env.DB_USER,
    password: process.env.DB_PW,
    database: process.env.DB_NAME,
    host: &#39;localhost&#39;,
    dialect: &#39;mysql&#39;,
    ...common,
  },
  production: {
    username: process.env.DB_USER,
    password: process.env.DB_PW,
    database: process.env.DB_NAME,
    host: &#39;localhost&#39;,
    dialect: &#39;mysql&#39;,
    ...common,
  },
};</code></pre>
<h1 id="시퀄라이즈-설정">시퀄라이즈 설정</h1>
<h2 id="공통-설정-코드예제">공통 설정 코드예제</h2>
<pre><code class="language-js">const common = {
  charset: &#39;utf8mb4&#39;, // utf8 + 이모티콘 
  collate: &#39;utf8mb4_general_ci&#39;,  // utf8 + 이모티콘 getneral 또는 unicode 적용
  logging: true,
  // query: {
  //   raw: true, // ! 이 옵션 넣으면 result.get에러 발생! 넣지말기^^
  // },
  underscored: true,
  dialectOptions: {
    useUTC: true, // for reading from database
    dateStrings: true, // ! 데이터 로드시 문자열로 가저옴
    typeCast: true, // ! 타임존을 역으로 계산하지 않음
  },
  timezone: &#39;+09:00&#39;, //for writing to database
};</code></pre>
<h3 id="1-타임존-설정하기">1. 타임존 설정하기</h3>
<blockquote>
<p>참고 사이트 : <a href="https://devstudioonline.com/article/sequelize-set-timezone-and-datetime-format-for-mysql">시퀄라이즈 타임존 설정하기</a></p>
</blockquote>
<ul>
<li>위 설정에서 <code>dialectOptions</code>, <code>timezone</code>를 보면 된다.</li>
<li>타임존 설정 전 : <strong>2018-10-18T06 : 45 : 38.000Z</strong> 요런 형태에서</li>
<li>타임존 설정 후 : <strong>2018-10-19 01:08:50</strong> 요런 형태로 </li>
<li>한국 시간 설정을위해 : <code>timezone</code> 옵션에 <code>+9</code> 설정</li>
<li>참고 : 타임존 설정 이후 <code>gnoring invalid configuration option passed to Connection: useUTC. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection</code> 라고 콘솔에 출력된다.</li>
</ul>
<h3 id="2-한글이모지를-위한-charset-설정">2. 한글+이모지를 위한 <code>charset</code> 설정</h3>
<p>내가 사용한 데이터베이스 MySQL을 기준으로, DB에 한글을 담기 위해서는 <code>utf8</code> 설정이 필요하다. 사용자 이름을 담는 필드라면 <code>utf8</code> 만으로 충분하지만, 본문을 담은 필드라면 이모지를 담을수 있는 <code>utf8mb4</code> 설정을 해주어야 한다.
<code>callate</code>옵션 또한 동일한 옵션을 적용하며 <code>general</code> or <code>unicode</code> 중 선택하여 적용한다. <code>unicode</code> 옵션이 더 넓은 범위라고하니 너의 선택!</p>
<blockquote>
<p>참고 사이트 : <a href="https://c10106.tistory.com/2617">general_ci &amp; unicode_ci의 차이점</a></p>
</blockquote>
<h3 id="3-query---raw--true-">3. <code>Query : { raw : true }</code>...</h3>
<p>처음 타임존을 설정하면서 포스팅쓴 엉아가 설정한 옵션을 <code>cmd +C &amp;  cmd +V</code> 로 고스란히 옴겨서 사용했다. 하하하! 모델링 다 하고 api 만들다 보니 Include에서 문제가 발생한다. </p>
<ul>
<li>문제 1 : <code>result.get is not a function..</code><ul>
<li><strong>문제 1</strong>을 해결하기 위해 미친 듯 구글 검색</li>
<li><strong>해결</strong> : 파인더(findAll())옵션에 <code>raw:true, nest:true</code> 추가로 가까스로 해결</li>
<li>하지만 문제 2등장🤧</li>
</ul>
</li>
<li>문제 2 : hasMany(1:다 중 다 일때)관계의, 즉 <code>Feed.hasMany(Image)</code> 일 때, <code>Image</code>가 <strong>배열</strong>에 담겨 반환되야 하는데, <code>raw:true</code> 옵션 덕분에 단일 객체가 되고, 여러장 이미지 결과로 나온다면, 각각 1개씩 여러게에 나뉘어 <strong>중복 출력</strong>되버림!<ul>
<li>문제 해결을 위해 또 미친 듯 구글 검색 : <code>raw:true</code>를 제거해야 한다, id 필드를 새로 만들어라 뭐라.. 말이 많음</li>
<li>해결과정 1 : <code>raw:true</code> 를 제거해라 -&gt; 처음 <strong>문제 1</strong>로 되 돌아감</li>
<li>해결과정 2 : <code>id</code> 필드를 새로 만들어라 -&gt; 별반응 없음</li>
<li>해결과정 3 : 글로벌설정에 <code>query: {raw:ture}</code> 설정을 추가해라 -&gt; 이미 추가되어 있는데?</li>
<li>울며 겨자 먹기로 모든 설정 다 지우고 시도해봄...</li>
<li>해결 : <code>query: {raw:ture}</code>  글로벌 설정 까지 제거하고 시도했더니 정상 출력되었다.</li>
<li>꺅🤧</li>
</ul>
</li>
</ul>
<blockquote>
<p>느낀 점 : <strong>모르는 코드는 넣는 것이 아니다..!</strong>
<code>query: {raw:ture}</code> 이 한줄이 하는 기능도 모른체 일딴 넣고 본 내 잘못으로.. 몇 일 날렸네..</p>
</blockquote>
<h4 id="파인더-옵션-잠깐-살피기-🤓">파인더 옵션 잠깐 살피기 🤓</h4>
<p>findAll, findOne같은 파인더를 사용할 때 반환값 설정을 할 수 있다. 다음과 같은 옵션이 있으니 참고하자! (<em>이번에 내가 사용해보고 문제가 있었던 것들만 정리!</em>)</p>
<ul>
<li><code>plain: true</code> : 결과값의 배열을 단순화 하여 리턴  <code>ex : images : [object,object] =&gt; images : Array</code></li>
<li><code>raw: true</code> : 시퀄라이즈 설정에서 <code>query:{raw:true}</code> 했을 경우 이 옵션을 꼭 넣어줘야 result.get 에러가 안난다. 이 옵션은 리턴 값을 단일 객체로 변형하여 보여준다. 문제는 hasMany의 배열값도 객체로 단일화 해버린다는 것!</li>
<li><code>nest : true</code> : 객체를 계층화 하여 보여준다. raw 옵션과는 항상 쌍으로 다닌다. 설정안하면... <code>&#39;Images.Feed.id&#39; : 값</code>이런식으로 문자열로 키가 보여줌.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Server Error serialzing....]]></title>
            <link>https://velog.io/@hwang-eunji/Server-Error-serialzing</link>
            <guid>https://velog.io/@hwang-eunji/Server-Error-serialzing</guid>
            <pubDate>Fri, 28 Aug 2020 01:13:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>최종 수정 : 2020.10.07(수)</p>
</blockquote>
<h1 id="🥶-error-serialzing-">🥶 Error serialzing ....</h1>
<p><img src="https://images.velog.io/images/hwang-eunji/post/e5cdbd63-402f-4cd9-a5f3-7c9dc81b08d2/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-28%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%209.40.58.png" alt=""><img src="https://images.velog.io/images/hwang-eunji/post/18a55c68-b3d3-45e3-87a4-1df1f851d742/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-28%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%209.44.01.png" alt=""></p>
<pre><code class="language-bash">SerializableError: Error serializing `.initialState.account.user` returned from `getServerSideProps` in &quot;/&quot;.
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value all together.
....</code></pre>
<p>한참 잘 하고 있었는데 두둥 에러등장..</p>
<p>프론트에서 타입스크립트 코드 정리한다고 한참 뒤적거리다가, 콘솔을 확인하니 에러가 등장했다. 이게 또 타입스크립트 만지다 잘못했나? 했지만 아니고, 백엔드 서버가 문제였다. 해더-쿠키 읽어서 유저정보 확인하는 과정에서 정리안된 코드(프론트-백엔드 오가며 작업한것이 화근!🥵) 덕분에 서버에러가 난 것! <strong>코드는 마무리 될 때까지... or 뒷정리를 잘하자! 😫</strong></p>
<h2 id="원인">원인</h2>
<p>결론은 백엔드서버에서 동일한 상태코드 응답을 2회 작성 했을때 에러발생시킴(<strong>다른 상태코드로 응답할 경우 에러 안났음</strong>)
여기서 원인 찾는데 고생한 이유 중 하나는 프론트에서 구현한 저 변수명 때문인데, 참 바보같이.. 화면에 <code>ServerError</code> 라고 잘 쓰여있구만 프론트에서 뒤적뒤적 거렸다~</p>
<ul>
<li><code>initialState.account.user</code> : 리덕스 스토어의 상태, 유저데이터를 담는다.</li>
<li><code>getServerSideProps</code> : nextjs의 서버사이드랜더링 함수</li>
</ul>
<p>결국 유저데이터 업데이트 할때 문제가 생긴다는 것을 알았고, 서버를 확인하니, 바로 문제해결 스타또오!</p>
<ul>
<li><code>undefined</code>는 직렬화되지 못하기에 <strong><code>null</code> 로 대체</strong> 되도록, 또는 <strong>undefined가 발생하지 않도록</strong> 해야함.</li>
<li>왜 <code>undefined</code>가 발생 되었는지 찾아보잤!</li>
</ul>
<h2 id="문제의-코드">문제의 코드</h2>
<pre><code class="language-js">/** @쿠키유저정보 */
router.get(&#39;/match-cookie&#39;, async (req, res) =&gt; {
  try {
    // console.log(&#39;쿠킹?&#39;, req.cookies);
    if (req.cookies &amp;&amp; req.cookies[&#39;egg-sns-token&#39;])
      return res.status(200).json({
        message: &#39;success&#39;,
        user: {
          id: 1,
          userName: &#39;hwang&#39;,
          email: &#39;hwang@naver.com&#39;,
          phoneNumber: &#39;000-0000-0000&#39;,
          fullName: &#39;hwang eunji&#39;,
          imageUrl: null,
          content: &#39;안농하세영&#39;,
          secretMode: false,
        },
      });

    console.log(&#39;쿠키엄떠&#39;);
    return res.status(200).json({ message: &#39;empty-cookie-data&#39; }); // 여기서에러
    // return res.status(400).json({ message: &#39;empty-cookie-data&#39; }); // 다른 상태코드 보내면 안남 !
  } catch (error) {
    console.log(&#39;에러인가?&#39;);
    res.status(500).json({ message: &#39;server-error&#39; });
  }
});</code></pre>
<h2 id="마무리-😇">마무리 😇</h2>
<p>근대 .. 나만 저 콘솔에러 내용이 어려운가? 직렬화가 뭐야.. 여기서 직렬화만 알았어도 쉽게 해결했을 것 같은데, 직렬화 저 Serializable 만 알았어도!  궁금할때 배워야 더 빨리 배운다. 검색해보자!</p>
<blockquote>
<p><a href="https://ko.wikipedia.org/wiki/%EC%A7%81%EB%A0%AC%ED%99%94">위키백과 <strong>직렬화</strong></a> 
<a href="https://m.blog.naver.com/PostView.nhn?blogId=magnking&amp;logNo=221156324082&amp;proxyReferer=https:%2F%2Fwww.google.com%2F">쉽게읽는 프로그래밍 : 직렬화(serialization)란?</a> &lt;- 아주 순한맛 추천
<a href="https://woowabros.github.io/experience/2017/10/17/java-serialize.html">우아한형재-자바직력화 훓어보기 편</a>
<a href="https://brunch.co.kr/@oemilk/179">브런치 Effective Java  - 직렬화(serialization)</a></p>
</blockquote>
<h3 id="직렬화">직렬화</h3>
<p>이해한 것을 정리해보면,</p>
<blockquote>
<p>객체(또는 데이터)를 다른 외부 시스템에서 사용하려 할 때, <strong>바이트(byte)형태</strong>로 변환하여 보내 사용(=== 직렬화), 사용처에서는 바이트형태의 데이터를 객체 또는 데이터로 복구(=== 역직렬화)시키는 사용한다.</p>
</blockquote>
<ul>
<li>직렬화 하는 형태는 바이트/문자열/이진 등</li>
<li>클라이언트와 백엔드간 통신에 <strong>JSON</strong>을 주고받는 것이 문자열 직렬화 방식!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Syntax error: 'import' and 'export' may only appear at the top level]]></title>
            <link>https://velog.io/@hwang-eunji/Syntax-error-import-and-export-may-only-appear-at-the-top-level</link>
            <guid>https://velog.io/@hwang-eunji/Syntax-error-import-and-export-may-only-appear-at-the-top-level</guid>
            <pubDate>Thu, 27 Aug 2020 19:47:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/hwang-eunji/post/20cc9955-b364-4f6e-896c-04d2888bad52/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-28%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%204.16.13.png" alt=""></p>
<h1 id="😰-에러발생">😰 에러발생!</h1>
<p>Syntax error 구문/문법 에러가 발생했다. 어딘가에 (<code>,</code> , <code>;</code>, <code>{}</code>,<code>()</code>)을 빼먹었겠지? 라고 생각했는데 에러 설명이 장황하다❗️먼저 문제가 발생한 코드를 위치를 확인했다. 하필이면 <code>redux-saga</code>파일에서..? , 이제 막 써보려고 하는데 에러를 마주하니 <del>갑자기 무쓰워 지고.. 나는 왜 점점 작아지는지..</del></p>
<h2 id="문제발생-위치확인">문제발생 위치확인</h2>
<pre><code class="language-bash">error - ./store/account/saga.ts:83:1
Syntax error: &#39;import&#39; and &#39;export&#39; may only appear at the top level (83:0)

  81 | 
  82 | 
&gt; 83 | export default function* accountSaga(): SagaIterator {
     | ^
  84 |   yield all([fork(watchRequestSignUp), fork(watchReqeustLogIn),fork(watchRequestUserData)]);
  85 | }
  86 | </code></pre>
<ul>
<li><code>saga.ts</code> 파일에서 모듈내보낼 때 에러가 났다고 표시가 나지만, 해당 위치에는 문제는 없었다.</li>
</ul>
<h2 id="다시-원점으로-🎶🎵">다시 원점으로.. 🎶🎵</h2>
<p>알려주는 단서로는 잘모르겠구만! 🎶
구글검색 스따또 ~ 🎵</p>
<pre><code class="language-js">const foo = () =&gt; {
  return (
    &#39;bar&#39;
  );
}; &lt;== this bracket was missing

export default foo;</code></pre>
<p><strong>또잉 ? 그저 괄호 빼먹었다구?</strong>
다시 한번 내 코드를 확인했다.
코드는 빨간줄 없이 깨끗하니. 린트가 안먹는건지 정말 문제가 없는건지? 긴가 민가 하다 깨달아버렸다잉!</p>
<h2 id="이유">이유!</h2>
<blockquote>
<ul>
<li>최상단 함수에서 괄호하나를 빼먹음</li>
</ul>
</blockquote>
<ul>
<li>중간 괄호가 빼먹었다면 밑줄이 쫙쫙 그어졌겠지만, 최고 밖 <code>}</code>를 빼먹었기에, 이하 함수들이 내부 함수가 되어버림</li>
<li>최하단 까지 도달하여 <code>export default</code> 키워드가 등장했는데, 닫침 괄호가 없어, <code>export default</code>가 함수 내부에 위치 함</li>
<li>때문에 <code>&#39;import&#39; and &#39;export&#39; may only appear at the top level&#39;</code>이라고 최고 밖에서 사용하라고 에러출력</li>
</ul>
<pre><code class="language-js">// 문제의 코드
import 블라블라 from &#39;블라블라&#39;;

function* A () {
  try {
    //...
  } catch (error) {
    //...
  }
// } &lt;- 여기 닫는 중괄호 빼먹고 
// 당연히 이하 B,C.. 코드는  A 내부에 선언되고,
    function* B () {
      try {
        //...
      } catch (error) {
        //...
      }
    }  
    // .. 중략
    // 내부 함수인 accountSaga함수가 export default 될수 없다고 에러가 호출 
    export default function* accountSaga() {
      yield all([
        fork(A),
        fork(B),
        fork(C),
      ]);
    }</code></pre>
<p><img src="https://images.velog.io/images/hwang-eunji/post/ca9b7c1f-1ac7-44d2-bdca-627b87e6b013/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f6d61782f313030302f302a37323256624576442d4935544d70784f2e676966.gif" alt=""></p>
<h1 id="😑">😑</h1>
<p>결론은 처음 생각한 <code>어딘가에 (, , ;, {},())을 빼먹었겠지?</code>!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript Curring]]></title>
            <link>https://velog.io/@hwang-eunji/Javascript-Curring</link>
            <guid>https://velog.io/@hwang-eunji/Javascript-Curring</guid>
            <pubDate>Sat, 15 Aug 2020 14:10:23 GMT</pubDate>
            <description><![CDATA[<h1 id="curring">Curring</h1>
<ul>
<li>커링(curring), 커리 함수(curried function)</li>
<li>함수 내부에서 변수선언 없이 바로 함수를 리턴</li>
<li><strong>JS에서는 클로져의 원리로 구현</strong>되지만, 이런 패턴의 코드를 <strong>커링이라고 구분지어 부름</strong></li>
<li>화살표함수가 값을 바로 리턴한다면 중괄호와 <code>return</code> 키워드를 생략하여 작성<pre><code class="language-js">// () 와 {}, return 키워드를 사용한 curring 작성
const curring = (arg1) =&gt; {
return (arg2) =&gt; {
  return arg1 + arg2;
}
}
// 생략할 것 다 생략한 curring 작성
const curring = arg1 =&gt; arg2 =&gt; arg1+arg2;</code></pre>
</li>
</ul>
<blockquote>
<h3 id="🤔-그래서-언제-쓰는거니">🤔 그래서, 언제 쓰는거니?</h3>
<p>함수가 인자를 여러번에 걸쳐 받아 실행해야 하는 상황!</p>
<h3 id="왜-써">왜 써?</h3>
<p>함수의 <strong>재사용성</strong>을 높일수 있음
<strong>라이브러리</strong>와 같이 타인이 작성한 함수를 수정하지 않고 사용할 때 유용</p>
</blockquote>
<ul>
<li>커리함수가 처음 받는 인자 : <strong>설정</strong> or <strong>옵션</strong> 등에 해당하는 값</li>
<li>나중에 받는 인자 : <strong>적용대상</strong>, <strong>값</strong> 등에 해당</li>
</ul>
<h2 id="배열메서드-커링으로-구현">배열메서드 커링으로 구현</h2>
<blockquote>
<p><code>map()</code>,<code>filter()</code>,<code>reduce()</code>,<code>sort()</code>,<code>reverse()</code>,<code>slice()</code>를 커링으로 구현해보자!</p>
</blockquote>
<ul>
<li>원본 배열을 변경하지 않고 새로운 배열 리턴하도록 구현</li>
<li><code>map()</code>,<code>filter()</code>,<code>reduce()</code>,<code>sort()</code>는 <code>CB</code> 인자를 받도록</li>
<li><code>reverse()</code> : 인자 없음</li>
<li><code>slice()</code> : 2개의 숫자 값을 인자로 받음</li>
</ul>
<pre><code class="language-js">const mapArray = (func) =&gt; (arr) =&gt; {
  return arr.map(func);
};

const filterArray = (func) =&gt; (arr) =&gt; {
  return arr.filter(func);
};

const reduceArray = (func, init) =&gt; (arr) =&gt; {
  return arr.reduce(func, init);
};

const sortArray = (func) =&gt; (arr) =&gt; {
  const newArr = [...arr];
  return newArr.sort(func);
};

const reverseArray = () =&gt; (arr) =&gt; {
  const newArr = [...arr];
  return newArr.reverse();
};

const sliceArray = (start, end) =&gt; (arr) =&gt; {
  return arr.slice(start, end);
};

const numberNames = mapArray((e, i) =&gt; {
  return `${i + 1}. ${e}`;
});
</code></pre>
<blockquote>
<p>음.. 책에 수록된 내용을 따라해봤지만, 실제로 어떻게 활용되는지 감이 잘 안잡힌다 😱... 실무에 쓰는 날이 오길</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript Closure]]></title>
            <link>https://velog.io/@hwang-eunji/Javascript-Closure</link>
            <guid>https://velog.io/@hwang-eunji/Javascript-Closure</guid>
            <pubDate>Sat, 15 Aug 2020 11:22:34 GMT</pubDate>
            <description><![CDATA[<h1 id="클로져closure">클로져(Closure)</h1>
<p>클로져는 자바스크립트의 함수가 갖는 특징 중 하나의 함수 형태를 말한다.
자바스크립트에서 함수는 <strong>1급</strong>, number, string과 같이 <strong>값으로 취급</strong>하게 된다. 즉, 값이될 수 있는 함수는 함수의 <strong>인자</strong>로서 받거나 <strong>리턴</strong>할 수 있게 된다. 이것을 활용하여, 특정 함수로만 접근할수 있는 값을 만드는 것(<strong>함수 스코프 활용</strong>)이 클로져의 개념!</p>
<pre><code class="language-js">// 예제코드 1
const func1 = () =&gt; {
  const name = &#39;hwang&#39;;
  const closureFunc = () =&gt; {
    console.log(name);
  };
  return closureFunc;
};

const result = func1();
result(); // &#39;hwang&#39;
console.log(name); // 스코프가 때문에 name에 접근 할 수 없음!
            ^
// ReferenceError: name is not defined</code></pre>
<h2 id="응용-1">응용 1</h2>
<p><code>예제코드 1</code>에서 본것처럼 고정값을 반화하는 클로져는 거의 사용되지 않으며, 보통 첫번째 함수의 인자로 값을 전달하면 인자를 변형하는 값을 출력하는 방식으로 사용된다.</p>
<pre><code class="language-js">// 예제코드 2
const func2 = (name) =&gt; {
  const greeting = name +&#39;님 안농~!&#39;
  const printGreeting = ()=&gt;{
    console.log(greeting)
  }
  return printGreeting
}
const result2 = func2(&#39;hwang&#39;)
result2() // &#39;hwang님 안농~!&#39;</code></pre>
<blockquote>
<h3 id="그래서-🤔-클로져는-누구야-">그래서, 🤔 클로져는 누구야 ?</h3>
<p>최고 밖에 선언된 함수 ? 내부에 선언된 함수? 누가 클로져인데!?
<strong>3개의 함수가 등장하는데 결론적으로 클로져는 <code>result2</code>이다!</strong></p>
</blockquote>
<h2 id="응용-2">응용 2</h2>
<blockquote>
<p>클로저 함수를 통해 내부 값을 수정/로드 할 수 있게 작성 (<strong><code>get()</code>,<code>set()</code>의 방식</strong>)</p>
</blockquote>
<pre><code class="language-js">// 예제코드 3
const func3 = (name) =&gt; {
  const greeting = () =&gt; console.log(name + &#39;님 반갑습니다앗!&#39;);
  const getValue = () =&gt; {
    return console.log(name);
  };
  const setValue = (newName) =&gt; {
    name = newName;
    return console.log(name);
  };
  return {
    print: greeting,
    get: getValue,
    set: setValue,
  };
};

const { print, get, set } = func3(&#39;hwang&#39;);
print(); // hwang님 반갑습니다앗!
get(); // hwang
set(&#39;미미&#39;); // 미미</code></pre>
<h2 id="응용-3">응용 3</h2>
<blockquote>
<p><code>set(value)</code>의 <strong>입력검증</strong>과 <strong>기록처리</strong>하기</p>
</blockquote>
<pre><code class="language-js">// 입력검증 &amp; 기록처리 예제
const func4 = (name) =&gt; {
  // 기록할 배열 선언
  const historyArray = [];
  const history = () =&gt; {
    // 기록 출력용 메서드
    return historyArray;
  };
  const setName = (newName) =&gt; {
    // 매개변수 타입 검사
    if (typeof newName === &#39;string&#39;) {
      name = newName;
      // set메서드로 새로운 이름 작성될때마다 기록
      historyArray.push({ code: &#39;이름변경&#39;, newName });
      return name;
    } else {
      return &#39;문자열이 아님&#39;;
    }
  };
  const getName = () =&gt; {
    // get메서드로 새로운 이름 작성될때마다 기록
    historyArray.push({ code: &#39;이름로드&#39;, name });
    return name;
  };
  const printGreeting = () =&gt; {
    return name + &#39;님, 안녕!&#39;;
  };
  return {
    set: setName,
    get: getName,
    history,
    print: printGreeting,
  };
};

const result = func4(&#39;황&#39;);
console.log(result.get());
console.log(result.set(&#39;마마&#39;));
console.log(result.set(88));
console.log(result.history());
// [
//   { code: &#39;이름로드&#39;, name: &#39;황&#39; },
//   { code: &#39;이름변경&#39;, newName: &#39;마마&#39; },
// ];</code></pre>
<h2 id="응용-4">응용 4</h2>
<blockquote>
<ul>
<li>잠금/잠금해제 기능 추가</li>
</ul>
</blockquote>
<ul>
<li><code>validateLocked()</code> 작성하여 잠금상태 확인 코드 분리<blockquote>
<ul>
<li>암호 추가/변경</li>
</ul>
</blockquote>
</li>
<li><code>validatePw()</code> 작성하여 비밀번호 확인 코드분리</li>
</ul>
<pre><code class="language-js">const func5 = (initPw) =&gt;{
  // 잠금상태와 비밀번호 변수 정의
  let isLock = true;
  let pw = initPw;

  // 비밀번호 확인 함수 작성
  const validatePw = inputPw =&gt; {
    if (!pw === inputPw) {
      console.log(&#39;암호틀림&#39;)
      return false
    }
    return true
  }
  // 잠금상태 확인 함수 작성
  const validateLocked = () =&gt; {
    if (isLock) {
      console.log(&#39;잠금상태&#39;);
      return false;
    }
    return true
  }
  // &#39;잠금상태&#39;로 설정
  const lock = () =&gt; {
   isLock = true;
  }
  // &#39;잠금해제&#39;로 설정
  const unlock = (curPw) =&gt; {
    if (!validatePw(curPw)) return false;
    isLock = false;
  }
  // 비밀번호 변경 메서드
  const password = (curPw, newPw) =&gt; {
    // 현재 비밀번호 맞는지 체크
    if (!validatePw(curPw)) return false;
    // 비번 맞을경우 newPw로 변경
    pw = newPw;
  } 
  const 그밖에_메서드 = () =&gt; {
    // 잠금상태확인하고 메서드 실행
    if (!validateLocked()) return false;
    return 반환 값;
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript Array method]]></title>
            <link>https://velog.io/@hwang-eunji/Javascript-Array-method</link>
            <guid>https://velog.io/@hwang-eunji/Javascript-Array-method</guid>
            <pubDate>Sat, 15 Aug 2020 10:29:39 GMT</pubDate>
            <description><![CDATA[<h1 id="1-원본-배열을-변형하는-메서드">1. 원본 배열을 변형하는 메서드</h1>
<p>아래 나열된 7개의 메서드는 원본 배열을 변형시키는데, 이를 <strong>side effect(부수효과)</strong> 라고 한다. 이런 <strong>side effect</strong>를 갖는 함수(or 메서드)는 코드의 복잡도와 버그 발생확률을 높이는 원인 중 하나다. 그렇기 때문에 아래 메서드를 사용하기 보다 다음에 <a href="#2-%EB%B3%80%ED%98%95%EB%B0%B0%EC%97%B4%EB%A5%BC%EB%B0%98%ED%99%98%ED%95%98%EB%8A%94%EB%A9%94%EC%84%9C%EB%93%9C">2. 변형 배열를 반환하는 메서드</a>에서 소개하는 메서드를 사용을 우선시 하자~!</p>
<pre><code class="language-js">let arr = [1,2,3,4,5]

arr.push(0) // [1, 2, 3, 4, 5, 0] 변형된 배열의 length 리턴, 맨 뒤에 요소 추가
arr.pop() // [ 1, 2, 3, 4 ] 제거한 요소 리턴, 맨 뒤 요소 제거
arr.shift() // [ 2, 3, 4, 5 ]  제거한 요소 리턴 , 맨 앞 요소 제거 //
arr.unshift(9) // 6 ,[ 9, 1, 2, 3, 4, 5 ] 변형된 배열의 length 리턴, 맨앞에 요소 추가
arr.splice(0); // 변경된 배열 리턴 [ 1, 2, 3, 4, 5 ]
arr.splice(1);
arr.splice(4); // 잘라낸 값 리턴 [ 5 ], 결과는 남은 배열

let arr2 = [22,1,555,11,4,33]
arr2.sort() // 각 값을 문자열로 변형한뒤 사전순으로 정렬, 변형된 배열을 리턴 [ 1, 11, 22, 33, 4, 555 ]
arr2.reverse() // 변형된 배열을 리턴, [ 33, 4, 11, 555, 1, 22 ]
</code></pre>
<h2 id="1-push--추가">1) <code>push()</code> : 추가</h2>
<ul>
<li>리턴 : 변형된 배열의 length 리턴</li>
<li>결과 : 배열의 <strong>맨 마지막</strong>에 요소 <strong>추가</strong></li>
</ul>
<h2 id="2-pop--제거">2) <code>pop()</code> : 제거</h2>
<ul>
<li>리턴 : 제거한 요소 리턴</li>
<li>결과 : 배열의 <strong>맨 마지막</strong>에 요소 <strong>제거</strong></li>
</ul>
<h2 id="3-shift--제거">3) <code>shift()</code> : 제거</h2>
<ul>
<li>리턴 : 제거한 요소 리턴</li>
<li>결과 : 배열의 <strong>맨 앞 요소 제거</strong></li>
</ul>
<h2 id="4-unshift--추가">4) <code>unshift()</code> : 추가</h2>
<ul>
<li>리턴 : 변형된 배열의 length 리턴</li>
<li>결과 : 배열의 <strong>맨 앞 요소 추가</strong></li>
</ul>
<h2 id="5-sort--정렬">5) <code>sort()</code> : 정렬</h2>
<blockquote>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort"><code>sort()</code> 메서드의 정렬방식 : mdn</a></p>
</blockquote>
<p>값을 문자열로 변형한뒤 사전순으로 정렬한다. 인자로 compareFunction을 넘기면 해당 함수에 따라 정렬된다.</p>
<ul>
<li>리턴 : 변형된 배열을 리턴</li>
<li>결과 : 정렬 적용</li>
</ul>
<h3 id="오름차순">오름차순</h3>
<pre><code class="language-js">const orderNum1 = arr =&gt; {
  arr.sort((left, right)=&gt;{
  if (left &lt; right) {
    return -1;
  }
  if (left &gt; right) {
    return 1;
  }
  // a must be equal to b
  return 0;
})
}</code></pre>
<h3 id="내림차순">내림차순</h3>
<pre><code class="language-js">const orderNum1 = arr =&gt; {
  arr.sort((left, right)=&gt;{
  if (left &lt; right) {
    return 1;
  }
  if (left &gt; right) {
    return -1;
  }
  // a must be equal to b
  return 0;
})
}</code></pre>
<h2 id="6-reverse--뒤집기">6) <code>reverse()</code> : 뒤집기</h2>
<ul>
<li>리턴 : 변형된 배열을 리턴</li>
<li>결과 : 정렬 적용</li>
</ul>
<h2 id="7-splicestart-range--잘라내기">7) <code>splice(start, range)</code> : 잘라내기</h2>
<p>잘라낼 배열의 인덱스를 인자로 지정</p>
<ul>
<li>매개변수 갯수에 따른 결과<ul>
<li>1개 : 지정 인덱스부터 끝까지</li>
<li>2개 : 시작 인덱스, 지정 길이</li>
</ul>
</li>
<li>리턴 : 잘라낸 배열이 리턴</li>
<li>결과 : 나머지 배열이 리턴</li>
</ul>
<h1 id="2-변형-배열를-반환하는-메서드">2. 변형 배열를 반환하는 메서드</h1>
<p>원본 배열을 변형하지 않고 새로운 배열을 반환하는 메서드를 배열접근 메서드라 부른다.</p>
<h2 id="1-concat">1) <code>concat()</code></h2>
<p>원본배열을 복제한뒤 인자로 받은 값을 배열 맨뒤에 추가하여 새로운 결과 리턴, 여러개의 인자를 받을 수 있다.</p>
<pre><code class="language-js">const originArr = [2,22]

// push() 대체하기
const newArr = originArr.concat(3,[4,44])
console.log({originArr, newArr})
// { originArr: [ 2, 22 ], newArr: [ 2, 22, 3, 4, 44 ] }

// unshift() 대체하기
const newArr2 = ([&#39;a&#39;]).concat(originArr);
console.log(newArr2) // [ &#39;a&#39;, 2, 22 ]</code></pre>
<ul>
<li>리턴 : 새로운 배열을 리턴</li>
<li>인자로 배열(<code>[4,44]</code>)이 입력되면, 배열에 속한 각각의 값이 1개의 인덱스(<code>newArr: [ 2, 22, 3, 4, 44 ]</code>)로 합쳐진다!</li>
<li><code>push()</code>, <code>unshift()</code>를 대체할 수 있다</li>
</ul>
<h2 id="2-slicestartend">2) <code>slice(start,end)</code></h2>
<p><code>splice()</code>와 매개변수의 사용이 다름.</p>
<ul>
<li>1번 인자 : 시작 index</li>
<li>2번 인자 : 끝 지점, 포함되지 않는 index.</li>
<li>start-index는 포함되며, end-index -1의 값까지 포함하여 잘라냄... 말보다 코드!<pre><code class="language-js">const arr = [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;]
const newArr1 = arr.slice(1)
const newArr2 = arr.slice(1,2)
const newArr3 = arr.slice(1,3)
console.log({newArr1,newArr2,newArr3})
// { 
//   newArr1: [ &#39;b&#39;, &#39;c&#39;, &#39;d&#39; ],
//   newArr2: [ &#39;b&#39; ],
//   newArr3: [ &#39;b&#39;, &#39;c&#39; ]
// }</code></pre>
</li>
</ul>
<h2 id="3-mapcb">3) <code>map(CB)</code></h2>
<p><code>CB</code> 에는 3개의 매개변수가 오는데 첫번째 매개변수는 배열순회 각 값, 두번째 매개변수는 해당 값의 index, 세번째 매개변수는 원본 배열이 위치함.</p>
<pre><code class="language-js">const arr = [&#39;apple&#39;,&#39;banana&#39;,&#39;citron&#39;]
const newArr = arr.map((currentValue, currentIndex, originArray)=&gt;{
  // 여기에 할 것 ~
  console.log(currentValue,currentIndex) 
  // &#39;apple&#39;, 0
  // &#39;banana&#39;, 1
  // &#39;citron&#39;, 2
  return currentValue.length &gt; 5 ? currentValue : false
})

console.log(newArr) // [ false, &#39;banana&#39;, &#39;citron&#39; ]</code></pre>
<h2 id="4-filtercb">4) <code>filter(CB)</code></h2>
<p><code>CB</code>는 <code>map()</code>메서드와 동일하다.  조건을 걸어 해당 조건이 참일때 값만 모은 배열을 리턴한다.</p>
<pre><code class="language-js">const arr = [&#39;apple&#39;,&#39;banana&#39;,&#39;citron&#39;]
const newArr = arr.filter((currentValue, currentIndex)=&gt;{
  // 여기에 할 것 ~
return currentValue.length &gt; 5
})
console.log(newArr) // [ &#39;banana&#39;, &#39;citron&#39; ]</code></pre>
<h2 id="5-reducecb초기값">5) <code>reduce(CB,초기값)</code></h2>
<p><code>reduce()</code>의 <code>CB</code>는 <code>map()</code>, <code>filter()</code>와는 조금 다르다.</p>
<ul>
<li>누산기 역할의 매개변수가 1번 인자로 위치</li>
<li>초기값에 배열순회하며 리턴되는 값을 누적하여 최종 리턴함</li>
</ul>
<pre><code class="language-js">arr.reduce((acc,currentValue,currentIndex,originArray)=&gt;{
  console.log(&#39;리듀스&#39;,{acc,currentValue,currentIndex,originArray})
},&#39;&#39;)

// &#39;리듀스&#39; {
//   acc: &#39;&#39;,
//   currentValue: &#39;a&#39;,
//   currentIndex: 0,
//   originArray: [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39; ]
// }
// &#39;리듀스&#39; {
//   acc: undefined,
//   currentValue: &#39;b&#39;,
//   currentIndex: 1,
//   originArray: [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39; ]
// }
// &#39;리듀스&#39; {
//   acc: undefined,
//   currentValue: &#39;c&#39;,
//   currentIndex: 2,
//   originArray: [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39; ]
// }
// &#39;리듀스&#39; {
//   acc: undefined,
//   currentValue: &#39;d&#39;,
//   currentIndex: 3,
//   originArray: [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39; ]
// }</code></pre>
<h3 id="리듀서-구현-예">리듀서 구현 예</h3>
<p><code>reduce()</code>를 사용하다보면 누산기 <code>acc</code>의 값을 직접적으로 변형하기도 하고, <strong>객체 불변성을 유지하며 새로운 값을 리턴</strong>할수 도 있다. 객체 불변성을 유지하는 방식으로 작성하는 것이 <strong>side effect</strong>를 만들지 않고, 코드의 복잡도와 버그 발생확률을 낮칠수 있다.</p>
<pre><code class="language-js">const reducer = arr =&gt; arr
.reduce((acc, curr) =&gt; {
  const { key, value } = curr;

  // acc를 직접 변형하는 방식
  acc[key] = value;
  return acc

  // acc를 변형하지 않고 새로운 객체 리턴하는 방식
  return {
    ...acc,
    [key]: value,
  }
}, {});</code></pre>
<h2 id="5-예외-foreach">5) 예외 :<code>forEach()</code></h2>
<p><code>forEach()</code> 메서드는 원본 배열을 수정하지 않고 순회만 하며, 새로운 배열이 아닌 <code>undefined</code> 리턴한다. for문을 간편하게 쓰는 메서드!</p>
<ul>
<li>리턴 : <code>undefined</code> </li>
<li>원본 배열 수정 : X</li>
</ul>
<h1 id="3-메서드-체이닝method-chaining">3. 메서드 체이닝(method chaining)</h1>
<p>변형 배열를 반환하는 메서드는 메서드 체이닝을 할 수 있다~~</p>
<pre><code class="language-js">const arr = [1,10,100,200,300]
const result = arr
                .filter(data =&gt; data &gt; 100)
                .map(data=&gt;data.toString())
console.log(result) // [ &#39;200&#39;, &#39;300&#39; ]
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[터미널꾸미기 : Oh-my-zsh  테마 & 그 밖에 추가 설정(MacOS)]]></title>
            <link>https://velog.io/@hwang-eunji/%ED%84%B0%EB%AF%B8%EB%84%90%EA%BE%B8%EB%AF%B8%EA%B8%B0-Oh-my-zsh-%ED%85%8C%EB%A7%88-%EA%B7%B8-%EB%B0%96%EC%97%90-%EC%B6%94%EA%B0%80-%EC%84%A4%EC%A0%95MacOS</link>
            <guid>https://velog.io/@hwang-eunji/%ED%84%B0%EB%AF%B8%EB%84%90%EA%BE%B8%EB%AF%B8%EA%B8%B0-Oh-my-zsh-%ED%85%8C%EB%A7%88-%EA%B7%B8-%EB%B0%96%EC%97%90-%EC%B6%94%EA%B0%80-%EC%84%A4%EC%A0%95MacOS</guid>
            <pubDate>Wed, 05 Aug 2020 22:19:07 GMT</pubDate>
            <description><![CDATA[<p>컴퓨터 켜고 터미널을 열었는데 매일보는 터미널의 색상도 질리고, 테마도 질리고~
간만에 새로운 맘으로 터미널을 꾸며볼까~? 하고 기존 설치되어 있던 oh-my-zsh 테마 변경을 찾아봤다.</p>
<blockquote>
<p><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes">zsh 테마 깃헙</a> : 다양한 테마 둘러보세! 🤩</p>
</blockquote>
<p>부트캠프를 다니면서 첫주에 했던것 중 하나가 터미널 꾸미기 였다. 그 당시엔 뭘 하는지도 모르고 따라하기 바뻤는데, 이제와서 보니 그냥 zsh을 다운로드하고 설정한거였구나..나만 몰랐나?
코딩을 배우기 전에는 기본 터미널이 너무 이뻐서 좋았는데 이제는 알록 달록 색으로 명령어와 git상태 표시등이 있다보니 기능적으로 좋아 기존 터미널 보다 선호하게 됐다. 그리고 .. 개발자같아 멋져!😎</p>
<h1 id="터미널-zsh로-변경">터미널 zsh로 변경</h1>
<blockquote>
<p>mac 카탈레나 이후 터미널이 zsh이라는데 그런가요?</p>
</blockquote>
<p>터미널이 bash로 설정되어 있다면 zsh로 변경해주자.
homebrew를 통해 설치하자. (없다면 검색 고고)</p>
<ol>
<li>설치 전 홈브류 업데이트 진행 : <code>brew update</code></li>
<li>zsh 설치 <code>brew install zsh</code> </li>
<li>zsh의 설치 경로 확인 <code>which zsh</code></li>
<li>기본 shell을 변경 <code>chsh -s $(which zsh)</code></li>
</ol>
<h1 id="oh-my-zsh-설치">oh-my-zsh 설치</h1>
<p>zsh 을 설치했으니 zsh 테마를 변경해야 겠죠. 테마변경을 위해 <a href="https://ohmyz.sh/">oh-my-zsh 설치안내</a>에 방문, 설치 명령어를 복사 혹은 아래 명령어를 터미널에 입력!
<code>sh -c &quot;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&quot;</code></p>
<p>나는 이미 설치해서.. 더이상 완료 메세지가 뜨지 않는데, 첫 설치라면 멋진 지셸메세지를 볼수 있다.</p>
<p>먼저 적용하고 싶은 테마를 둘러봤다. 기존 사용하던 테마는 &#39;<strong>agnoster</strong>&#39;였고, 이쁘지만 것두 매일보니 지겨브.. 이번엔 컬러바 없이 깔끔한 문자만 보이도록 설정하려 &#39;<strong>cloud</strong>&#39; 적용!</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/c42ea1b7-1926-4ed0-a8a2-c6859b0408d3/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%206.03.05.png" alt=""></p>
<p>구름모양과 번개가 너무 귀엽!!!!!! 너모나 귀엽둥!!</p>
<h1 id="zshrc-"><code>.zshrc</code> ?</h1>
<p><code>.zshrc</code>는 터미널을 열면 위치하게되는 루트경로에 숨김파일로 있다. 파일명 그대로 <strong>zsh의 설정파일</strong>이다. 에디터를 통해 열어보면 주석처리 잔득과 몇가지 활성화된 코드를 볼수 있다. 설정에 관한 코드고 설명이 잘되어 있어 읽어보고 원하는 부분 주석 on-off하여 설정해보자!</p>
<pre><code class="language-bash"># 빔 으로 파일열기
vi .zshrc

# vscode로 파일열기
code .zshrc</code></pre>
<h1 id="zsh_theme">ZSH_THEME</h1>
<p>설정중 먼저봐야할 것은 지금이 포스팅을 작성하는 이유인 <strong>테마설정</strong>! <code>.zshrc</code> 상단에 바로 위치하기에 쉽게 찾을수 있고, <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes">zsh 테마</a>를 통해 맘에드는 것을 찾고, 테마명만 입력해주면 된다. 너무 간단해서 포스팅하는 의미...😳</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/9dfffdce-20be-42dd-a4fa-cedcada68eea/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%206.14.36.png" alt=""></p>
<p>나는 <strong>cloud</strong> 를 적용! 귀염둥이 구름과 번개가 아주 기대된당!</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/cbbd9e50-0f1f-4e3e-aebb-171b37255bf3/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%206.19.05.png" alt=""></p>
<p>헌대 이게 무슨일이야. 구름이 업더..저 작은..하늘색이 구름일까..
어찌되었던, 이렇게 간단하게 맘에드는 테마를 등록할 수 있습니다. </p>
<h1 id="랜덤테마-설정">랜덤테마 설정</h1>
<p>이쯤되면, -<em>&quot;테마도 다양하니 먼저 써보고 맘에드는 테마에 정착하겠다.&quot;</em>- 라는 생각을 하게 됩니다.(제가요..)</p>
<p>위 테마설정 변수에 테마명을 직접 입력하지 않고, <code>random</code> 을 설정하게 되면 터미널을 열때마다 테마가 변경됩니다. 아주 훌륭한 기능이죠 ?</p>
<h1 id="적용테마-확인-random_theme">적용테마 확인 <code>$RANDOM_THEME</code></h1>
<p>랜덤 설정을 했다면, 지금 적용된 테마가 뭔지 너무나 궁금하게 되겠죠! 이때는 적용테마를 확인하면 되는데,
-<em>그래서 그게 어떻게 하는건데?</em>- 라는 생각을 또 하시겠죠?</p>
<ul>
<li>터미널을 열고</li>
<li>랜덤 테마가 너무나 맘에들어 버렸네? &#39;-<em>어맛! 이 테마 뭐야 ? 당장 적용할랫!</em>-&#39;</li>
<li>터미널 상단에 <code>[oh-my-zsh] Random theme &#39;Soliah&#39; loaded</code> 라고 친적히 적혀있다.</li>
</ul>
<blockquote>
<h2 id="랜덤안내글-제거">랜덤안내글 제거</h2>
<p>만약, <strong>나는 깔끔한 터미널이 좋다!</strong>
터미널 상단에 뜨는 <code>[oh-my-zsh] Random theme &#39;Soliah&#39; loaded</code> 이가 싫다면 제거하자!</p>
<ol>
<li>에디터로 <code>.oh-my-zsh/themes/random.zsh-theme</code> 파일을 열어고 <code>[oh-my-zsh]..</code> 로 시작하는 동일 내을 찾아 해당 코드를 주석처리하자!</li>
</ol>
<pre><code class="language-bash"># 나는 vscode로 파일을 확인했다
$ code .oh-my-zsh/themes/random.zsh-theme

# ---------------------- random.zsh-theme 최하단  해당코드 주석처리 --------------
# ! 터미널 상단 테마 안내문구 출력
# echo &quot;[oh-my-zsh] Random theme &#39;${RANDOM_THEME}&#39; loaded&quot;
</code></pre>
<ol start="2">
<li>이후 <code>echo $RANDOM_THEME</code> 명령어로 현재 설정된 렌덤테마를 확인한다!</li>
</ol>
</blockquote>
<h1 id="터미널을-깔끔하게-표시하기">터미널을 깔끔하게 표시하기</h1>
<p><img src="https://images.velog.io/images/hwang-eunji/post/0b634f62-835e-43e1-bb68-a6f775ecfa43/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%206.55.48.png" alt="">
만약 나처럼     <code>last login : ....일시 On ttys015</code> 같은 안내문이 최상단에 배치된다면?
깔끔하지 못한 저모습 너무나 지우고 싶고 !!!!! 해서 지워보자 찾아보니 역시나 너무 간단하다. 지금까지 왜 저상태로 써왔는지 허허!🥱</p>
<ol>
<li>터미널 열고 루트에 위치하기</li>
<li><code>touch .hushlogin</code> 파일 생성</li>
<li>터미널 새로 열기 : 적용된 깔끔한 터미널 확인가능 !</li>
</ol>
<p><img src="https://images.velog.io/images/hwang-eunji/post/68ad934f-388e-49b4-857a-7f28bc0c83b4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%206.59.06.png" alt=""></p>
<p>행복하다.. </p>
<h1 id="단축키-등록">단축키 등록</h1>
<p>만약 매일 너무나 자주쓰는 긴 단축키가 있다면 <code>.zshrc</code>에 등록할 수 있다.</p>
<ol>
<li>에디터를 통해  <code>.zshrc</code> 파일 열기</li>
<li>원하는 위치에 <code>alias 명령어 = &quot;길다란 명령어를 등록하자!&quot;</code> 와 같이 등록</li>
<li>나는 최하단에 주석처리하여 단축키 등록할 곳을 표시했다.</li>
</ol>
<pre><code class="language-bash"># 여기부터 zsh단축키 등록
# 문법 : alias 단축키=&quot;원래 길다란 명령어를 작성&quot;

alias proj=&quot;cd project/nodejs&quot;</code></pre>
<p>...
자주쓰는 단축키가 아직 없다.
하하하하하 있다면 등록하세요~</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/7f55c5b5-95a2-40eb-bd93-24d5970205de/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%207.17.30.png" alt=""></p>
<p><code>proj</code> 만 입력했더니 지정한 경로로 이동했어요. 호호호 </p>
<h1 id="명령어-자동완성-플러그인-설정">명령어 자동완성 플러그인 설정</h1>
<blockquote>
<p><a href="https://github.com/zsh-users/zsh-autosuggestions">깃헙 : zsh-autosuggestions</a></p>
</blockquote>
<p>명령어가 자동완성되는 아주 편리한 플러그인을 설치하자. 훓어보니 oh-my-zsh을 사용중이라면 아래 방식을 따라야 하나보다 ?</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/8d691db1-41e7-40d4-899d-e302b4724f7f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%207.59.24.png" alt=""></p>
<ol>
<li>플러그인 파일 받기
<code>git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions</code></li>
</ol>
<p><img src="https://images.velog.io/images/hwang-eunji/post/8a023f4f-5e54-4c28-a31d-fb829c38fe28/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%208.01.39.png" alt=""></p>
<ol start="2">
<li><p><code>.zshrc</code> 플러그인 설정
<img src="https://images.velog.io/images/hwang-eunji/post/5f34506b-5ae2-4472-940c-892c4b1b35fe/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%208.03.28.png" alt="">
<code>code .zshrc</code> 명령으로 .zshrc의 내용중 위처럼 플러그인 내용을 찾고 
<code>zsh-autosuggestions</code>을 추가합니다.</p>
</li>
<li><p>터미널 종료후 다시 시작 또는 <code>source ~/.zshrc</code> 를 통해 바로 적용!
아래 사진과 같이 한단어만 작성해도 최근 명령어 or 연관 명령어가 보여진다 !</p>
</li>
</ol>
<blockquote>
<p><code>source</code> 명령어는 스크립트 변경후 바로 적용할때 쓰임</p>
</blockquote>
<p><img src="https://images.velog.io/images/hwang-eunji/post/0a731acc-2362-4d4d-bf43-f29551cb5838/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%208.05.49.png" alt=""></p>
<h1 id="사용자-이름-단순화">사용자 이름 단순화 &gt;</h1>
<p>터미널에 랜덤 테마를 적용하고 나니, 테마마다 내 컴퓨터의 이름 표기법이 다르다. 누구는 없고, 누구는 아주 길게 표기되고.. 어떻게 설정 안될까나 ?</p>
<p>찾아보니 <code>.zshrc</code> 파일을 열고 최하단에 아래 내용을 추가하면 된다는데 나는 테마마다 지멋대로 여전하다!</p>
<pre><code class="language-bash"># 사용자 이름 단순화 적용
prompt_context() { if [[ &quot;$USER&quot; != &quot;$DEFAULT_USER&quot; || -n &quot;$SSH_CLIENT&quot; ]]; then prompt_segment black default &quot;%(!.%{%F{yellow}%}.)$USER&quot; fi }</code></pre>
<p>해서... 테마 마다 다 설정해야 하는가?
일단 테마에서 유저이름이 긴 녀석들 나올때 해당 테마의 설정에 위의 코드를 추가했다.</p>
<ul>
<li>*<em>문제의 테마가 나올때 : <code>code .oh-my-zsh/themes/$RANDOM_THEME.zsh-theme</code> 명령어로 테마설정파일 열기 *</em></li>
</ul>
<pre><code class="language-bash"># 문제의 테마설정 !!!...

ZSH_THEME_GIT_PROMPT_PREFIX=&quot; %{$fg[green]%}&quot;
ZSH_THEME_GIT_PROMPT_SUFFIX=&quot;%{$reset_color%}&quot;
ZSH_THEME_GIT_PROMPT_DIRTY=&quot; %{$fg[red]%}⚡&quot; # 여기에 번개모양이 뜨는게 깃에 내용있을때?? 
ZSH_THEME_GIT_PROMPT_CLEAN=&quot;&quot;

function prompt_char {
    if [ $UID -eq 0 ]; then echo &quot;%{$fg[red]%}#%{$reset_color%}&quot;; else echo $; fi
}

PROMPT=&#39;%(?,,%{$fg[red]%}FAIL: $?%{$reset_color%}
)%{$fg[magenta]%}%n%{$reset_color%}@%{$fg[yellow]%}%m%{$reset_color%}: %{$fg_bold[blue]%}%~%{$reset_color%}$(git_prompt_info) $(prompt_char) &#39;

RPROMPT=&#39;%{$fg[green]%}[%*]%{$reset_color%}&#39;</code></pre>
<p>하하하하하하 녀석 무슨말인지 하나도 모르겠구다 ! 모를때는 저 변수명을 처보자!
열심히 찾은거 같은데? 랜덤설정할때는 추가설정이 안먹히는건가?
결국 cloud 테마의 설정파일에서 구름모양만 잘보이는 이모지로 바꾸고. 저장해서 cloud 테마를 적용했다.</p>
<p>여기까지 디깅한 결과..! 테마설정은 환경변수 설정으로 적용하는 듯 하다? 좀만 더 파면 테마 하나 만들겠구나 ^^</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/2b167079-c84d-4cb6-9699-2ed29f05032e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-06%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%209.03.43.png" alt=""></p>
<p><strong>결국 나는.. cloud 테마 이모지만 잘 뜨도록 수정해서 쓰는중!</strong></p>
<h2 id="oh-my-zsh-업데이트">oh-my-zsh 업데이트</h2>
<p><img src="https://images.velog.io/images/hwang-eunji/post/46097756-ff15-4372-8778-12225518a751/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-18%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.16.46.png" alt=""></p>
<pre><code class="language-bash">$ upgrade_oh_my_zsh
# 또는 
$ omz update</code></pre>
<p>터미널에 <code>upgrade_oh_my_zsh</code> 입력! 햇더니 더이상 쓰지 않는 명령어라며 <code>omz update</code>명령어를 사용하라고 하네요! 아직까지 <code>upgrade_oh_my_zsh</code>명령어를 사용할 수 있지만, 앞으로는 <code>omz update</code> 사용 합시다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Styled-components # nextjs에서 className 오류]]></title>
            <link>https://velog.io/@hwang-eunji/Styled-components-nextjs%EC%97%90%EC%84%9C-className-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@hwang-eunji/Styled-components-nextjs%EC%97%90%EC%84%9C-className-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Sat, 01 Aug 2020 19:33:53 GMT</pubDate>
            <description><![CDATA[<h1 id="warning--props-classname-did-not-match">Warning : Props &#39;className&#39; did not match</h1>
<p><img src="https://images.velog.io/images/hwang-eunji/post/e2b69a34-422e-4144-969a-cdc8ba0f0d72/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%203.40.46.png" alt=""></p>
<p>next로 styled-components로 스타일 적용하고, 개발 서버를 띄워서 확인해보면 첫 페이지 로딩은 문제없이 잘 작동하고, 새로고침 이후 <code>Warning : Props &#39;className&#39; did not match. Server : &quot;블라블라&quot; Client: :&quot;블라블라&quot;</code> 경고메세지가 출력되고, 화면 스타일이 사라져버린다!
첫 페이지는 SSR로 작동하며 이후 CSR로 화면을 렌더링하게 되는데, 이때 서버에서 받은 해시+클래스명과 이후 클라이언트에서 작동하는 해시+클래스 명이 달라지면서 스타일을 불러올수 없는 문제가 발생한다.</p>
<p>이때는 바벨 플러그인 <code>babel-plugin-styled-components</code>를 설치하고 바벨설정을 추가함으로 해결할 수 있다.
이 플러그인은 서버와 클라이언트의 클래스명을 일치 시켜줌으로 문제를 해결!</p>
<p><code>npm i babel-plugin-styled-components</code></p>
<h1 id="babelrc-설정"><code>.babelrc</code> 설정</h1>
<pre><code class="language-js">{
  &quot;presets&quot;: [&quot;next/babel&quot;],
  &quot;plugins&quot;: [&quot;babel-plugin-styled-components&quot;]
}</code></pre>
<p>프로젝트 루트에 <code>.babelrc</code> 파일을 추가했고, 위와 같이 작성한다. <strong>nextjs에서 바벨 설정을 추가할때는 <code>next/bable</code> 프리셋을 항상 추가해야함을 잊지말자!</strong></p>
<p>이후 서버를 다시 켜보면, 경고창은 사라지고, 스타일도 깨지지 않고 잘나온다! 굳굳</p>
<h2 id="추가옵션">추가옵션</h2>
<pre><code class="language-js">{
  &quot;presets&quot;: [&quot;next/babel&quot;],
  &quot;plugins&quot;: [
    [
      &quot;babel-plugin-styled-components&quot;,
      { &quot;fileName&quot;: true, &quot;displayName&quot;: true, &quot;pure&quot;: true }
    ]
  ]
}</code></pre>
<p><a href="https://styled-components.com/docs/tooling#usage">styled-components 바벨옵션 설명</a></p>
<p>바벨 플러그인 설정은 배열로 담아 <code>[0]</code>인덱스에는 <strong>플러그인명</strong>, <code>[1]</code>인덱스에는 <strong>옵션</strong>을 위치시킨다.</p>
<ul>
<li>fileName: 코드가 포함된 파일명을 알려줌</li>
<li>displayName : 클래스명에 해당 스타일 정보  추가</li>
<li>pure : 사용하지 않은 속성 제거<blockquote>
<p>*<em>옵션적용 전/후 클래스명 비교 *</em> </p>
<ul>
<li>전 : sc-17fsht8-0 cbfSeC </li>
<li>후: Header__Container-sc-17fsht8-0 kZvURD </li>
<li>개발모드는 자동 true 설정</li>
</ul>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[svg 파일 react, next에서 사용하기]]></title>
            <link>https://velog.io/@hwang-eunji/svg-%ED%8C%8C%EC%9D%BC-react-next%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hwang-eunji/svg-%ED%8C%8C%EC%9D%BC-react-next%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 01 Aug 2020 19:08:43 GMT</pubDate>
            <description><![CDATA[<h1 id="svgrwebpack-설치"><code>@svgr/webpack</code> 설치</h1>
<blockquote>
<p><a href="https://github.com/gregberge/svgr/tree/master/packages/webpack">@svgr/webpack 깃헙</a></p>
</blockquote>
<p><code>npm i -D @svgr/webpack</code></p>
<ul>
<li>svg파일을 react or next프로젝트에서 사용하자! 먼저 npm에서 svg 로더를 받아야 한다.</li>
</ul>
<h1 id="설정">설정</h1>
<h2 id="next에서-사용">next에서 사용</h2>
<p>next는 <code>next.config.js</code>를 프로젝트 루트에 작성하여 기존 설정을 수정할 수 있게 함</p>
<pre><code class="language-js">//  `next.config.js` 작성하기
module.exports = {
  webpack(config) {
    config.module.rules.push({ // 웹팩설정에 로더 추가함
      test: /\.svg$/,
      issuer: {
        test: /\.(js|ts)x?$/,
      },
      use: [&#39;@svgr/webpack&#39;],
    });

    return config;
  },
};</code></pre>
<h2 id="react에서-사용">react에서 사용</h2>
<h3 id="webpackconfigjs">webpack.config.js</h3>
<pre><code class="language-js">module.exports = {
  // ...생략
  module: {
    rules: [
      //... 로더 생략
      {
        test: /\.svg$/,
        use: [&#39;@svgr/webpack&#39;],
      },
    ],
  },
 // ... 생략
};
</code></pre>
<blockquote>
<p>svgr로더만 설정했을때는 .SVG 파일을 컴포넌트로 가져와서 사용할수 있게된다.</p>
</blockquote>
<pre><code class="language-js">import Star from &#39;./star.svg&#39; // 이미지를 불러오면 컴포넌트에 담김!

const App = () =&gt; (
  &lt;div&gt;
    &lt;Star /&gt; // 컴포넌트로 사용
  &lt;/div&gt;
)</code></pre>
<h2 id="url-loader-와-함께쓰기"><code>url-loader</code> 와 함께쓰기</h2>
<blockquote>
<p>url로 설정하고싶다면 url-loader 추가
<strong>물론 url-loader 설치할 것!</strong>
<code>npm i -D url-loader file-loader</code>
<em>공식문서에는 file-loader도 설정하라고 되어 있는데, 🧐 같이 쓰니적용이 안되는 듯허이... url-loader만 적용</em>
<em>file-loader의 확장자 목록에 추가해봐도 적용 안됨</em></p>
</blockquote>
<pre><code class="language-js">// webpack.confign.js

module.exports = {
  // ...생략
  module: {
    rules: [
      //... 로더 생략
      {
        test: /\.svg$/,
        use: [&#39;@svgr/webpack&#39;,&#39;url-loader&#39;], // file-loader는 적용안됨..
      },
    ],
  },
 // ... 생략
};</code></pre>
<h3 id="url파일명svg-사용하기"><code>url/파일명.svg</code> 사용하기</h3>
<pre><code class="language-js">import starUrl, { ReactComponent as StarComponent } from &#39;./star.svg&#39;

const App = () =&gt; (
  &lt;div&gt;
    &lt;StarComponent /&gt; // 기본 svgr-컴포넌트 방식  
    // url-loader &amp; file-loader 동시 적용 후
    &lt;img src={starUrl} alt=&quot;star&quot; /&gt; // img파일 불러와서 요소에 url적용
    &lt;StarImage&gt; // style속성에 url적용
  &lt;/div&gt;
)
const StarImage = styled.div`
  background-image: url(&#39;/svg-file.svg&#39;);
`;</code></pre>
<blockquote>
<p><strong>svgr-로더만 설정했을때</strong></p>
<ul>
<li>style속성 url()경로 설정가능 : 정적파일제공 폴더인 <code>public</code>경로 이하만 작성 <strong><code>/파일명.svg</code></strong></li>
<li>컴포넌트형으로 이미지 삽입가능</li>
</ul>
<p><strong>url-loader 설정후</strong></p>
<ul>
<li>태그 요소에 src속성에 url 입력가능</li>
</ul>
<p><strong>file-loader 는 설정 적용이 안되서 확인안됨</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Styled-component #3 with typescript]]></title>
            <link>https://velog.io/@hwang-eunji/styled-component-typescript</link>
            <guid>https://velog.io/@hwang-eunji/styled-component-typescript</guid>
            <pubDate>Sat, 01 Aug 2020 17:17:18 GMT</pubDate>
            <description><![CDATA[<h1 id="😗💤">😗💤</h1>
<p>오늘은 글로벌 스타일 적용하고, 스타일 컴포넌트에 타입 적용하는 방법을 해보겠돠.
하루에 아조조~금씩🔨 야금야금🔨</p>
<h1 id="styled-components-설치"><code>styled-components</code> 설치</h1>
<p><code>npm i styled-component</code></p>
<h2 id="타입스크립트---타입정의-받기">타입스크립트 - 타입정의 받기</h2>
<p><code>npm i -D @types/styled-components</code></p>
<h2 id="코드-분리">코드 분리</h2>
<p><code>styled-components</code>를 사용할때 보통 테마/전역스타일 코드를 분리하여 사용한다.
추가로 내가 생성할 <code>styled-components</code>의 타입을 지정하기 위한 <code>styled.d.ts</code> 파일을 추가로 생성하자.</p>
<ul>
<li>스타일-테마 모음 : <code>src/styles/theme.ts</code></li>
<li>스타일-타입정의 모음 : <code>src/styles/styled.d.ts</code></li>
<li>전역-스타일 모음 : <code>src/styles/global-style.ts</code></li>
</ul>
<h2 id="styleddts"><code>styled.d.ts</code></h2>
<p><a href="https://styled-components.com/docs/api#typescript">styled-components 공식문서 : typescript 적용하기</a></p>
<p><code>styled-components</code>의 타입정의를 불러와 내가 사용할 신규 타입정의 추가 &amp; 확장함</p>
<pre><code class="language-ts">// import original module declarations
import &#39;styled-components&#39;

// and extend them!
declare module &#39;styled-components&#39; {
  // 우리가 아는 타입지정을 여기서 다해주고 불러서 쓰기
  // 1. 인터페이스 지정
  export interface 인테페이스명지정 {
    속성1 : 타입지정;
  }
  // 2. 타입속성지정
  export type // 타입~~~지정지정해~

  // ThemeProvider theme에 적용할 타입으로, theme의 속성과 동일하게 작성
  export interface DefaultTheme {
    dark: {
      mainBackground: string;
      // neutral color
      title: string;
      primaryText: string;
      secondaryText: string;
      disable: string;
      border: string;
      divider: string;
      background: string;
      tableHeader: string;
    };
    light: {
      mainBackground: string;
      // neutral color
      title: string;
      primaryText: string;
      secondaryText: string;
      disable: string;
      border: string;
      divider: string;
      background: string;
      tableHeader: string;
      // point-color
      // point-color
    };
    response: {};
  }
}</code></pre>
<blockquote>
<p><code>defaultTheme</code> 인터페이스는 <code>node_modules/@types/styled-components/ts3.7/index.d.ts</code>에 정의되어있다(빈객체 상태). 해당 인터페이스를 확장하는 개념이다! </p>
</blockquote>
<h2 id="createglobalstyle-적용하기"><code>createGlobalStyle</code> 적용하기</h2>
<ul>
<li>reset-css를 적용할 것인데 npm을 둘러보니 styled-components용 reset-css인 <code>styled-reset</code>이 있어 받아보았다.</li>
<li><code>npm i styled-reset</code> 으로 설치</li>
<li>적용방법은 2가지로
 1) styled-reset이 제공하는 <code>&lt;Reset /&gt;</code>컴포넌트를 불러 최상위에 위치시킴
 2) styled-reset이 제공하는 css변수를 <code>createGlobalStyled</code>에 적용</li>
<li>나는 2번으로 적용할 예정, 나중에 추가로 전역 스타일 설정할때 추가해 줄수 있기 때문에~<h3 id="1-reset-으로-전역스타일-설정">1) <code>&lt;Reset /&gt;</code>으로 전역스타일 설정</h3>
<pre><code class="language-ts">import { Reset } from &#39;styled-reset&#39;;
</code></pre>
</li>
</ul>
<p>const App = () =&gt; (
  &lt;&gt;
    <Reset /> {/* 여기에 리셋-컴포넌트 위치 */}
    <div>여기는 최상위 컴포넌트</div>
  &lt;/&gt;
);</p>
<pre><code>### 2) `createGlobalStyled`으로 전역스타일 설정
- 먼저 전역스타일 파일을 생성하여 코드를 분리 : `src/styles/global-style.ts`
- 파일 위치는 원하는 곳에 잘 정리해두기

```ts
// global-style.ts
import { createGlobalStyle } from &#39;styled-components&#39;;
import { reset } from &#39;styled-reset&#39;;

// 외부에서 import 할거니까 모듈 내보내자~!
export const GlobalStyle = createGlobalStyle`
  ${reset}
  /* 그밖에 글로벌 스타일 작성하기  */
`;

// 최상위 컴포넌트 : App.js 또는 index.js 등등 원한느 최상위에 코드 추가 
import {GlobalStyle} from &#39;파일경로/global-style.ts&#39;

const App = () =&gt; (
  &lt;&gt;
    &lt;GlobalStyle /&gt; {/* 여기에 글로벌-스타일-컴포넌트 위치 */}
    &lt;div&gt;여기는 최상위 컴포넌트&lt;/div&gt;
  &lt;/&gt;
);</code></pre><h2 id="공유스타일-작성-theme">공유스타일 작성 (theme)</h2>
<pre><code class="language-jsx">// theme.js
import styled, { css } from &#39;styled-components&#39;;

export const theme:defaulTheme = {
  dark: {
    mainBackground: `#333`,
    // neutral color
    title: `rgba(255,255,255,0.85)`,
    primaryText: `rgba(255,255,255,0.65)`,
    secondaryText: `rgba(255,255,255,0.45)`,
    disable: `rgba(255,255,255,0.25)`,
    border: `rgba(255,255,255,0.15)`,
    divider: `rgba(255,255,255,0.06)`,
    background: `rgba(255,255,255,0.04)`,
    tableHeader: `rgba(255,255,255,0.02)`,
    // point-color
  },
  light: {
    mainBackground: `#fff`,
    // neutral color
    title: `rgba(0, 0, 0, 0.85)`,
    primaryText: `rgba(0, 0, 0, 0.75)`,
    secondaryText: `rgba(0, 0, 0, 0.45)`,
    disable: `rgba(0, 0, 0, 0.25)`,
    border: `rgba(0, 0, 0, 0.15)`,
    divider: `rgba(0, 0, 0, 0.06)`,
    background: `rgba(0, 0, 0, 0.04)`,
    tableHeader: `rgba(0, 0, 0, 0.02)`,
    // point-color
  },
  response: {},
};
  response: {},
};

// _app.tsx or App.jsx
// 최상위컴포넌트에서 ThemeProvider 사용하기
import { ThemeProvider } from &#39;styled-components&#39;;
import { theme } from &#39;./../src/styles/theme&#39;;

// ... 상단 생략
return (// 기본 라이트 모드 지정
  &lt;ThemeProvider theme={theme.light}&gt; 
      &lt;Component /&gt;
  &lt;/ThemeProvider&gt;
)

// Component.tsx or Component.js : 하위 컴포넌트 전체에서 

// 스타일드-컴포넌트 정의
const Container = styled.div`
  background-color: ${(props) =&gt; props.theme.mainBackground};
  color: ${(props) =&gt; props.theme.primaryText};
`;

// 컴포넌트 정의
const Component = () =&gt; {
  return (
    &lt;Container&gt;
      &lt;h1&gt;테마적용하기🎨&lt;/h1&gt;
    &lt;/Container&gt;
  );
};</code></pre>
<ul>
<li><p>theme.dark 모드
<img src="https://images.velog.io/images/hwang-eunji/post/ed799c5b-4714-4efc-add6-e01cb92c56b0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.34.59.png" alt=""></p>
</li>
<li><p>theme.light 모드
<img src="https://images.velog.io/images/hwang-eunji/post/236aedc2-e052-4e45-acc3-ab503cf26d33/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.34.50.png" alt=""></p>
</li>
<li><p>예제와 같이 theme객체에 같은 이름의 key를 갖는 mode객체를 만들어 ThemeProvider 컴포넌트에 props를 넘겨 전체 컴포넌트 모드변경할때 적용색상이 변경하도록 함!</p>
</li>
<li><p>theme 객체를 작성할때 depth가 깊어지지 않도록 주의! 하위컴포넌트에서 <strong>theme속성 적용할 때 이름이 길어진다!</strong></p>
</li>
</ul>
<h2 id="스타일-작성하기">스타일 작성하기</h2>
<p><a href="https://blog.agney.dev/styled-components-&amp;-typescript/">참고 자료 : Styled Components &amp; TypeScript - 😍</a></p>
<h3 id="1-단일-props-사용시">1) 단일 props 사용시</h3>
<ul>
<li>styled-components를 작성할 때 여러개 <code>props</code>를 사용하여 컴포넌트를 정의한다면 인터페이스를 사용하여 분리하여 사용할 수 있다.</li>
<li>컴포넌트에 타입지정할때는 <code>styled.div&lt;인터페이스명&gt;</code> 와 같이 사용한다.</li>
</ul>
<pre><code class="language-tsx">// styled-components에 1개 props 타입지정
// const Container = styled.div&lt; {프롭스명 : 타입지정} &gt;`
const Container = styled.div&lt; { age : number } &gt;`
  color: ${(props) =&gt; (props.age &gt; 20 ? &#39;red&#39; : &#39;gray&#39;)};
`;
</code></pre>
<h3 id="2-다수-props-사용시-interface-작성">2) 다수 props 사용시: interface 작성</h3>
<ul>
<li><strong>인터페이스로 분리하여 타입지정</strong>하는 것 이외에 사용법은 동일!</li>
</ul>
<pre><code class="language-tsx">// Container styled-components에 적용할 interfacer를 작성
interface Container extends 상속타입 {
  isActive: boolean;
  age: number;
  프롭스명: 타입지정;
}
// styled-components에 interface 타입 지정하기
const Container = styled.div&lt;Container&gt;`
  color: ${(props) =&gt; (props.age &gt; 20 ? &#39;red&#39; : &#39;gray&#39;)};
  background-color: ${(props) =&gt; (props.isActive ? &#39;red&#39; : &#39;gray&#39;)};
`;</code></pre>
<h3 id="3-상속-컴포넌트에-타입지정">3) 상속 컴포넌트에 타입지정</h3>
<h4 id="interface-상속받기">interface 상속받기</h4>
<pre><code class="language-tsx">// 상속컴포넌트의 타입 상속받기
interface Container {
  isActive: boolean;
  age: number;
  프롭스명: 타입지정;
}

// 상속받은 컴포넌트에 타입 추가하기
const Container = styled(상속받을 컴포넌트명)&lt;Container&gt;`
  color: ${(props) =&gt; (props.age &gt; 20 ? &#39;red&#39; : &#39;gray&#39;)};
  background-color: ${(props) =&gt; (props.isActive ? &#39;red&#39; : &#39;gray&#39;)};
`;</code></pre>
<h4 id="단일-props-타입지정하기">단일 props 타입지정하기</h4>
<pre><code class="language-tsx">// 기존 방식과 동일하게 사용
const Container = styled(상속받을 컴포넌트명)&lt; { age : number } &gt;`
  color: ${(props) =&gt; (props.age &gt; 20 ? &#39;red&#39; : &#39;gray&#39;)};
`;

// 위 방식에 문제가 있을경우 아래와 같이 사용.. 하나 복잡!
const Container = styled(({ age, ...parentProps }) =&gt; (
  &lt;상속받을컴포명 {...parentProps} /&gt;
))&lt;{
  age: number;
}&gt;`
  color: ${(props) =&gt; (props.active ? &#39;red&#39; : &#39;blue&#39;)};
`;</code></pre>
<ul>
<li>상속컴포넌트명을 <strong>콜백 함수(callback function)</strong>으로 전달</li>
<li>매개변수는 <strong>신규 타입:<code>age</code></strong>과, <strong>부모의 타입:<code>parentProps</code></strong>을 <u>전개연산자(<code>...parentProps</code>)</u>로 지정</li>
<li>신규타입은 제네릭으로 기존과 동일하게 전달!</li>
</ul>
<h2 id="미디어-템플릿-적용">미디어 템플릿 적용</h2>
<ul>
<li>타입스크립트와 크게 관련없지만, 미디어쿼리 구성 참고~ (나중에 필요할 때 보기위한 기록)</li>
<li>보통 디바이스의 폭을 기준으로 나누어작업 (상황에 따라 높이도 적용)</li>
</ul>
<pre><code class="language-tsx">const customMediaQuery = (maxWidth: number):string =&gt; {
  // 최대폭을 입력하면. 문자열을 밷는다!
  return `@media (max-width: ${maxWidth}px)`;
}
// 각 디바이스에 따라 최대폭 값을 변수화
const media = {
  custom: customMediaQuery,
  desktop: customMediaQuery(922),
  tablet: customMediaQuery(768),
  phone: customMediaQuery(576),
};

const Content = styled.div`
  height: 3em;
  width: 3em;
  background: papayawhip;

  ${media.desktop} { 
    background: dodgerblue;
  }
  ${media.tablet} {
    background: mediumseagreen;
  }
  ${media.phone} {
    background: palevioletred;
  }
`;</code></pre>
<p><code>${media.desktop} { color: red;}</code> === <code>@media (max-width: 922px) {color:red}</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Next and Typescript #1 설치]]></title>
            <link>https://velog.io/@hwang-eunji/React-Next-and-Typescript-1-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@hwang-eunji/React-Next-and-Typescript-1-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Fri, 31 Jul 2020 15:06:02 GMT</pubDate>
            <description><![CDATA[<h1 id="cnacreate-next-app">CNA(create-next-app)</h1>
<p>정적 사이트 생성을 위해 next를 사용하기로 했고, 
CNA로 next 프로젝트 생성했다.</p>
<blockquote>
<p><a href="https://nextjs.org/docs/basic-features/typescript">nextjs 공식문서 typescript 사용하기</a>
<a href="https://github.com/vercel/next.js/tree/canary/examples/with-typescript">nextjs+typescript 예제 깃헙</a></p>
</blockquote>
<p><code>npx create-next-app --example with-typescript with-typescript-app</code>
명령을 통해 타입스트립트가 적용된 next를 받는다.</p>
<p>기존 next 모습과 다른것은</p>
<ul>
<li><code>tsconfig.jon</code> 파일 추가</li>
<li><code>next-env.d.ts</code> 파일 추가</li>
<li><code>devDependencies</code> : <code>@types/node</code> <code>@types/react</code> <code>@types/react-dom</code> <code>typescript</code> 추가<ul>
<li><code>node_modules/@types/</code>에 위치하게 된다. 각 패키지의 타입정의 파일이 있다!</li>
</ul>
</li>
<li><code>script :{ &quot;type-check&quot; : tsc }</code> 타입스크립트 실행명령 추가</li>
<li>그 밖에 <code>js</code>, <code>jsx</code> 파일 <code>ts</code>, <code>tsx</code>로 변경</li>
</ul>
<p><code>npm run dev</code> : 개발 서버 실행해보자, 아래 사진과 같은 못난이 페이지가 뜨면.. 본격 시작 ㅋ</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/3078971f-f998-4cb5-ace7-d956f4b061be/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-31%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.50.41.png" alt=""></p>
<h2 id="styled-components">styled-components</h2>
<p><code>npm i styled-components @types/styled-components</code></p>
<ul>
<li>스타일드 컴포넌트, @타입스 설치</li>
</ul>
<h2 id="커스텀-_apptsx">커스텀 _app.tsx</h2>
<p>전체페이지 <strong>레이아웃과 스타일 적용</strong>을 위해 <code>_app.tsx</code>를 커스텀하자! <a href="https://nextjs.org/docs/basic-features/typescript#custom-app">nextjs 공식문서 타입스크립트 커스텀 app 참고</a></p>
<pre><code class="language-tsx">// import App from &#39;next/app&#39;;
import { AppProps /*, AppContext */ } from &#39;next/app&#39;; // 타입 임포트
import Layout from &#39;../components/Layout&#39;; // 레이아웃 컴포넌트 가저오기

function MyApp({ Component, pageProps }: AppProps) {
  return (
    &lt;Layout&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/Layout&gt;
  );
}

// Only uncomment this method if you have blocking data requirements for
// every single page in your application. This disables the ability to
// perform automatic static optimization, causing every page in your app to
// be server-side rendered.
//
// MyApp.getInitialProps = async (appContext: AppContext) =&gt; {
//   // calls page&#39;s `getInitialProps` and fills `appProps.pageProps`
//   const appProps = await App.getInitialProps(appContext);

//   return { ...appProps };
// };

export default MyApp;</code></pre>
<ul>
<li>SSR을 한다면 주석 처리 된 타입 <code>AppContext</code>도 <code>import</code>하여 사용</li>
</ul>
<h2 id="동적라우팅">동적라우팅</h2>
<p><a href="https://nextjs.org/docs/routing/dynamic-routes">nextjs 동적라우팅</a></p>
<ul>
<li>pages 폴더에 <code>post/[id]</code>폴더에 <code>/[id].tsx</code>를 위치하는 식으로 동적라우팅 구현<blockquote>
<p>예</p>
<ul>
<li>파일경로 : <code>/pages/post/create.tsx</code> , URL : <code>도메인/post/create</code></li>
<li>파일경로 : <code>/pages/post/[pid].tsx</code> , URL : <code>도메인/post/1</code>,<code>도메인/post/abc</code></li>
<li>파일경로 : <code>/pages/post/[categori]/[id].tsx</code> , URL : <code>도메인/post/맛집/1</code></li>
<li>파일경로 : <code>/pages/post/[...slug].tsx</code> , URL : <code>도메인/post/1/2</code>,<code>도메인/post/a/b/c</code></li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="data-fetching">Data fetching</h2>
<p>이전에는 getInitialProps()만으로 데이터를 가져왔는데, 몇 가지가 더 늘었다.</p>
<p>상황에 따라 맞는 api를 사용하자. <a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation">nextjs 공식문서 : 데이터 가저오기 API설명</a>에서 더 정확하게 알수 있다.</p>
<blockquote>
<ul>
<li>정적생성 : 사전 렌더링/정적페이지에 사용</li>
</ul>
</blockquote>
<ul>
<li><code>getStaticProps()</code> : <strong>빌드</strong>할 때 데이터를 가져옴</li>
<li><code>getStaticPaths()</code> : 데이터를 기반으로 <strong>사전 렌더링(pre-render) 할 동적 경로</strong>를 지정</li>
<li><code>getStaticProps()</code>와 <code>getStaticPaths()</code> 는 항상 짝으로 사용하자<ul>
<li>SSR</li>
</ul>
</li>
<li><code>getServerSideProps()</code> : </li>
</ul>
<h3 id="getstatcprops"><code>getStatcProps()</code></h3>
<pre><code class="language-ts">// 예제코드

import { GetStaticProps } from &#39;next&#39;; // 타입스트립트 사용시 getStatcProps의 타입임포트

// 데이터 받을 컴포넌트 작성
const ContentList = ({ contentList }) =&gt; {
  // getStatcProps에서 패치받은 데이터 contentList가 props로 전달됨
  return (
    &lt;ul&gt;
      {contentList.map((content) =&gt; (
        &lt;li&gt;{content.title}&lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
};

export const getStaticProps: GetStaticProps = async (context) =&gt; {
  // context의 구성내용
  const { params, preview, previewData } = context;

  // data fetch
  const res = await fetch(&#39;url&#39;);
  const contentLists = await res.json();
  return {
    // 리턴은 객체 props키에 담아 보낸다!
    props: {
      contentList,
    }, // will be passed to the page component as props
    // revalidate 옵션 사용시 1초에 한번 데이터 패치 발생한다! 계속 업뎃~
    revalidate:1, // In seconds
  };
};

export default ContentList;
</code></pre>
<ul>
<li>서버-사이드-렌더링(SSR: server-side-render)에서만 사용되는 api, 즉, js번들에 포함하지 않음</li>
<li><code>pages</code> 폴더에서만 사용</li>
<li>페이지를 사전 렌더링(SEO 적용) &amp; 캐시 될 수 있음</li>
<li>페이지의 데이터가 빌드시 구성됨, (사용자의 요청X)</li>
<li>예: 블로그 페이지가 컨텐츠 관리 시스템(CMS)에서 블로그 게시물 목록을 가져와야 할 때</li>
<li>타입스크립트 타입 : <code>GetStaticProps</code>을 사용하며</li>
</ul>
<blockquote>
<p>만약, 패치데이터의 타입을 유추하길 원한다면 <code>InferGetStaticPropsType</code>로 컴포넌트의 해당 props의 타입을 지정</p>
</blockquote>
<pre><code class="language-ts">import { InferGetStaticPropsType } from &#39;next&#39;;
  const ContentList = ({ contentList }: InferGetStaticPropsType&lt;typeof getStaticProps&gt;)=&gt; {
    // will resolve posts to type Post[]
   }
&gt; type Content = {
  author: string;
  content: string;
};
export const getStaticProps = async () =&gt; {
  const res = await fetch(&#39;https://.../posts&#39;);
  // contentList는 Content 타입으로 구성된 배열 타입 이라고 지정
  const contentList: Content[] = await res.json();
  return {
    props: {
      contentList,
    },
  };
   export default ContentList;</code></pre>
<blockquote>
</blockquote>
<h3 id="getstatcpaths"><code>getStatcPaths()</code></h3>
<p><a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation">nextjs 공식문서 : 정적 페이지의 데이터쓰기</a></p>
<ul>
<li><p>pages폴더에 동적라우팅이 구현되 있을때, <code>getStatcProps</code>를 쓴다면 렌더링할 경로목록을 정의</p>
</li>
<li><p><code>getStatcPaths</code> 에 지정된 경로를 정적으로 사전 렌더링 함</p>
<pre><code class="language-ts">import { GetStaticPaths } from &#39;next&#39;
export async function getStaticPaths() {
return {
  paths: [
    // { params: { ... } }, // See the &quot;paths&quot; section below
    { params: { id: &#39;1&#39; } }, // pages/post/[id].tsx
    { params: { categori: &#39;맛집&#39;,id :&#39;1&#39; } }, // pages/post/[categori]/[id].tsx
    { params: { slug: [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;] } }, // pages/post/[...slug].tsx =&gt; /post/a/b/c
    { params: { slug: false }} // pages/[[...slug]] 폴더일때, 사이트 루트 페이지로 설정,  
  ],
  fallback: true or false // See the &quot;fallback&quot; section below
};
}</code></pre>
</li>
<li><p><code>pages</code> 폴더에서만 사용</p>
</li>
<li><p><code>getStaticProps</code>와 함께사용하며, <code>getServerSisdeProps</code>와 함께 사용할 수 없음!</p>
</li>
</ul>
<h4 id="paths-키"><code>paths</code> 키</h4>
<ul>
<li>위 예제 코드 &amp; <a href="#%EB%8F%99%EC%A0%81%EB%9D%BC%EC%9A%B0%ED%8C%85">동적라우팅</a> 참고하기</li>
<li>키 <code>paths</code> : 필수 키, 미리 렌더링 되는 키를 결정</li>
<li>지정한 경로 이외 루트경로로 이동시키기 : <code>catch-all-routes</code> 검색</li>
</ul>
<h4 id="fallback-키"><code>fallback</code> 키</h4>
<ul>
<li>기본 <code>false</code></li>
<li><code>false</code> 설정 시, 경로 지정 페이지만 사전-렌더링, 없는 경로 접근시 404페이지 렌더링</li>
<li><code>true</code> 설정 시,<ul>
<li>fallback 페이지 렌더링하여 로딩페이지 렌더링</li>
<li>다음, <code>getStaticProps</code>를 실행하여 필요데이터를 가저옴</li>
<li>다음, 가져온 데이터를 미리렌더링 된 정적페이지 보여줌.. <em>서버에서만 실행된다며, 어떻게되지?...</em></li>
</ul>
</li>
</ul>
<pre><code class="language-js">// pages/posts/[id].js
import { useRouter } from &#39;next/router&#39;

const Compo ({ data }) {
  const router = useRouter()

  // 만약 정적생성되지 않은 페이지가 있다면, getStaticProps()가 실행이 끝날때 까지 &#39;Loading&#39; 요소를 반환한다.
  if (router.isFallback) {
    return &lt;div&gt;Loading...&lt;/div&gt;
  }
  return (
    // 여기에, 사전-렌더링-페이지 
  )
}

// 빌드시 동작
export async function getStaticPaths() {
  // 데이터 목록을 받아와 아래와 같이 경로를 추가 할수 있돰
  const response = await fetch(&quot;.../posts&quot;)
  const data = await response.json()

  const paths = data.map(({ id }) =&gt; ({ // [...slug] 형태는 reduce()를 활용하자
    params: { id: String(id) }, // 값은 모두 string 타입으로 넣어야 함
  }))
// paths = [
//   {params : {id:&#39;1&#39;} },
//   {params : {id:&#39;2&#39;} },
//   {params : {id:&#39;3&#39;} },
//   {params : {id:&#39;4&#39;} },
// ]
  return { paths, fallback: false }
}

export async function getStaticProps({ params }) {
  const res = await fetch(`...url/${params.id}`)
  const data = await res.json()
// 데이터를 props로 전달 하며, 요청 시 1초에 한번 다시 패칭
  return {
    props: { data },
    revalidate: 1,
  }
}

export default Post</code></pre>
<h3 id="getserversideprops"><code>getServerSideProps()</code></h3>
<ul>
<li>pages폴더에만 사용가능</li>
<li>서버사이드에서만 실행, <code>getInitialProps()</code>는 양쪽 다 실행되지만, <code>getServerSideProps()</code>는 무조건 서버에서만</li>
<li>페이지 렌더링 전 꼭 필요한 data-fetch!, 매 페이지 요청시마다 호출</li>
<li>context객체는 params, req, res, query, preview, previewData 키를 포함. <a href="https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering">nextjs 공식문서 확인</a><pre><code class="language-ts">import { GetServerSideProps } from &#39;next&#39; // 타입스 임포트
</code></pre>
</li>
</ul>
<p>const Page= ({ data })=&gt; {
  // Render data...
}</p>
<p>// This gets called on every request
export const getServerSideProps:GetServerSideProps = async()=&gt; {
  // Fetch data from external API
  const res = await fetch(<code>https://.../data</code>)
  const data = await res.json()</p>
<p>  // 객체형태로 전달
  return { props: { data } }
}</p>
<p>export default Page</p>
<pre><code>
- getServerSideProps로 부터 전달받은 props를 통해 데이터타입을 유추하려면 `InferGetServerSidePropsType&lt;typeof getServerSideProps&gt;`를 컴포넌트 Props의 타입으로 지정

### `useSWR` hooks
next팀에서 제공하는 hooks로 클라이언트 측에서 데이터를 가져오는 경우 사용하기 권장
[swr 공식문서](https://swr.vercel.app/)
[swr - data-fetching](https://swr.vercel.app/docs/data-fetching) : axios, fetch, graphQl 방식설명
[swr - nextjs : client-side-Data-fetching](https://swr.vercel.app/docs/with-nextjs#client-side-data-fetching)

`const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)`

```js
import useSWR from &#39;swr&#39;

const Profile =()=&gt;{
  const {data, error} = useSWR(&#39;api-url&#39;,fetch)

  if (error) return &lt;div&gt;에러다~&lt;/div&gt;
  if (!data) return &lt;div&gt;loading&lt;/div&gt;
  return &lt;div&gt;{data}&lt;/div&gt;
}
</code></pre><h2 id="정적-파일-제공">정적 파일 제공</h2>
<p>next의 정적 파일 폴더는 <code>public</code>으로 설정되어 있다.</p>
<ul>
<li>원본 이미지 경로 : <code>public/image.png</code></li>
<li>정적파일 사용하기 :  <code>/image.png</code>만 입력, <code>public</code>을 생략하고 작성하면 원하는 이미지가 엑세스 됨</li>
</ul>
<h2 id="타입스크립트-types">타입스크립트 types</h2>
<h3 id="정적-생성-및-서버측렌더링-api">정적 생성 및 서버측렌더링 api</h3>
<p><code>import { GetStaticProps, GetStaticPaths, GetServerSideProps} from &#39;next&#39;</code></p>
<ul>
<li><code>getStaticProps()</code> : types name =<code>GetStaticProps</code></li>
<li><code>getStaticPaths()</code> :types name =  <code>GetStaticPaths</code></li>
<li><code>getServerSideProps()</code> : types name = <code>GetServerSideProps</code></li>
</ul>
<h3 id="라우팅-api">라우팅 api</h3>
<pre><code class="language-ts">import { NextApiRequest, NextApiResponse } from &#39;next&#39;
type Data = {
  name: string
}

export default (req: NextApiRequest, res: NextApiResponse&lt;Data&gt;) =&gt; {
  res.status(200).json({ name: &#39;John Doe&#39; })
}</code></pre>
<h3 id="커스텀-_app">커스텀 _App</h3>
<p><a href="#%EC%BB%A4%EC%8A%A4%ED%85%80-_apptsx">상단 설명참고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[여러 github 계정 사용하기 for mac (SSH 설정)]]></title>
            <link>https://velog.io/@hwang-eunji/github-2%EA%B0%9C-%EA%B3%84%EC%A0%95-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hwang-eunji/github-2%EA%B0%9C-%EA%B3%84%EC%A0%95-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 26 Jul 2020 17:37:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>만약, 하나의 컴퓨터에서 깃헙 계정 2개를 나누어 사용하고 싶다면?
<strong>ssh-key 설정한 뒤, remote 주소를 ssh방식을 사용</strong></p>
</blockquote>
<p><strong>참고 한 &amp; 더 잘 설명된 포스팅들~</strong></p>
<ul>
<li><a href="https://devlog.jwgo.kr/2018/08/17/how-to-use-multi-github-accounts-with-a-machine/">Tonic&#39;s lesson learned</a></li>
<li><a href="https://goddaehee.tistory.com/254">갓대희의 작은공간</a></li>
<li><a href="https://mygumi.tistory.com/96">마이구미의 Helloworld</a></li>
</ul>
<h1 id="시작에-앞서">시작에 앞서</h1>
<ul>
<li>갑자기 깃헙 계정을 새로 만들고 싶어짐, 그리하여 야심차게 계정 하나 추가요😎</li>
<li>New계정의 레포를 사용하려니 기존 계정과 겹치면서 퍼미션-둥-둥!😨</li>
<li>글로벌 <code>~/.gitcongig</code> 과 로컬 <code>프로젝트루트/.git/config</code>에 설정된 계정 정보를 바꿔도 안됨! 멘-붕😱<ul>
<li>글로벌 &lt; 로컬 설정 우선시 한다하여.. 수정했지마눙 안됨😂</li>
</ul>
</li>
<li>그리하여 ssh를 찾아보게 되었고, 핳 새로운 영역..😃</li>
</ul>
<blockquote>
<h3 id="ssh시큐어-셸-secure-shell">SSH(시큐어 셸, Secure Shell)</h3>
<p>네트워크로 다른 컴퓨터에 로그인/원격시스템에 명령을 실행, 파일복사를 할 수있게 하는 응용프로그램 또는 프로토콜
SSH는 암호화 기법을 사용하기 때문에, 통신이 노출된다고 하더라도 이해할 수 없는 암호화된 문자로 보인다.
<em><a href="https://ko.wikipedia.org/wiki/%EC%8B%9C%ED%81%90%EC%96%B4_%EC%85%B8">위키 : SSH</a> 참조</em></p>
</blockquote>
<h1 id="진행-순서">진행 순서</h1>
<ol>
<li>ssh-key 파일 생성</li>
<li>ssh-key 등록</li>
<li>ssh config 파일 작성</li>
<li>github 사이트 계정 설정</li>
<li>ssh 연결테스트</li>
<li>프로젝트의 git remote 설정</li>
</ol>
<hr>
<h2 id="1-ssh-key-생성">1) ssh-key 생성</h2>
<p><code>cd ~/.ssh</code></p>
<ul>
<li>터미널을 열고 루트에서 <strong>ssh 숨김폴더</strong>로 이동, 없으면 생성(<code>mkdir ~/.ssh</code>)</li>
</ul>
<p><code>ssh-keygen -t &lt;암호화방식&gt; -b &lt;key크기 기본3072&gt; -C &#39;깃헙등록메일@메일.com&#39;</code>
<code>ssh-keygen -t rsa -b 4096 -C &#39;my-mail@email.com&#39;</code> : 실제 작성</p>
<ul>
<li>위 와 같은 구조의 명령으로 key파일 생성</li>
<li>2개 계정을 사용할 것이기에 2번 진행</li>
<li><code>-t</code> 암호화 방식 지정 : <code>rsa</code> 지정</li>
<li><code>-b</code> key의 byte-size 설정 : 지정 안하면 <code>3072</code> 기본값으로 설정 (최대 4096)</li>
<li><code>-C</code> github에 등록한 email 작성 : <code>my-mail@email.com</code></li>
<li>명령 입력뒤 파일명/비밀번호 설정에 대한 input 등장하니 아래내용 참고하여 설정</li>
</ul>
<p><code>Enter file in which to save the key (/Users/hwang/.ssh/id_rsa): &lt;id_rsa_이름지정&gt;</code></p>
<ul>
<li>터미널에 <code>Enter 머시기</code> 내용이 등장하면 파일명 지정 : <code>id_rsa_work</code>와 <code>id_rsa_study</code>으로 설정(각자 자유롭게~)</li>
<li><code>Enter</code>를 누르고 넘긴다면 기본값 <code>id_rsa</code>로 설정됨</li>
</ul>
<p><code>Enter passphrase (empty for no passphrase): &lt;엔터누르고 다음&gt;</code></p>
<ul>
<li>암호(비밀번호) 설정할꺼야? 입력안하면 암호 설정 안할께!</li>
</ul>
<p><code>Enter same passphrase again: &lt;엔터누르고 다음&gt;</code></p>
<ul>
<li>위 암호와 동일하게 입력하여 진행</li>
</ul>
<blockquote>
<pre><code class="language-bash">~    $ cd ~/.ssh
.ssh $ ssh-keygen -t rsa -C &#39;my-mail@mail.com&#39;
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/hwang/.ssh/id_rsa): &lt;id_rsa_이름지정&gt;
Enter passphrase (empty for no passphrase): &lt;엔터누르고 다음&gt;
Enter same passphrase again: &lt;엔터누르고 다음&gt;
... &lt;뭔가 진행 함&gt;
+---[RSA 3072]----+
|             ..oB|
|             . .o|
... &lt;이런박스 나옴됨&gt;
|          .  .+%#|
|           . e&amp;E/|
|            .=+%%|
+----[SHA256]-----+</code></pre>
</blockquote>
<p>2개의 key를 생성하고 파일 목록을 확인해보자. 아래와 같이 총 <strong>4개 파일이 생성</strong>되었다면 완료</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/faae1711-0dca-49c9-bd05-81e248abd75b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.10.15.png" alt=""></p>
<ul>
<li><code>id_rsa_study</code> : 기존계정-비공개-ssh</li>
<li><code>id_rsa_study.pub</code> : 기존계정-공개-ssh</li>
<li><code>id_rsa_work</code> : New계정-비공개-ssh</li>
<li><code>id_rsa_work.pub</code> : New계정-공계-ssh</li>
</ul>
<p><code>.pub</code> 확장자가 붙은 파일만 공개하며, 이 파일 내용을 github계정 SSH설정에 등록하게 된다.  github 계정 설정은 마지막에 살펴보자.</p>
<hr>
<h2 id="2-ssh-key-등록">2) ssh-key 등록</h2>
<p>생성한 key를 등록해보자!</p>
<p><code>eval &quot;$(ssh-agent -s)&quot;</code></p>
<ul>
<li>생성한 키를 ssh-agent에 등록(.. ssh-agent를 실행시키고.. 이후에 ssh-add로 등록을........ 정확히 모.름. 😇 )</li>
<li><a href="https://devlog.jwgo.kr/2019/04/17/ssh-keygen-and-ssh-agent/">Tonic&#39;s lesson learned 포스팅</a> 중 <strong>ssh-agent에 대한 설명</strong>을 읽어보니, <ul>
<li>ssh-agent 에 등록하지 않고 ssh등록과 사용을 할 수 있지만, github에 연결 할때 비번입력하지 않고 쓰기위해서 설정한다함. 즉, <strong>로그인 매번 하기 싫으면 ssh-agent 등록을 하세요</strong>!</li>
</ul>
</li>
</ul>
<p><code>ssh-add &lt;key파일경로&gt;</code></p>
<ul>
<li>명령을 통해 key 등록을 한다.</li>
</ul>
<p><code>ssh-add -l</code> : 등록된 key 목록을 확인</p>
<blockquote>
<pre><code class="language-bash">$ ssh-add ~/.ssh/id_rsa_study
Identity added: id_rsa_study (등록한메일1@gmail.com)

$ ssh-add ~/.ssh/id_rsa_work
Identity added: id_rsa_work (등록한메일2@gmail.com)</code></pre>
</blockquote>
<h2 id="3-sshconfig-생성">3) .ssh/config 생성</h2>
<p>SSH 설정파일을 작성해야 한다. 숨김폴더에 들어가 생성해도 or 터미널에서 작성 or 에디터를 사용해 작성하도록 한다.
나는 터미널 + vim을 사용하도록 하겠다.</p>
<p><code>touch ~/.ssh/config</code></p>
<ul>
<li><code>.ssh</code>폴더에 <code>config</code>파일 생성</li>
</ul>
<p><code>vi ~/.ssh/config</code></p>
<ul>
<li>vim 에디터로 config 파일을 열고 아래와 같이 작성한다.<pre><code>#  깃헙계정 work
#  -------------------
Host github.com-work
HostName github.com
IdentityFile ~/.ssh/id_rsa_work
User eungeegee 
</code></pre></li>
</ul>
<h1 id="깃헙계정-study">깃헙계정 study</h1>
<h1 id="-------------------">-------------------</h1>
<p>Host github.com-study
  HostName github.com
  IdentityFile ~/.ssh/id_rsa_study
  User zu-hwang</p>
<pre><code>- `Host : github.com-&lt;이름지정&gt;` : 하이픈(`-`)다음에는 원하는 이름을 지정, 앞으로 계속 써야하기 때문에 짧은 문자 추천
- `HostName` : github.com
- `IdentityFile : ~/.ssh/ssh파일경로작성` : 각각의 ssh-key파일 경로를 작성
- `User` : 나의 깃헙 계정지정~

## 4) github SSH 설정
위 과정까지 모두 마쳤다면, github에 로그인 하여 설정페이지를 찾자.

- github.com &gt; 로그인 &gt; 오른쪽 상단 프로필사진 클릭 &gt; settings &gt; SSH and GPG keys &gt; New SSH key 
   - title : 아무거나 내가 보기 좋은 것으로 지정
   - key : 각 계정에 맞는 ssh-key `_.pub` 파일의 내용을 기입한다. **꼭 확장지 `.pub` 가 붙은 파일의 내용!**
      - 편하게 하기 : 터미널에서 `pbcopy &gt; 파일경로`를 통해 파일 내용을 클립보드에 복사해 붙여넣기
- 2개의 계정 모두 ssh-key를 등록

## 5) SSH 연결테스트
SSH 설정에서 등록한 Host 값을 사용하여 연결테스트를 하자.

`ssh -T git@github.com-지정값`

`ssh -T git@github.com-work`

 - `github.com-work` Host 값 작성
    - 출력 : `Hi eungeegee! You&#39;ve successfully ....` 
 - `github.com-study` Host 값 작성
    - 출력 : `Hi zu-hwang! You&#39;ve successfully ....` 

## 6) 프로젝트 git remote 설정

### 신규 프로젝트 설정
이전까지 git 레포에 연결할때 `https://github....` https 주소로 remote 했다면,
이제 그 옆에있는 `use SSH` 누르고 `git@github.com:userid/reponame.git` 방식을 사용
![](https://images.velog.io/images/hwang-eunji/post/cba3ecb9-005a-4062-a3e5-c6de1025dd43/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-27%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%202.28.30.png)![](https://images.velog.io/images/hwang-eunji/post/72aa3078-781c-4eed-89cb-288c042fb271/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-27%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%202.30.27.png)

`git remote add origin git@github.com-지정이름:깃헙계정/레포지토리명.git`
- **여기서 중요**! 그냥 SSH-key 복사하기후 사용한다면 오류가 남, 우리는 계정이 2개이기 때문에 어떤 계정을 쓸지 지정해주는것이 **뽀-인트**! `github.com-지정이름`에 주의하자, 나는 지정이름을 `work`로 등록했기에 아래와 같이 입력하였다.

`git remote add origin git@github.com-work:eungeegee/my-repo.git`


### 기존 프로젝트 설정

위와 동일한 내용으로, 기족 프로젝트는 이미 설정되어 있는 주소를 변경하는 명령을 하면 된다.
`git remote set-url origin git@github.com-지정이름:깃헙계정/레포지토리명.git`으로 설정하도록 한다!



## 마치며

이게 뭐라고..
굳이 계정 만들어야 했냐며, 하루 반나절 내내 찾아보고, 까먹는다고 내용 정리하고..
...

하지만! 
두개 설정되니 너무 만족,
얼마나 잘 쓸지는 모르겠지만 모쪼록.. 저와 같은 분들 화이팅!








</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[홈브류(homebrew : Mac 패키지 관리) 명령어정리]]></title>
            <link>https://velog.io/@hwang-eunji/homebrew1</link>
            <guid>https://velog.io/@hwang-eunji/homebrew1</guid>
            <pubDate>Sat, 25 Jul 2020 08:58:20 GMT</pubDate>
            <description><![CDATA[<h1 id="홈브류-명령어정리">홈브류 명령어정리</h1>
<h2 id="기본-설치">기본 설치</h2>
<blockquote>
<p><a href="https://brew.sh/">homebrew 공식 문서</a> 방문하여 명령어 확인 &amp; 설치
<code>/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)&quot;</code></p>
</blockquote>
<h3 id="패키지-검색">패키지 검색</h3>
<blockquote>
<p><code>brew search [패키지명]</code></p>
</blockquote>
<ul>
<li>nodejs 패키지 검색 : <code>brew search node</code>
<img src="https://images.velog.io/images/hwang-eunji/post/ed1f4f90-7555-4350-95e3-be2b4afe2b3e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.42.38.png" alt=""></li>
</ul>
<h3 id="패키지-설치">패키지 설치</h3>
<blockquote>
<p><code>brew install [패키지명]</code></p>
</blockquote>
<ul>
<li>nodejs 패키지 설치 : <code>brew install node</code></li>
</ul>
<h2 id="패키지-관리--업그레이드">패키지 관리 &amp; 업그레이드</h2>
<h3 id="패키지-관리">패키지 관리</h3>
<blockquote>
</blockquote>
<ul>
<li><code>brew outdated</code> : 버전업 된 패키지 확인</li>
<li><code>brew list</code> : 설치된 패키지 목록보기</li>
<li><code>brew info [패키지명]</code> : 지정 패키지의 정보를 본다</li>
<li><code>brew uninstall [패키지명]</code> : 지정 패키지 삭제</li>
</ul>
<h3 id="홈브류-업데이트">홈브류 업데이트</h3>
<blockquote>
<p><code>brew update</code> : 홈브루 자체 버전 업데이트. 앞으로 설치되는 버전에 영향을 줌. <strong>이미 설치된 패키지는 기존 버전을 유지함</strong></p>
</blockquote>
<h3 id="패키지-업그레이드">패키지 업그레이드</h3>
<blockquote>
<p><code>brew upgrade</code> : 설치된 <strong>모든 패키지</strong> 업그레이드
<code>brew upgrade [패키지명]</code> : <strong>지정 패키지 만</strong> 업그레이드</p>
</blockquote>
<h3 id="패키지-최신버전-만-유지">패키지 최신버전 만 유지</h3>
<blockquote>
<p><code>brew cleanup</code> : 최신버전 이외의 패키지 모두 삭제</p>
</blockquote>
<p><strong>패키지 업데이트는 최신버전을 추가 설치함</strong>/기존 버전 따로 존재&amp;유지</p>
<h1 id="그밖에">그밖에</h1>
<blockquote>
<ul>
<li><code>brew doctor</code> : 홈브루 오류 확인&amp; 수정?</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel #5 플러그인 제작]]></title>
            <link>https://velog.io/@hwang-eunji/Babel-5-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8-%EC%A0%9C%EC%9E%91</link>
            <guid>https://velog.io/@hwang-eunji/Babel-5-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8-%EC%A0%9C%EC%9E%91</guid>
            <pubDate>Wed, 15 Jul 2020 14:12:06 GMT</pubDate>
            <description><![CDATA[<h1 id="ast-explorer">AST Explorer</h1>
<p>플로그인을 제작하기 위해선 AST 구조를 알아야 한다.</p>
<blockquote>
<p><a href="https://astexplorer.net/">AST Explorer</a> 에서 AST가 뭔지 알아보자.</p>
</blockquote>
<p>에디터에 <code>const myNamy= hwang + &#39;eunji&#39;;</code>를 입력했을때 AST Explorer에 출력된 json의 모습이다.</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/19368401-e987-441b-b346-20661cf8e8bc/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-15%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.19.36.png" alt=""></p>
<ul>
<li>type : 각 노드의 타입을 나타낸다 <ul>
<li>Program : 루트의 타입</li>
<li>VariableDeclaration : 변수 타입</li>
<li>FunctionDeclaration : 함수 타입</li>
<li>Identifier : 개발자가 만든 값(변수, 함수 등)</li>
<li>BinaryExpression : 사칙연산</li>
<li>Literal : 문자열</li>
<li>등...</li>
</ul>
</li>
<li>declarations : 선언부, 변수명, 초기값 등이 위치</li>
</ul>
<blockquote>
<h1 id="👻">👻</h1>
<p><em>보기는 했으나 이걸 어떻게 활용하는지..하핳</em></p>
</blockquote>
<h1 id="babel-plugin의-기본구조">babel plugin의 기본구조</h1>
<pre><code class="language-js">module.exports = function ({ types: t }) {
  const node = t.BinaryExpression(&#39;+&#39;, t.Identifier(&#39;a&#39;), t.Indentifier(&#39;b&#39;));
  console.log(&#39;isBinaryEspression:&#39;, t.inBinaryExpression(node));
  return {};
};</code></pre>
<ul>
<li><code>a+b</code>를 하는 코드 작성</li>
<li>types를 매겨변수로 하는 함수를 내보냄</li>
<li>types 매개변수를 이용해 AST 노드를 생성할 수 있다.</li>
<li><code>inBinaryExpression()</code>을 통해 타입검사를 진행했다.</li>
<li>return 값이 없기때문에 아무일도 일어나지 않는다.</li>
</ul>
<h2 id="반환-값-넣기">반환 값 넣기</h2>
<pre><code class="language-js">module.exports = function ({ types: t }) {
  return {
    visitor: {
      Identifier(path) {
        console.log(&#39;Identifier name:&#39;, path.node.name);
      },
      BinaryExpression(path) {
        console.log(&#39;BinaryExpression operator: &#39;, path.node.operator);
      },
    },
  };
};
</code></pre>
<ul>
<li>visitor 객체 내부에서 노트의 타입명으로 함수를 작성한다.(예 :<code>Identifier()</code>)</li>
<li>변수가 작성되면 <code>Identifier()</code><em>-개발자가 만든 값(변수, 함수 등)-</em> 함수가 호출되며, 변수가 쓰인 만큼 호출</li>
<li><code>path.node.name</code> 변수명을 나타내며, <code>const myName= hwang + &#39;eunji</code>에서 <strong>myName</strong>, <strong>hwang</strong>에 해당</li>
<li>연산자를 작성하면 <code>BinaryExpression()</code>함수가 실행</li>
<li><code>path.node.operator</code>는 <code>const myName= hwang + &#39;eunji</code>에서<code>+</code>연산자에 해당</li>
<li><strong><code>const myName= hwang + &#39;eunji&#39;</code></strong> 가 입력됬을 때<ul>
<li><code>Identifier()</code> 는 2번 호출</li>
<li><code>BinaryExpression()</code> 1번 호출</li>
</ul>
</li>
</ul>
<h2 id="콘솔로그-제거-plugin">콘솔로그 제거 plugin</h2>
<p>콘솔로그를 제거하는 플러그인을 제작 하기 위해서는 먼저 콘솔로그의 AST를 이해해야 한다.</p>
<p><a href="https://astexplorer.net/">AST Explorer</a> 사이트에 방문하여 <code>console.log()</code>의 AST를 확인하자</p>
<pre><code class="language-js">// console.log(&#39;hi&#39;) 의 JSON 데이터
// 필요없는 옵션 제거함 : start, end)
{
  &quot;type&quot;: &quot;Program&quot;,
  &quot;body&quot;: [
    {
      &quot;type&quot;: &quot;ExpressionStatement&quot;,
      &quot;expression&quot;: {
        &quot;type&quot;: &quot;CallExpression&quot;,
        &quot;callee&quot;: {
          &quot;type&quot;: &quot;MemberExpression&quot;,
          &quot;object&quot;: {
            &quot;type&quot;: &quot;Identifier&quot;,
            &quot;name&quot;: &quot;console&quot;
          },
          &quot;property&quot;: {
            &quot;type&quot;: &quot;Identifier&quot;,
            &quot;name&quot;: &quot;log&quot;
          },
          &quot;computed&quot;: false
        },
        &quot;arguments&quot;: [
          {
            &quot;type&quot;: &quot;Literal&quot;,
            &quot;value&quot;: &quot;hi&quot;,
            &quot;raw&quot;: &quot;&#39;hi&#39;&quot;
          }]}}
  ],
  &quot;sourceType&quot;: &quot;module&quot;
}</code></pre>
<h3 id="콘솔로그의-ast">콘솔로그의 AST</h3>
<pre><code class="language-js">- [root]:[type]: Program // 최상위
  - [body]
    - [첫 요소 : `console.log(&#39;hi)&#39;`]
      - [type] : ExpressionStatement // 1
      - [expression] : CallExpression // 2
        - [callee]
          - [type] : MemberExpression // 3
          - [object] // 객체 타입과 이름
            - [type] : Identifier  // 4
            - [name] : console
          - [property] // 메서드 or 속성이 위치
            - [type] : Identifier
            - [name] : log
         - [args]
           - [1st args : `(&#39;hi&#39;)`] // 첫번째 인자에 대한 객체
             - [type] : Literal // 5
             - [value] : &#39;hi&#39;// 입력값이 표시됨
             - [raw] : &#39;hi&#39;
</code></pre>
<h4 id="콘솔로그의-types">콘솔로그의 Types</h4>
<ol>
<li><code>ExpressionStatement</code> : 콘솔로그의 최상위 노드</li>
<li><code>CallExpression</code> : 함수 또는 메서드를 호출하는 코드의 type</li>
<li><code>MemberExpression</code> : 메서드 호출 시 type</li>
<li><code>Identifier</code> : 변수명과 같이 선언되기에 Identifier type</li>
<li><code>Literal</code> : 문자열이 주어졌음으로 literal type</li>
</ol>
<h3 id="콘솔로그-제거-플로그인-코드작성">콘솔로그 제거 플로그인 코드작성</h3>
<pre><code class="language-js">module.exports = function ({ types: t }) {
  return {
    visitor: {
      ExpressionStatement(path) {
        // ExpressionStatement type을 갖을때 호출
        if (t.isCallExpression(path.node.expression)) {
          if (t.isMemberExpression(path.node.expression.callee)) {
            // 노드체이닝이 넘 길어서 변수에 넣고 다시 체이닝
            const calleeNode = path.node.expression.callee;
            if (
              calleeNode.object.name === &#39;console&#39; &amp;&amp;
              calleeNode.property.name === &#39;log&#39;
            ) {
              path.remove(); // 조건에 맞으면 코드 최상위 제거! === console.log() 제거하게됨
}}}},},};};
</code></pre>
<ul>
<li><code>ExpressionStatement(path)</code> 콘솔로그 최상위 Types를 함수화 하여 작성, 매개변수를 지정해 노드에 접근하도록 한다.</li>
<li><code>isCallExpression(node)</code> : <code>is타입명(노드)</code>을 통해 인자로 지정한 node가 해당 type을 인지 확인!</li>
<li><code>isMemberEspression(node)</code> : 맞찬가지로 인자로 넣은 노드가 해당 type인지 확인</li>
<li>최하위 노드까지 접근했을때 <code>console</code> 객체에 <code>log</code> 메서드가 쓰였다면 <strong>해당 요소의 최상위 노드 제거</strong></li>
</ul>
<blockquote>
<h1 id="👻-1">👻</h1>
<p>여기까지 실습하면서 AST 구조 들여다 보다보니 조금, 아주 쪼오오오오오오금 이해가 된다.</p>
</blockquote>
<h3 id="직접-만든-플러그인-사용하기">직접 만든 플러그인 사용하기</h3>
<p>직접 만들 플러그인을 사용하기 위해서는 바벨 설정이 필요하다. 전역 설정파일(<strong><code>babel.confil.js</code></strong>)을 만들고 다음 코드를 작성하자.</p>
<pre><code class="language-js">// babel.config.js

// plugins 변수에 [플러그인1, 플러그인2, ... 그리고 내가만든 플러그인]
// 여러게 플러그인을 배열로 담기
const plugins = [&#39;./plugins/consolelog-remover.js&#39;]
module.exports = { plugins }</code></pre>
<p>콘솔로그가 있는 코드를 작성하고 바벨을 사용해 컴파일하여 보자~~아!</p>
<pre><code class="language-js">// sample-consolelog-remove.js

console.log(&#39;콘솔로그를 지워볼깨&#39;);
const text = &#39;run console.log() remove-plugin&#39;;
console.log(text);</code></pre>
<p><code>npx babel 경로/파일명.js</code> 명령 실행 후 콘솔출력</p>
<pre><code class="language-js">const text = &#39;run console.log() remove-plugin&#39;;</code></pre>
<p>책보고 따라한 실습이지만, 감격....멋지당!!!
분명 잘 작성했는데 에러가나거나 한다면. 노드 체이닝에 문제가 없는지 다시한번 확인하자. 나는 <code>if (t.isMemberExpression(path.node.expression.callee)){}</code> 에서 인자로 넣은 노드에서 <code>expression</code>을 빼먹어서 한참을 다시 봤다! 노드를 잘 보기!</p>
<h2 id="콘솔로그-추가-plugin">콘솔로그 추가 plugin</h2>
<p>콘솔로그 제거를 해봤으니 콘솔로그 추가하는 플러그인을 작성해보자.</p>
<blockquote>
<p>규칙 : &#39;<strong>on</strong>&#39;으로 시작하는 함수에 콘솔로그를 추가</p>
</blockquote>
<p>먼저 <a href="https://astexplorer.net/">AST Explorer</a> 사이트에 방문하여 <code>onFunctionName()</code> 로직을 작성해 노드를 확인해보자.</p>
<p><img src="https://images.velog.io/images/hwang-eunji/post/3ffef14a-daff-4852-b682-1d055b5d23d4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-16%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.46.01.png" alt=""></p>
<pre><code class="language-js">// AST 구조 확인하기 : JSON
// 너무 길어서 필요없는 옵션은 제거
{
  &quot;type&quot;: &quot;Program&quot;,
  &quot;body&quot;: [
    {
      &quot;type&quot;: &quot;FunctionDeclaration&quot;,
      &quot;id&quot;: {
        &quot;type&quot;: &quot;Identifier&quot;,
        &quot;name&quot;: &quot;onFunc&quot;
      },
      &quot;body&quot;: {
        &quot;type&quot;: &quot;BlockStatement&quot;,
        &quot;body&quot;: [
          {
            &quot;type&quot;: &quot;VariableDeclaration&quot;, // const 변수 노드
            &quot;kind&quot;: &quot;const&quot;
          },
          {
            &quot;type&quot;: &quot;ExpressionStatement&quot;,  // console.log 노드
            &quot;expression&quot;: {
              &quot;type&quot;: &quot;CallExpression&quot;,
              &quot;callee&quot;: {
                &quot;type&quot;: &quot;MemberExpression&quot;,
                &quot;object&quot;: {
                  &quot;type&quot;: &quot;Identifier&quot;,
                  &quot;name&quot;: &quot;console&quot;
                },
                &quot;property&quot;: {
                  &quot;type&quot;: &quot;Identifier&quot;,
                  &quot;name&quot;: &quot;log&quot;
           // .. 이하 닫기
          {
            &quot;type&quot;: &quot;ReturnStatement&quot;, // return 노드
          } 
            // .. 이하 닫기</code></pre>
<h3 id="콘솔로그-플러그인-추가-작성">콘솔로그 플러그인 추가 작성</h3>
<pre><code class="language-js">module.exports = function ({ types: t }) {
  return {
    visitor: {
      FunctionDeclaration(path) {
        if (path.node.id.name.substr(0, 2) === &#39;on&#39;) {
          path
            .get(&#39;body&#39;)
            .unshiftContainer(
              &#39;body&#39;,
              t.expressionStatement(
                t.callExpression(
                  t.memberExpression(
                    t.identifier(&#39;console&#39;),
                    t.identifier(&#39;log&#39;)
                  ),
                  [t.stringLiteral(`call ${path.node.id.name}`)]
                )));}},},};};</code></pre>
<h3 id="실행결과">실행결과</h3>
<h4 id="바벨적용-전">바벨적용 전</h4>
<pre><code class="language-js">function onFunc1() {
  return &#39;일반함수 타입: FunctionDeclaration&#39;;
}

const onFunc3 = function () {
  return &#39;익명함수 변수지정: VariableDeclaration&#39;;
};

const onFunc4 = () =&gt; {
  return &#39;화살표함수 타입: VariableDeclaration&#39;;
};</code></pre>
<h4 id="바벨-적용-후">바벨 적용 후</h4>
<pre><code class="language-js">function onFunc1() {
  console.log(&quot;call onFunc1&quot;);
  return &#39;일반함수 타입: FunctionDeclaration&#39;;
}

const onFunc3 = function () {
  return &#39;익명함수 변수지정: VariableDeclaration&#39;;
};

const onFunc4 = function () {
  return &#39;화살표함수 타입: VariableDeclaration&#39;;
};
</code></pre>
<p>AST Explorer에서 확인해보면 알겠지만, 함수 선언 방식마다 타입종류가 다르다 변수형으로 <code>function 함수명</code> 방식 이외의 함수 선언방식은 변수선언 타입 <strong><code>VariableDeclaration</code></strong> 로 적용된다.</p>
<ul>
<li>일반 함수 선언방식 : <code>function 함수명(){}</code> FunctionDevlaration type</li>
<li>화살표함수, 익명함수 : <code>()=&gt;{}</code>, <code>function(){}</code> VariableDeclaration type</li>
</ul>
<hr>
<blockquote>
<h4 id="참고자료">참고자료</h4>
<p><a href="http://book.interpark.com/product/BookDisplay.do?_method=detail&amp;sc.prdNo=333702230&amp;gclid=EAIaIQobChMI5cqh2M3K6gIVSHRgCh2gQAwJEAQYASABEgLkZvD_BwE">실전 리액트 프로그래밍/이재승 저</a>
<a href="https://gyujincho.github.io/2018-06-19/AST-for-JS-devlopers">자바스크립트 개발자를 위한 AST(번역)</a>
<a href="https://github.com/jamiebuilds/babel-handbook">바벨-핸드북 깃헙</a> : 한국어버전 있음
<a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md">바벨-핸드북 깃헙 : 플러그인 만들기</a> : 한국어버전 있음</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel #5 폴리필 (polyfill)]]></title>
            <link>https://velog.io/@hwang-eunji/Babel-5-%ED%8F%B4%EB%A6%AC%ED%95%84-polyfill</link>
            <guid>https://velog.io/@hwang-eunji/Babel-5-%ED%8F%B4%EB%A6%AC%ED%95%84-polyfill</guid>
            <pubDate>Wed, 15 Jul 2020 12:13:03 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://babeljs.io/docs/en/babel-polyfill">babel 공식문서 @babe/polyfill</a>
<a href="https://babeljs.io/docs/en/babel-preset-env">babel 공식문서 @babe/preset-env</a>
<a href="https://github.com/zloirock/core-js#readme">core-js github 문서</a>
<a href="http://book.interpark.com/product/BookDisplay.do?_method=detail&amp;sc.prdNo=333702230&amp;gclid=EAIaIQobChMI5cqh2M3K6gIVSHRgCh2gQAwJEAQYASABEgLkZvD_BwE">실전 리액트 프로그래밍/이재승 저</a>
 <a href="https://github.com/browserslist/browserslist">browserslist 패키지 문법</a></p>
</blockquote>
<h1 id="폴리필polyfill">폴리필(polyfill)</h1>
<p>자바스크립트의 최신기술을 구버전 브라우저에서 사용하기 위해서는 변화과 함께 폴리필도 사용해야 한다. 폴리필은 <strong>런타임 기능 주입</strong>을 말한다. 런타임 기능 주입이 뭐야? 한다면, <strong>브라우저에서 코드가 실행될 때 기능이 있는지 없는지 확인한 뒤 없을 경우에만 코드 변환을 하는 기능을 말한다</strong>.</p>
<blockquote>
<p><strong>Q.</strong> 바벨을 쓰면 최신 문법 전부 적용 되는거 아니였나요? 
A. 네, 아니에요. <strong>바벨 써도 폴리필 설정 해줘야 해요</strong></p>
</blockquote>
<pre><code class="language-js">// 폴리필 코드 예
// ES8의 String.padStart()가 있는지 확인하고 없으면 폴리필 함수를 대입하게 된다.
if(!String.prototype.padStart) {
  String.prototype.padStart = 폴리필 함수 대입;
}</code></pre>
<h2 id="babelpolyfill"><code>@babel/polyfill</code></h2>
<p><code>@babel/polyfill</code> 는 바벨 공식 폴리필 지원 패키지다. 모든 폴리필을 포함시키기고 있기 때문에 별다른 설정없이 패키지를 import 하여 사용한다. 단순한 사용법이 가장 큰 장점이라면, 파일이 크기가 크다는 것이 단점이다.</p>
<p><strong>파일 크기에 너그러운 프로젝트에 추천</strong>, 가장 쉽게 폴리필을 적용할 수 있는 방법!</p>
<pre><code class="language-js">import &#39;@babel/polyfill&#39;
// 이하 코드 작성하기</code></pre>
<h2 id="babelpolyfill--with-webpack"><code>@babel/polyfill</code>  with Webpack</h2>
<pre><code class="language-js">// @babel/polyfill을 사용하기 위한 설정

module.exports = {
  entry: [&#39;@babel/polyfill&#39;, &#39;./src/index.js&#39;],
  // 이하 설정 생략
};</code></pre>
<ul>
<li>entry에 폴리필 패키지를 추가시켰다.</li>
</ul>
<h2 id="core-js의-polyfill"><code>core-js</code>의 polyfill</h2>
<blockquote>
<p><a href="https://medium.com/@simsimjae/%EA%B0%9C%EB%B0%9C%EC%9D%84-%ED%95%98%EB%8B%A4%EB%B3%B4%EB%8B%88-%EC%9D%B4%EB%9F%B0-%EC%97%90%EB%9F%AC%EA%B0%80-%EC%83%9D%EA%B2%A8%EC%84%9C-%EC%9B%90%EC%9D%B8%EC%9D%84-%EC%B0%BE%EB%8B%A4%EA%B0%80-%ED%8F%B4%EB%A6%AC%ED%95%84-%EB%AC%B8%EC%A0%9C%EB%9D%BC%EB%8A%94%EA%B1%B8-%EA%B9%A8%EB%8B%AB%EA%B3%A0-%EC%A0%95%EB%A6%AC%ED%95%A9%EB%8B%88%EB%8B%A4-217a207f8181">core-js란? - 심재철님 블로그</a></p>
</blockquote>
<p><code>@babel/polyfill</code> 도 내부적으로는 <code>core-js</code>패키지를 사용한다. 즉, <code>@babel/polyfill</code>를 사용하지 않고 <code>core-js</code> 패키지로 부터 필요한 폴리필만 가져와 사용하면 파일 크기를 줄일 수 있다. <strong>파일 크기에 민감한 프로젝트에 추천</strong></p>
<h2 id="babelpreset-env"><code>@babel/preset-env</code></h2>
<p>실행 환경에 대한 정보를 설정해주면 자동으로 필요한 기능을 주입해준다.
<strong>적당한 번들 파일 크기 유지하면서 폴리필 빼먹는 실수를 막기위해 <code>@babel/preset-env</code> 사용이 가정 합리적인 선택이 될 수 있다</strong></p>
<h3 id="babelconfigjs에-실행환경-정보작성">babel.config.js에 실행환경 정보작성</h3>
<pre><code class="language-js">// babel.config.js 

const presets = [[&#39;@babel/preset-env&#39;, { targets: &#39;&gt;0.25%, not dead&#39; }]];
// ... 설정 등등등

module.exports = { presets };</code></pre>
<ul>
<li>targets 속성으로 지원하는 브라우저 정보를 입력한다. (시장점유율 0.25퍼센트 이상, 업데이트가 죽지 않은 브라우저)</li>
<li>targets에 사용된 속성은 <a href="https://github.com/browserslist/browserslist">browserslist 패키지 문법</a>을 확인하고 사용하자.</li>
</ul>
<pre><code class="language-js">// @babel/preset-env 프리셋으로 폴리필 설정하는 방식

const presets = [[&#39;@babel/preset-env&#39;, { targets: &#39;&gt;0.25%, not dead&#39; }]];
const presets = [
  [
    &#39;@babel/preset-env&#39;,
    {
      targets: {
        chrome: &#39;40&#39;,
        ie :&#39;버전&#39;,
        // ... 브라우저 정보
      },
      useBuiltIns: &#39;entry&#39;, // 폴리필 관련 설정 : 지원하는 브라우저에 필요한 폴리필만 포함
    },
  ],
];

module.exports = { presets };</code></pre>
<ul>
<li>targets : 크롬 40버전 이상을 설정</li>
<li>useBuiltIns : 폴리필 관련 설정<ul>
<li><strong>entry</strong> 옵션 : 지원 브라우저에 필요한 폴리필만 골라가져온다(core-js폴리필 중 브라우저에 없는 기능 모두)</li>
<li><strong>usage</strong> 옵션 : entry옵션시 폴리필에서 내가 작성한코드에 필요한 폴리필 만 골라서 (<strong>폴리필이 최적화 된다</strong>)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel #4 babel의 다양한 속성(extends, env, overrides)]]></title>
            <link>https://velog.io/@hwang-eunji/Babel-4-babel%EC%9D%98-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%86%8D%EC%84%B1</link>
            <guid>https://velog.io/@hwang-eunji/Babel-4-babel%EC%9D%98-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%86%8D%EC%84%B1</guid>
            <pubDate>Wed, 15 Jul 2020 11:17:38 GMT</pubDate>
            <description><![CDATA[<h1 id="babel-설정속성">babel 설정속성</h1>
<ul>
<li>extends : 다른 설정파일을 가저와 확장하여 사용가능(상속)</li>
<li>env : 환경설정</li>
<li>overrides : 파일별 다른설정 적용</li>
</ul>
<p>실습을 위해 아래 패키지 설치
<code>npm i @babel/core @babel/cli @babel/preset-react @babel/plugin-transform-arrow-functions @babel/plugin-transform-template-literals babel-preset-minify</code></p>
<ul>
<li><code>@babel/core</code> : 필수 바벨 설정</li>
<li><code>@babel/cli</code> : 바벨 실행</li>
<li><code>@babel/preset-react</code> : 리액트 프리셋</li>
<li><code>@babel/plugin-transform-arrow-functions</code> : 화살표 함수 플러그인</li>
<li><code>@babel/plugin-transform-template-literals</code> : 템플릿 문자열 플러그인</li>
<li><code>babel-preset-minify</code> : 프로덕션 모드일때 코드 압축 적용</li>
</ul>
<h2 id="extends-속성">extends 속성</h2>
<h3 id="공용-babelrc-작성">공용 <code>.babelrc</code> 작성</h3>
<p>프로젝트 루트에 <code>/common/.babelrc</code> 파일을 작성하여 모든 설정파일에서 상속받을 파일을 작성한다.</p>
<pre><code class="language-js">{
  &quot;presets&quot;: [&quot;@babel/preset-react&quot;],
  &quot;plugins&quot;: [[&quot;@babel/plugin-transform-template-literals&quot;, { &quot;loose&quot;: true }]]
}</code></pre>
<ul>
<li>공통으로 적용될 presets, plugins 작성</li>
<li>plugins에 옵션을 적용할경우 <code>[[플러그인1,{설정:값}],[플러그인2,{설정:값}]]</code> 와 같이 작성</li>
<li><code>loose</code> 옵션은 템플릿 문자열을 변환할때 <code>.concat()</code>을 사용하는 대신 <code>+</code> 연산자를 사용한다.</li>
</ul>
<h3 id="공용-babelrc-상속받기">공용 <code>.babelrc</code> 상속받기</h3>
<pre><code class="language-js">{
  &quot;extends&quot;: &quot;../../common/.babelrc&quot;, // 상속받을 바벨설정파일 지정
  &quot;plugins&quot;: [
    &quot;@babel/plugin-transform-arrow-functions&quot;,
    &quot;@babel/plugin-transform-template-literals&quot;
  ]
}</code></pre>
<ul>
<li>extends 속성으로 상속받을 파일을 지정</li>
<li>필요한 plugins 추가</li>
<li>중복의 경우 현재 파일로 덮어쓰기. 즉, <code>plugin-transform-template-literals</code>의 <code>loose</code> 옵션은 제거된다.</li>
</ul>
<h2 id="env-속성">env 속성</h2>
<p>env 속성은 환경별 다른 설정을 할수 있게 돕는다.</p>
<blockquote>
<h3 id="바벨의-현재환경-적용-우선순위">바벨의 현재환경 적용 우선순위</h3>
<p> babel의 현재환경은 <code>process.env.BABEL_ENV || process.env.NODE_ENV || &#39;development&#39;</code> 로 적용된다.</p>
<ul>
<li>즉, <code>&#39;development&#39;</code> &gt; <code>process.env.NODE_ENV</code> &gt; <code>process.env.BABEL_ENV</code> 순으로 적용</li>
</ul>
</blockquote>
<pre><code class="language-js">{
  &quot;presets&quot;: [&quot;@babel/preset-react&quot;],
  &quot;plugins&quot;: [
    &quot;@babel/plugin-transform-template-literals&quot;,
    &quot;@babel/plugin-transform-arrow-functions&quot;
  ],
  &quot;env&quot;: {
    &quot;production&quot;: { &quot;presets&quot;: [&quot;babel-preset-minify&quot;] }
  }
}</code></pre>
<p>이제 환경변수에 따른 설정적용이 잘 되는지 보자!</p>
<ul>
<li>개발모드 : <code>npx babel ./src/example-env/code.js</code> 
<img src="https://images.velog.io/images/hwang-eunji/post/2f7eccb4-e28b-4750-916a-335726bf0a1d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-15%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.03.19.png" alt=""></li>
<li>프로덕션 모드 : <code>NODE_ENV=production npx babel ./src/example-env/code.js</code>
<img src="https://images.velog.io/images/hwang-eunji/post/d42775e6-da93-4f95-b9e1-22b75c9e97cf/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-15%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.02.59.png" alt=""><blockquote>
<p><strong>파일생성을 하려면  <code>--out-file src/example-env/dist-모드명.js</code> 옵션을 추가 하도록</strong></p>
</blockquote>
</li>
</ul>
<h2 id="overrides-속성">overrides 속성</h2>
<pre><code class="language-js">{
  &quot;presets&quot;: [&quot;@babel/preset-react&quot;],
  &quot;plugins&quot;: [
    &quot;@babel/plugin-transform-template-literals&quot;,
  ],
  &quot;overrides&quot;: [
    {
      &quot;includ&quot;: &quot;./inc&quot;, 
      &quot;exclude&quot;: &quot;./inc/exc.js&quot;,
      &quot;plugins&quot;: [&quot;@babel/plugin-transform-arrow-functions&quot;]
    }
  ]
}</code></pre>
<p>overrides 속성의 모습을 보자. include/exclude 파일 지정한 것이 보인다. 옵션명으로 알수 있듯 <strong>포함/제외</strong> 항목이다. include 항목은 모두 포함시키며, exclude 항목은 제외시킨뒤 overrides 속성의 plugins, presets등 옵션등을 적용하게 된다. exclude된 항목은 상위 적용값에 영향을 받게 된다.</p>
<ul>
<li>include(포함) : 지정된 폴더, 파일을 overrides속성 적용 <strong>템플릿 문자열 + 화살표 함수 변환</strong></li>
<li>exclude(제외) : 지정된 폴더, 파일은 상위 속성에 영향을 받음 <strong>템플릿 문자열 만 변환</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel #3 @babel/core로 실행 & 설정]]></title>
            <link>https://velog.io/@hwang-eunji/Babel-3-babelcore%EB%A1%9C-%EC%8B%A4%ED%96%89-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@hwang-eunji/Babel-3-babelcore%EB%A1%9C-%EC%8B%A4%ED%96%89-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Wed, 15 Jul 2020 10:21:36 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://babeljs.io/docs/en/babel-core">babel 공식 문서 - @babel/core</a></p>
</blockquote>
<h1 id="babelcore로-실행--설정"><code>@babel/core</code>로 실행 &amp; 설정</h1>
<p>앞서 살펴본 <code>@babel/cli</code>, <code>babel-loader</code>는 <code>@babel/core</code>를 통해 실행된다. 다른 파일을 통하지 않고 직접 <code>@babel/core</code>를 통해 실행하는 방법을 알아보자.</p>
<h2 id="실행파일-작성">실행파일 작성</h2>
<p>프로젝트 루트에 바벨 실행파일을 작성해보자. 이전까지는 콘솔을 통해 babel명령어를 작성하여 실행했지만, 이제 runBabel.js을 작성하고 바벨을 실행하게 된다.</p>
<blockquote>
<p>코드예졔 : <a href="http://book.interpark.com/product/BookDisplay.do?_method=detail&amp;sc.prdNo=333702230&amp;gclid=EAIaIQobChMI5cqh2M3K6gIVSHRgCh2gQAwJEAQYASABEgLkZvD_BwE">실전 리액트 프로그래밍/이재승 저</a></p>
</blockquote>
<pre><code class="language-js">const babel = require(&#39;@babel/core&#39;);
const fs = require(&#39;fs&#39;);

const filename = &#39;./src/code.js&#39;;
const source = fs.readFileSync(filename, &#39;utf8&#39;);
const presets = [&#39;@babel/preset-react&#39;];
const plugins = [
  &#39;@babel/plugin-transform-arrow-functions&#39;,
  &#39;@babel/plugin-transform-template-literals&#39;,
];

const { code } = babel.transformSync(source, {
  filename,
  presets,
  plugins,
  configFile: false,
});

console.log(code);</code></pre>
<ul>
<li><code>@babel/core</code> 불러오기</li>
<li>file-system(fs) 불러오기 : <code>/src.core.js</code>를 불러오기 위해 사용</li>
<li>presets, plugins : 사용한 플로그인/프리셋 배열에 담아 작성</li>
<li><code>@babel/core</code>의 <code>transformSync()</code> 메서드를 통해 코드 변환</li>
<li>변환파일은 저장하지 않고 콘솔에 출력</li>
</ul>
<blockquote>
<p>위 코드예제를 보고 느끼는 점은 이전 <code>webpack/babel-loader</code>나 <code>@babel/cli</code> 설정과 딱히 다르지 않고 더 복잡한 느낌적 느낌이 드는데 왜 이 방식을 쓸까 라는 것. 하지만 코드가 복잡해지고 여러 설정에 따라 바벨적용을 달리해야 한다면 여러번 바벨 컴파일 하지 않고, <code>@babel/core</code>를 통해 직접 작성한 코드가 훨씬 간결하고, 1회 실행으로 결과물이 나온다고한다. (나는 아직 경험해 보지 못해.. 중요성은 모르겠다)</p>
</blockquote>
<h2 id="babelcore의-컴파일-단계"><code>@babel/core</code>의 컴파일 단계</h2>
<ul>
<li>파싱(parse) : 입력된 코드 부터 AST(abstract sytax tree)를 생성</li>
<li>변환(transform): AST를 원하는 형태로 변환</li>
<li>생성(generate): AST를 코드로 출력</li>
</ul>
<blockquote>
<p><a href="https://ko.wikipedia.org/wiki/%EC%B6%94%EC%83%81_%EA%B5%AC%EB%AC%B8_%ED%8A%B8%EB%A6%AC">추상 구문 트리 : AST(abstract syntax tree)</a> <em>위키참조</em>
추상 구문 트리는 컴파일러에 널리 사용되는 자료 구조인데, 이는 프로그램 코드의 구조를 표현하는 프로퍼티이기 때문이다. AST는 일반적으로 컴파일러의 구문 분석 단계의 결과물이다. 컴파일러가 요구하는 여러 단계를 통해 프로그램의 중간 표현의 역할을 하며 컴파일러의 최종 결과물에 대해 강력한 영향을 준다.</p>
</blockquote>
<ul>
<li><strong>AST = 코드가 분석된 결과를 담는 트리 구조체</strong></li>
</ul>
<h2 id="ast-활용-효율적-babel-실행법">AST 활용 효율적 babel 실행법</h2>
<pre><code class="language-js">// AST 활용하여 효율적인 바벨실행파일을 작성해보자

const babel = require(&#39;@babel/core&#39;);
const fs = require(&#39;fs&#39;);

const filename = &#39;./src/code.js&#39;;
const source = fs.readFileSync(filename, &#39;utf8&#39;);
const presets = [&#39;@babel/preset-react&#39;];

// 코드 생성하지 않고 AST만 생성 : 동일한 옵션 적용
const { ast } = babel.transformSync(source, {
  filename,
  presets,
  configFile,
  ast: true,
  code: false,
});

// ast 설정과 + code.js + 개별설정 에 따라 컴파일된 code1 반환 : 화살표 함수 적용
const { code: code1 } = babel.transformFromAstSync(ast, source, {
  filename,
  plugins: [&#39;@babel/plugin-transform-arrow-functions&#39;],
  configFile: false,
});

// ast 설정과 + code.js + 개별설정 에 따라 컴파일된 code2 반환 : 템플릿 문자열적용
const { code: code2 } = babel.transformFromAstSync(ast, source, {
  filename,
  plugins: [&#39;@babel/plugin-transform-template-literals&#39;],
  configFile: false,
});

console.log(code1);
console.log(code2);
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel #3 webpack babel-loder로 실행 & 설정]]></title>
            <link>https://velog.io/@hwang-eunji/Babel-3-webpack-babel-loder%EB%A1%9C-%EC%8B%A4%ED%96%89-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@hwang-eunji/Babel-3-webpack-babel-loder%EB%A1%9C-%EC%8B%A4%ED%96%89-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Wed, 15 Jul 2020 09:45:26 GMT</pubDate>
            <description><![CDATA[<h1 id="webpack-babel-loder로-실행--설정">webpack babel-loder로 실행 &amp; 설정</h1>
<blockquote>
<p><a href="https://webpack.js.org/concepts/">webpack 공식 문서</a></p>
</blockquote>
<h2 id="webpack-package-install">webpack package install</h2>
<p>webapck babel-loder를 사용하기 위해서 먼저 관련 패키지를 설치하자.</p>
<p><code>npm i webpack webpack-cli babel-loader</code></p>
<ul>
<li>webpack</li>
<li>webpack-cli</li>
<li>babel-loader </li>
</ul>
<h2 id="설정파일">설정파일</h2>
<p><code>babel.config.js</code>와 같이 webpack도 설정파일을 만들어보자. <code>webpack.config.js</code>로 프로젝트 루트에 저장!</p>
<pre><code class="language-js">// webpack.config.js 웹팩 설정파일을 작성하자. 리액트를 하면서 여기저기서 자주 봤던 모습

const path = require(&#39;path&#39;); // path 모듈 임포트

module.exports = {
  mode: &#39;development&#39;,
  entry: &#39;./src/code.js&#39;, // 웹팩 적용할 시작점 파일
  output: {
    // 웹팩 적용후 output 경로와 파일명
    path: path.resolve(__dirname, &#39;dist&#39;),
    filename: &#39;code.bundle.js&#39;,
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: &#39;babel-loader&#39;,
      },
    ],
  },
  // 웹팩의 압축기능을 잠시 꺼두기 위한 옵션
  optimization: { minimizer: [] },
};
</code></pre>
<blockquote>
<h3 id="스크립트-작성">스크립트 작성</h3>
</blockquote>
<pre><code class="language-js">  &quot;scripts&quot;: {
    &quot;webpack&quot;: &quot;npx webpack&quot;,
  }</code></pre>
<p><code>yarn webpack</code> 또는 <code>npm run webpack</code>을 통해 스크립트를 실행시켜보자. webpack이 프로젝트 루트에서 <code>webpack.config.js</code>있는지 먼저 확인 후, 있다면 설정파일을 읽어 실행하게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel #2 @babel/cli로 실행 & 설정]]></title>
            <link>https://velog.io/@hwang-eunji/Babel-2-babelcli%EB%A1%9C-%EC%8B%A4%ED%96%89-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@hwang-eunji/Babel-2-babelcli%EB%A1%9C-%EC%8B%A4%ED%96%89-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Wed, 15 Jul 2020 09:13:33 GMT</pubDate>
            <description><![CDATA[<h1 id="babelcli로-실행--설정"><code>@babel/cli</code>로 실행 &amp; 설정</h1>
<h2 id="설정파일">설정파일</h2>
<p><code>@babel/cli</code>에 대부분의 설정 담겨있지만, 실행환경에 따라 설정이 다른 경우에는 설정파일을 따로 만들어 관리하는 것이 좋다. 설정파일은 프로젝트 루트에 위치한다.</p>
<ul>
<li><code>.bebelrc</code> : <strong>지역 설정파일(local config)</strong>, 바벨6 이전 버전까지 추천 설정파일 형태</li>
<li><code>babel.config.js</code> : <strong>전체 설정파일(global config)</strong>, 바벨7 이후 추천 설정파일 형태</li>
<li><code>.babelrc</code>,<code>package.json</code> babel 설정 &gt; <code>bebel.config.js</code> : 지역 설정파일의 우선순위가 높다.</li>
</ul>
<h2 id="설정-값">설정 값</h2>
<h3 id="presets--plugins">presets &amp; plugins</h3>
<pre><code class="language-js">/*
 * npx babel src/code.js
 * --presets=@babel/preset-react
 * --plugins=@babel/plugin-transform-template-literals,@babel/plugin-transform-arrow-functions&quot;,
 * 
 * const 옵션명 = [설치파일명, 설치파일명...];
 *
 */


// --presets=프리셋1,프리셋2 동일
const presets = [&#39;@babel/preset-react&#39;]; 

// --plugins=플러그인1,플러그인2  동일
const plugins = [ 
  &#39;@babel/plugin-transform-arrow-functions&#39;,
  &#39;@babel/plugin-transform-template-literals&#39;,
];

module.exports = { presets, plugins }; </code></pre>
<blockquote>
<p>설정파일을 만들어 주었으니 <code>package.json</code>의 스크립트에서 프리셋&amp;플러그인 관련 명령어를 제거하여준다.</p>
</blockquote>
<pre><code class="language-js">&quot;scripts&quot;: {
    &quot;babel&quot;: &quot;npx babel src/code.js&quot;,
}</code></pre>
<h3 id="output">output</h3>
<p>지금까지 진행한 방식으로는 바벨을 통해 컴파일하여 콘솔에 출력할 수 있으나 새로운 파일로 저장하지는 못하는 상태다.
만약 새 파일에 컴파일 내용을 작성하고 싶다면 스크립트에 <code>--out-file</code>,<code>--out-dir</code> 옵션을 사용하자.</p>
<pre><code class="language-js"> &quot;scripts&quot;: {
    &quot;babel&quot;: &quot;npx babel src/code.js --out-file dist/dist.js&quot;, // 루트 dist폴더에 dist.js로 저장
    &quot;save-codejs&quot; :&quot;npx babel src --out-dir dist&quot;, // 루트 dist폴더에 cods.js로 저장
 }</code></pre>
<blockquote>
<p><code>--out-file</code>, <code>--out-dir</code> 를 같이 사용하면 콘솔에 <code>--out-file and --out-dir cannot be used together</code>에러를 출력한다. 이는 기능이 겹침으로 같이 사용할 필요가 없기 때문인데, </p>
</blockquote>
<ul>
<li><code>--out-file</code> : 파일만 생성할 수도 있고, 폴더경로/파일명 과같이 경로설정도 가능. 즉 <code>--out-dir</code> 기능이 포함되어 있다,</li>
<li><code>--out-dir</code> : 폴더생성</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>