<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>_junukim.log</title>
        <link>https://velog.io/</link>
        <description>https://junukim.dev &lt;- 호스팅하는 블로그입니다.</description>
        <lastBuildDate>Wed, 24 Feb 2021 16:10:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>_junukim.log</title>
            <url>https://images.velog.io/images/_junukim/profile/7559cfc0-3e99-11ea-8249-b5d8f306b80d/823586212106162666412362457419942757138432n.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. _junukim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/_junukim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Typescript + React + Rollup으로 풀세트 
 Component Library만들기]]></title>
            <link>https://velog.io/@_junukim/Typescript-React-Rollup%EC%9C%BC%EB%A1%9C-%ED%92%80%EC%84%B8%ED%8A%B8-Component-Library%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@_junukim/Typescript-React-Rollup%EC%9C%BC%EB%A1%9C-%ED%92%80%EC%84%B8%ED%8A%B8-Component-Library%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 24 Feb 2021 16:10:54 GMT</pubDate>
            <description><![CDATA[<h2 id="fcc-😘">FCC 😘</h2>
<p>최근에 회사에서 <code>ui-library</code>처럼 사용할 <code>global-package</code>를 만들었었다.
이름은 <code>FCC (Flex Custome Contract - Flex 커스텀 계약서)</code>로 고객사에서 커스텀 한 계약서(근로, 연봉, 경업금지 등..)를 간편하게 등록 및 관리할 수 있게 하였다.</p>
<p>계약서에 들어가야 하는 여러 <code>placeholder</code>들을 채워 넣어야 하는데 각각의 로직이 매우 복잡하게 이루어진다. 예를 들면 <code>이름</code>, <code>계약일</code>, <code>연 근무 시간</code>, <code>초과 근로 수당</code> 등이 있다.</p>
<p><code>근로자 A</code>의 <strong>연 근무 시간</strong>을 구하기 위해 <strong>주당 일하는 시간 및 휴게 시간</strong>, <strong>휴일 근로 여부와 시간</strong>, <strong>연봉 정보</strong> 등 여러 가지의 데이터가 필요한데 척 보기에도 복잡하게 생긴 데이터들을 소수점 단위로 계산해야 한다.</p>
<p>그리고 <code>FCC</code>에선 이런 <code>placeholder</code>들을 모두 계산해서 자동으로 지정된 위치에 넣어주는 역할을 한다.</p>
<p>FCC를 라이브러리처럼 만든 이유는 <code>Flex Client(클라이언트 - ts)</code> <code>Aws lambda(서버 - js)</code>에서 사용해야 하기에 어차피 <code>build</code> 파일이 필요한 구조라면 <code>libray</code>처럼 만들어서 어디와도 의존성을 완전 제거해보고 싶었다.</p>
<h2 id="비하인드-😢">비하인드 😢</h2>
<p>FCC는 현 product에 영향력이 강한 feature를 개발하는데 사용해야 해서 최대한 이쁘고 완벽하게 만들려고 노력했다. 그리고 셋업을 진행하며 피드백과 코드리뷰를 많이 받고 기쁜 마음으로 반영했다.</p>
<p><strong>하지만...</strong>
feature의 방향성이 바뀌면서 <code>library pr</code>을 <code>close</code>했다.</p>
<p>열심히 만든 FCC가 close 된 게 너무 아쉬워서 블로그 글로 남겨본다.</p>
<h2 id="왜-rollup인가-❓">왜 rollup인가 ❓</h2>
<p>rollup이 생소하고 익숙하지 않은 사람이 있을 수 있다. 애초에 라이브러리화하는 패키지가 webpack으로 빌드되는 <code>react (cra 기준)</code>로 개발되는데 <code>webpack</code>을 사용하면 된다고 생각할 수 있다.</p>
<p>맞다. webpack으로 빌드해도 ui-library를 만드는데 아무런 문제가 없다.
다만, webpack과 비교했을 때 라이브러리로써 얻을 수 있는 이점이 몇 있다.</p>
<ul>
<li><code>웹펙에서는 ESM 번들이 힘들다. -&gt; rollup은 가능</code></li>
<li><code>복잡한 웹펙보다 설정이 쉽다.</code></li>
<li><code>build 결과물이 좀 더 가볍다</code></li>
<li><code>webpack보다 강한 tree shaking을 지원한다</code></li>
</ul>
<p>이를 제외하고 개인마다 느끼는 이점은 다 다르겠지만 보편적인 예를 들어보았다.</p>
<h3 id="fcc의-rollup-👀">FCC의 rollup 👀</h3>
<p>FCC를 설계할 때 <code>rollup</code> 말고 <code>webpack</code>을 사용할 수도 있었다. 그런데도 rollup을 사용한 이유는 위에 나열되어있는 이유가 대부분이다.</p>
<p>개인적으로 <code>esm</code>과 <code>cjs</code>를 둘 다 제공하고 싶었고, 최근에 rollup관련 블로그를 많이 읽으면서 <code>package.json</code>의 강력함을 알게 되어서 이를 활용 해보고 싶기도 하였다.</p>
<h2 id="rollup-setting-⚒">rollup setting ⚒</h2>
<p>FCC는 <code>typescript</code> + <code>react</code> + <code>scss</code> + <code>rollup</code>의 구조로 이루어진다.
그리고 <code>cjs</code>와 <code>esm</code> 빌드를 제공한다. (FCC와 동일한 세팅을 하겠습니다.)</p>
<p>+<code>eslint</code>를 적용하고 깔끔한 환경에서 개발 하려 했었는데 전부 다 세팅하고 보니까 상위 package에서 적용되고 있는 별도의 lint때문에 내가 설정한 lint는 먹히지 않았다.</p>
<h3 id="1-packagejson-init">1. package.json init</h3>
<p>먼저 package.json을 만들기 위해 터미널에 명령어를 작성해준다.</p>
<pre><code class="language-ter">npm init</code></pre>
<p>명령어를 작성하고 나면 여러 질문을 할 것이다. 전부 엔터 누르고 마지막에 <code>yes</code> 하면 된다.
그러면 <code>package.json</code> 파일이 생성된다. 그리고 이어서 필요한 모듈들을 다운로드한다.</p>
<p>명령어는 네 줄 다 작성해야 한다.</p>
<pre><code class="language-ter">// babel
npm i -D @babel/core babel-preset-react-app

// rollup
npm i -D @rollup/plugin-commonjs @rollup/plugin-json @rollup/plugin-node-resolve rollup rollup-plugin-peer-deps-external rollup-plugin-postcss rollup-plugin-typescript2

// typescript, react
npm i -D @types/react typescript

// postcss
npm i -D node-sass postcss postcss-loader postcss-prefixer
</code></pre>
<p>모든 모듈이 다운로드 되고 나면 package.json에 <code>peerDependency</code>를 추가한다.
(peerDependency는 간단히 말해, 현 package(FCC)에 모듈을 다운하는 게 아니라 package를 사용하는 쪽(FCC를 사용하는 곳)에서 dependeny를 갖고 있어야 한다.)</p>
<pre><code class="language-json">{
  ...
  &quot;devDependencies&quot;: {
    ...
  },
  &quot;peerDependencies&quot;: {
    &quot;react&quot;: &quot;^16.8.6&quot;,
    &quot;react-dom&quot;: &quot;^16.8.6&quot;
  }
}</code></pre>
<p>peerDependency를 끝으로 모듈 다운로드는 끝이 났다.</p>
<p>그리고 build파일들을 외부에서 캐치할 수 있게 타입들과 빌드파일들을 package.json에 명시해주어야한다.</p>
<p>+추가로 간편 명령어 등록도 해주었다.</p>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;flex-customer-contract&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;components for contract in flex&quot;,
  &quot;license&quot;: &quot;UNLICENSED&quot;,
  // type 명시
  &quot;types&quot;: &quot;lib/index.d.ts&quot;,
  // 외부에서 접근할 index 명시
  &quot;main&quot;: &quot;dist/esm.js&quot;,
  &quot;directories&quot;: {
    &quot;example&quot;: &quot;example&quot;
  },
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;npm run exam &amp; npm run watch&quot;,
    &quot;build&quot;: &quot;rollup -c&quot;,
    &quot;watch&quot;: &quot;rollup -cw&quot;,
    &quot;exam&quot;: &quot;cd example &amp;&amp; npm start&quot;,
    &quot;lint&quot;: &quot;eslint . --ext .js,.jsx,.ts,.tsx&quot;
  },
  &quot;author&quot;: &quot;junwoo@flex.team&quot;,
  &quot;devDependencies&quot;: {
    ...
  },
  &quot;peerDependencies&quot;: {
    ...
  }
}</code></pre>
<h3 id="2-rollup-config">2. rollup config</h3>
<p>다음으로 rollup.config.js 파일을 생성한다.
rollup은 특이하게 config를 배열로 설정할 수 있다.
배열로 설정하게 되면 배열의 인자에 맞춰서 여러 개의 build파일이 생성된다.</p>
<pre><code class="language-js">import pkg from &#39;./package.json&#39;;
import typescript from &#39;rollup-plugin-typescript2&#39;;
import peerDepsExternal from &#39;rollup-plugin-peer-deps-external&#39;;
import postcss from &#39;rollup-plugin-postcss&#39;;
import postcssPrefixer from &#39;postcss-prefixer&#39;;
import resolve from &#39;@rollup/plugin-node-resolve&#39;;
import commonjs from &#39;@rollup/plugin-commonjs&#39;;
import json from &#39;@rollup/plugin-json&#39;;

const extensions = [&#39;.js&#39;, &#39;.jsx&#39;, &#39;.ts&#39;, &#39;.tsx&#39;, &#39;.scss&#39;];

process.env.BABEL_ENV = &#39;production&#39;;

function setUpRollup({ input, output }) {
  return {
    input,
    exports: &#39;named&#39;,
    output,
    watch: {
      include: &#39;*&#39;,
      exclude: &#39;node_modules/**&#39;,
    },
    plugins: [
      peerDepsExternal(),
      json(),
      resolve({ extensions }),
      commonjs({
        include: /node_modules/,
      }),
      typescript({ useTsconfigDeclarationDir: true }),
      postcss({
        extract: true,
        modules: true,
        sourceMap: true,
        use: [&#39;sass&#39;],
        plugins: [
          postcssPrefixer({
            prefix: `${pkg.name}__`,
          }),
        ],
      }),
    ],
    external: [&#39;react&#39;, &#39;react-dom&#39;],
  };
}

export default [
  setUpRollup({
    input: &#39;index.ts&#39;,
    output: {
      file: &#39;dist/cjs.js&#39;,
      sourcemap: true,
      format: &#39;cjs&#39;,
    },
  }),
  setUpRollup({
    input: &#39;index.ts&#39;,
    output: {
      file: &#39;dist/esm.js&#39;,
      sourcemap: true,
      format: &#39;esm&#39;,
    },
  }),
];</code></pre>
<p>위 config파일을 간단히 설명하면</p>
<ul>
<li><code>setUpRollup</code>이라는 함수를 만들어서 rollup config setting을 한다.</li>
<li><code>index.ts</code>파일을 불러와서 빌드하고 각각 <code>dist/cjs.js</code>와 <code>dis/dsm.js</code>로 추출한다.</li>
<li><code>source-map</code>파일을 함께 만들며 각각의 format은 <code>cjs, esm</code>으로 한다.</li>
<li>peerDependency를 사용할 수 있다.</li>
<li>json파일을 읽을 수 있다. (package.json을 읽기 위함)</li>
<li>ts 컴파일이 가능하다.</li>
<li>postcss를 통해 scss를 컴파일링 할 수 있다. 그리고 scss를 통해 만들어진 파일들의 이름앞에 prefix를 설정한다.</li>
</ul>
<h3 id="3-tsconfigjson-설정">3. tsconfig.json 설정</h3>
<p>FCC는 타입스크립트를 사용하기 때문에 ts를 관리하는 tsconfig 파일을 만들어 줘야한다.
(tsconfig 설정은 ts빌드 파일 관련한 설정을 제외하곤 생략)</p>
<pre><code class="language-json">{
  &quot;compilerOptions&quot;: {
    &quot;declaration&quot;: true,
    &quot;declarationDir&quot;: &quot;./lib&quot;, // lib폴더에 ts 타입 속성을 빌드한다.
    &quot;target&quot;: &quot;es5&quot;,
    &quot;lib&quot;: [&quot;dom&quot;, &quot;dom.iterable&quot;, &quot;esnext&quot;],
    &quot;skipLibCheck&quot;: true,
    &quot;esModuleInterop&quot;: true,
    &quot;allowSyntheticDefaultImports&quot;: true,
    &quot;strict&quot;: true,
    &quot;module&quot;: &quot;es6&quot;,
    &quot;moduleResolution&quot;: &quot;node&quot;,
    &quot;resolveJsonModule&quot;: true,
    &quot;jsx&quot;: &quot;react&quot;,
    &quot;typeRoots&quot;: [&quot;@types&quot;]
  },
  &quot;include&quot;: [&quot;**/*.tsx&quot;, &quot;**/*.ts&quot;, &quot;@types&quot;, &quot;index.ts&quot;],
  &quot;exclude&quot;: [&quot;node_modules&quot;, &quot;build&quot;, &quot;dist&quot;, &quot;lib&quot;, &quot;example&quot;, &quot;rollup.config.js&quot;]
}</code></pre>
<h3 id="4-테스트-환경-구성">4. 테스트 환경 구성</h3>
<p>FCC는 라이브러리기 때문에 다른 React 프로젝트에서 install 해서 테스트를 해봐야했다.
때문에 나는 <code>cra</code>를 이용하여 테스트 환경을 구성하였다.</p>
<pre><code class="language-ter">// rollup.config.js가 있는 path에서
create-react-app example</code></pre>
<p>그리고 cra로 만들어진 package.json 에 FCC를 install 하였다.</p>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;example&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;dependencies&quot;: {
    &quot;@testing-library/jest-dom&quot;: &quot;^5.11.4&quot;,
    &quot;@testing-library/react&quot;: &quot;^11.1.0&quot;,
    &quot;@testing-library/user-event&quot;: &quot;^12.1.10&quot;,
    // 요기
    &quot;flex-customer-contract&quot;: &quot;file:..&quot;,
    &quot;react&quot;: &quot;^17.0.1&quot;,
    &quot;react-dom&quot;: &quot;^17.0.1&quot;,
    &quot;react-scripts&quot;: &quot;4.0.1&quot;,
    &quot;web-vitals&quot;: &quot;^0.2.4&quot;
  },
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;PORT=8000 react-scripts start&quot;,
    &quot;build&quot;: &quot;react-scripts build&quot;,
    &quot;test&quot;: &quot;react-scripts test&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;
  }
}</code></pre>
<p>package.json에서 FCC를 install 할 때 path를 <code>file:..</code>으로 해주었는데, example 밖에 존재하는 FCC의 package.json에서 index.js를 main으로 설정해 주었기에 동작한다.</p>
<h3 id="5-indexts-생성-및-개발">5. index.ts 생성 및 개발</h3>
<p>기본적인 세팅이 마무리되었으니 직접 ts, tsx파일을 생성해서 library를 만들어야한다.</p>
<p>먼저 명령어로 rollup watch를 실행시킨다. rollup watch는 react의 hot-loader와 같은 역할을 한다. 그리고 example에서 테스트 해야하니까 함께 실행시킨다.</p>
<pre><code class="language-ter">// ter 1
npm run watch

// ter 2
npm run exam</code></pre>
<p>본격적으로 개발에 들어가서 <code>*.scss</code>파일들의 타입을 정의한다.</p>
<pre><code class="language-ts">// @types/index.d.ts
declare module &#39;*.scss&#39; {
  const content: { [className: string]: string };
  export = content;
}</code></pre>
<p>그리고 root가 될 <code>index.ts</code>와 demo component <code>Input.tsx</code> 를 작성한다</p>
<pre><code class="language-ts">// index.ts

export { default as Input } from &#39;./components/Input&#39;;</code></pre>
<pre><code class="language-tsx">// components/Input.tsx
import React from &#39;react&#39;;

import &#39;index.scss&#39;;

const Input = () =&gt; {
  return (
    &lt;div class=&quot;like-input&quot;&gt;인풋인 척 하는 div&lt;/div&gt;
  );
};

export default Input;</code></pre>
<p>그리고 scss테스트를 위해 <code>index.scss</code>파일을 생성한다.</p>
<pre><code class="language-scss">// index.scss
.like-input {
  width: 20px;
  height: 20px;
  background: red;
}</code></pre>
<h3 id="6-라이브러리-테스트">6. 라이브러리 테스트</h3>
<p>빌드가 성공적으로 돌아가면 /example/src에서 FCC를 install후 사용할 수 있다.</p>
<pre><code class="language-tsx">import React from &#39;react&#39;;
import * as FCC from &#39;flex-customer-contract&#39;;

function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;FCC.Input /&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<h2 id="코드리뷰로-코드-다듬기-✨">코드리뷰로 코드 다듬기 ✨</h2>
<p>코드리뷰 과정에서 53개의 코멘트를 받았다. 그리고 그 중 반영하면서 삽질을 많이 했던 부분들을 정리해보았다.</p>
<ol>
<li>절대경로를 설정하면 <code>build 결과물</code>이 회손될 수 있다. <strong>(path문제)</strong></li>
<li>tslint는 deprecated 되었다. -&gt; eslint로</li>
<li>rollup이 모노레포로 변화하면서 <code>@rollup/~</code>의 꼴로 package들이 변했다.</li>
<li><code>rollup-plugin-typescript2</code> package는 build시간을 <a href="https://github.com/rollup/rollup/issues/2716#issuecomment-484529982">많이 저하시킨다.</a></li>
<li>ant design의 build를 봤더니 <code>.css, .js</code> 이렇게만 build하더라. -&gt; FCC도 이렇게 해보자!</li>
</ol>
<h2 id="fcc잘가-🧵">FCC잘가 🧵</h2>
<p>FCC가 close된 것은 아쉽지만 재미있게 셋업 했던 것 같다.</p>
<p>요즘들어 회사일이 많이 바빠서 피곤했는데 잠시나마 코딩이아니라 빌드 셋업을 하니까 뭔가 많이 배운 것 같아서 기분이 좋다.</p>
<p>+) <a href="https://platum.kr/archives/151902">최근 받은 투자</a>에 힘입어 전 직군에서 함께 의지하며 성장하는 좋은 동료 분들을 모시고 있습니다. 관심이 가시거든 많은 지원 부탁드립니다.
<a href="https://recruiting.flex.team/#6b846298299540afaf25615d320d4674">flex 채용 링크 바로가기 😆</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫 직장, 첫 월급 그리고 첫 FLEX 🤘🏻]]></title>
            <link>https://velog.io/@_junukim/%EC%B2%AB-%EC%A7%81%EC%9E%A5-%EC%B2%AB-%EC%9B%94%EA%B8%89-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%B2%AB-FLEX</link>
            <guid>https://velog.io/@_junukim/%EC%B2%AB-%EC%A7%81%EC%9E%A5-%EC%B2%AB-%EC%9B%94%EA%B8%89-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%B2%AB-FLEX</guid>
            <pubDate>Thu, 05 Nov 2020 13:27:58 GMT</pubDate>
            <description><![CDATA[<p>내 나이 19살.
꿈에 그리던 취업에 성공하고 오늘 첫 월급을 받았다.🥳 한 달 이라는 짧은 시간동안 얼마나 많은걸 겪은지 모르겠다. 요즘 회사에서 업무에 집중하다보면 시간이 너무 빨리 지나가서 걱정이다. 한창 수능준비할(🤔) 19살인데 업무에 쏟아부을 시간이 부족하다고 말하고 있으니까 신기하기도 하다. </p>
<p>앞으로 한달 간격으로 회고를 써보기로 했다. 앞으로 계속 될 나의 개발자 인생의 첫 걸음을 땐만큼 열심히 하고싶은 마음 뿐이다.</p>
<h1 id="회사">회사</h1>
<p>나는 <code>소프트웨어 마이스터고등학교를 재학 중</code> 이다. 덕분에 고3인데도 불구하고 <code>현장실습</code>이라는 명칭으로 회사에 취업할 수 있었다. 나는 지금 <a href="https://flex.team">Flex 주식회사 </a>에 다니고 있다. 회사에 입사부터 퇴사까지 모든 인사관리업무를 대신 하는 <code>B2B SaaS 솔루션</code>을 제공하는 따끈따끈한 스타트업이다. (FLEX는 아름다운 미래, 밝은내일이 기다리고있다.😎 <del>난 나옹이다옹</del>)</p>
<p>간단한 취업 스토리를 읊어보면..</p>
<h2 id="면접-🤦🏻♂️">면접 🤦🏻‍♂️</h2>
<p>나는 친구들 사이에서 취업을 빨리한 편이 아니었다. 친구들이 하나둘 씩 취업을 하고 학교에서 떠나가는 모습을 보고 조바심을 느끼고 두려웠다. 게다가 나는 <strong>병역특례</strong>를 목표로 취업을 하려고 결심했었기에 도전할 수 있는 폭이 좁았다. </p>
<p>병역 TO를 갖고있는 회사는 서류부터 탈락했고 어찌저찌 1차, 2차합격을 하면 <code>코딩 테스트</code>라는 벽에 막혀 떨어지기 일쑤였다. 이렇게 계속해서 떨어진 기업들은 내가 욕심을 갖고 너무 큰 회사에 지원한게 아닌가 싶기도 하였고 아직 내가 많이 부족함을 느낄 수 있었다.</p>
<p>그렇게 계속해서 도전하고 선택하던 도중 학교 선배 한명이 사내추천으로 나를 넣어줬다. 꽤나 큰 회사였고 아는사람도 있었기에 지원서를 드렸더니 서류 통과를 받았다. 그리고 이어서 <code>코딩 과제</code>를 진행하였고, 결과는 정말 좋았다.</p>
<p>회사의 2차 면접 공지를 받고 꼭 합격하겠다는 마음으로 공부하고 준비하던 도중 충격적인 소식이 들려왔다. 만약 내가 합격한다 한들 2021년도에 병역특례 혜택을 받는게 힘들다고했다. (😭)</p>
<h2 id="flex-🏢">Flex 🏢</h2>
<p>그러던 도중 학교를 통해 <a href="https://flex.team">Flex</a>라고 하는 설립된지 2년도 안된 스타트업의 정보를 알게 되었다. 처음에는 이렇게 작은 회사에 들어가봐야 미래 보장도 안되고 성장하기도 힘들거라는 걱정이 앞섰다. 하지만 물불 가릴 처지가 아니었기 때문에 걱정되는 마음으로 서류를 넣었다. 서류를 넣고 하루 정도가 지나자 화상 인터뷰 요청이 왔고, 나는 기쁜마음으로 수락하였다.</p>
<p>Flex와 인터뷰를 마치고 난 뒤 든 생각은 딱 이거였다.</p>
<blockquote>
<p>조금 회사가 작은 것 같은데.. 이 것 빼면 다 좋은데? (<del>오해하지 마세요. 저는 Flex가 좋습니다. 이건 생각만.. 🤓</del>)</p>
</blockquote>
<p>첫 술에 배부를 수 없다고 하지만 회사의 대외적으로 알려진 정도가 친구들과 꽤 차이가 나서 자랑하고 싶었지만 남들이 부럽기만 했다. 그리곤 이미 취업한 것 마냥 김칫국을 마시다가 약속한 태크인터뷰 날짜가 다가오고 회사로 면접을 보러 갔다.</p>
<p>면접을 보면서 &#39;아 Fit이 잘 맞는다는게 이런거구나&#39; 하는 생각이 들정도로 물 흐르듯이 진행되었다. 그리고 결과는 대 성공이었다! (나는 면접이 끝나고 3<del>4일이 지나도록 결과가 안나오길래 떨어진 줄만 알았는데, 알고보니까 면접 이후 1시간도 안되서 합격 통보를 전했다고 한다. ~</del>학교에서 일부로 늦게 알려줬었다. 왜 그런 건지..~~)</p>
<p>아무튼 이렇게 우여곡절 끝에 <a href="https://flex.team">Flex</a>에 취업 하고 지금은 <code>Core Squad</code>에서 열심히 클라이언트 개발을 하고 있다.</p>
<h1 id="내가-한달동안-해온-일">내가 한달동안 해온 일</h1>
<h2 id="일주일의-적응-기간">일주일의 적응 기간</h2>
<p>처음에 회사에 오고 일주일동안은 회사에 적응하고 코드를 읽기 바빴다. COVID 19때문에 회사에서 제공하는 맥북이 중국에 묶여있어서 내 개인 맥북으로 일을 했던 것 같다.</p>
<p>우리 회사는 <code>FDS(Flex Design System)</code>라고 하는 디자인 시스템을 사용한다. 마치 <code>ant design</code>같이 모든 요소를 템플릿 화 시켜서 개발한다. 개인적으로 사이드 프로젝트를 하면서 꼭 한번 만들어보고 싶었던 구조였는데 회사에 와서 직접 사용해보니까 내 생각만큼 좋기도 하고 그만큼 단점도 있는 것 같고 싶다.</p>
<h2 id="바로-product-개발-😳">바로 Product 개발?! 😳</h2>
<p>일주일간 회사에 적응기간(?)을 갖고 개발 장비를 받았다. 맥북 16인치에 최고옵으로 회사에서 노트북을 준비해주었다. 새로운 장비를 받았다는 설레임에 기쁘고 신나서 더 열심히 했던 것 같다.</p>
<p>이것 저것 개발할 준비를 하고 <code>Planning Meeting</code>에 참가했다. (애자일 스럽게 <code>squad</code>단위로 팀을 나누고 개발하는 모습이 나도 이제 진짜 프로구나 라는 걸 세삼 느끼게 해주었다.) 미팅에서 서로 얘기를 나누다가 역할을 배정했었다. 회사에 신입으로 입사하면 이것 저것 배우고 사수님의 뒷바라지하는 역할을 하거나 귀찮은 노가다 작업 등을 하게 될 줄 알았는데 처음부터 <code>feature</code>개발에 참여하게 되었다.</p>
<p><code>feature</code> 개발이라고 해서 많이 긴장하고 설레었는데 그냥 하다보면서 느낀게
&#39;뭐야 그냥 학교에서 큰 프로젝트 할 때랑 별로 차이가 없잖아?&#39; 라는 생각이 좀 강하게 남았다.
학교에선 많이 바쁘면 프로젝트 5~6개 정도를 동시에 진행 하곤 했는데 지금은 그냥 매일매일이 그렇게 바쁘게 움직이면서 개발하는 느낌? 정도다.</p>
<h2 id="흠-개발은-뭔가-비슷하고요-다른게-좀-많이-다르네요-👀">흠.. 개발은 뭔가 비슷하고요.. 다른게 좀 많이 다르네요 👀</h2>
<p>솔직히 말해서 개발하는건 더 굴려주셔도.. 잘 할 수 있을 것 같다. (<del>물론 시간이 뒷 받쳐준다면..!</del>)</p>
<p>학교에서 프로젝트를 진행하면서 최대한 실무와 비슷하게 개발하려고 노력하다보니까 그런 것 같다.</p>
<p>그리고 개발적인 측면보다 일을하면서 동료들과의 커뮤니케이션이나 코드 컨벤션, 마인드 컨트롤 등을 더 많이 배우고 필요하다고 생각이된다. 일주일에 2~3번 정도 하루의 절반 정도를 쏟는 <code>planing meeting</code>과 역할 챕터 별 미팅이 있는데 (나는 <code>PE(Product Enginner) meeting과 FE(Front Enginner) meeting</code>에 참석한다.) 이렇게 모여서 실무 경험이 짱짱👍 하신 분들이 대화하는 걸 보고있으면 나는 한없이 작아진다.</p>
<p>그래도 한 4~5번 참석하고 나니까 나도 뭔가를 해야할 것 같아서 용기를 내보는 중이다.</p>
<h2 id="뭔가-내가-tl이-된-것-같다">뭔가 내가 TL이 된 것 같다.</h2>
<p>현재 내가 속해있는 <code>core squad</code>가 맡고 있는 <code>part</code>는 크게 3가지로 나뉜다. 그 중 한가지를 내가 혼자 FE(Front Enginner)작업을 해야한다. 내가 생각하기에는 엄청 나게 큰 <code>feature</code>단위 중 하나라고 생각이된다. 원래는 나 혼자하는 개발이 아니었다. FE(Front Enginner)와 BE(Back Enginner)를 모두 하실 수 있는 풀스택 팀원분이랑 함께 개발할 예정이었는데 갑자기 팀원분이 나에게 티타임을 요청하셨다.</p>
<p>스타트업에서 첫직장을 시작하다보면 내가 원하는 목표에 도달하기가 쉽지 않다고 하셨다. 대화를 나눠보니까 개발 직군에 관련된 이야기였다. WEB FE개발자를 목표로 취업했지만 스타트업에서는 자신이 하고싶지 않은 BE일이나 모바일 개발 등도 하게 될 수 있다. 라는 내용인데 내가 스타트업에 취업한 이상 이런 고민에 부딪힐 거라고 생각하고 있었기 때문에 별다른 고민없이 나는 말할 수 있었다.</p>
<blockquote>
<p>저는 흐름에 맞춰가고싶어요.</p>
</blockquote>
<p>나는 개발자로 살아가면서 여러가지를 공부해보고 경험하는 일은 필수적이라고 생각한다. 그렇기에 흐름에 맞춰가고 싶다. 라고 말씀을 드렸더니 팀원분께선 나에게 제안을 하셨다.</p>
<blockquote>
<p>팀원: 그러면 준우님이 Client개발을 <code>전부</code>하시는건 어떨까요?
나: 오.. 그러면 뭔가 저희 feature에서 제가 FE 리더 같은 느낌이네요?
팀원: 음.. 네 그렇죠.</p>
</blockquote>
<p>위와 비슷한 내용의 대화 맥락이 있었고 나는 뭔가 인정받았다는 느낌에 기분이 너무나도 좋았다.</p>
<p>그래서 지금 feature의 client를 인수인계 받아서 협업하며 개발에 착수하고 있다.</p>
<h2 id="기술적인-측면에서-봤을-땐">기술적인 측면에서 봤을 땐..</h2>
<p>학교에서 사이드프로젝트를 진행하거나 친구들과 큰 프로젝트를 진행할 때 개발하면서 최대한 코드를 깔끔하게 짜보려고 노력했었다.</p>
<p>나는 개발을 할 때 우선순위 1번으로 <strong>코드 퀄리티</strong>를 두고 2번으로 <strong>기능이 동작하게 하자.</strong> 로 두었다.</p>
<p>하지만 지금 회사에서는</p>
<ol>
<li>코드 퀄리티</li>
<li>기능의 효율성</li>
</ol>
<p>으로 우선순위를 맞추고 있다. 나는 지금까지 기능의 효율성에 관해서 많은 고민을 하지 않았었다.</p>
<p>내가 회사에 와서 기술적으로 많이 배우고 성장한 건 <code>React Component Debugging</code>과 <code>rendering</code>을 고려해서 성능상의 이슈를 해결하는 방법등 인 것 같다.</p>
<h1 id="왜-나만-1레벨-이지-🤔">왜 나만 1레벨 이지? 🤔</h1>
<p>우리 회사는 엄청 특이하다.
신입(주니어)개발자는 나 한명 뿐이고 나머지 전부 엄청난 이력을 갖고 있는 만렙 개발자 뿐이다. 우리나라에 <code>typescript</code>를 전파했다고 불러도 손색이 없는 슈퍼 개발자분과 네이버가 젖먹던 시절부터 지금 한국을 대표하는 검색엔진이 되기까지 많은 기여를 하신 분도 계시다. 현재 잘나가는 스타트업의 공동 창업자 분들도 계시고 친구가 다니고 있는 회사의 초기 맴버였던 분들도 계시다.</p>
<p>여기서 충격적인건 나를 제외하곤 서로가 대부분 같이 일을 해봤던 사이인 것 이다. 🥺</p>
<h2 id="솔직히-좋으면서-왜-그래-😘">솔직히 좋으면서, 왜 그래~ 😘</h2>
<p>맞다. 나는 사실 지금 내 직장생활이 너무나도 행복하다.</p>
<p>앞으로 살면서 이런 경험을 할 수 있을까 싶기도 하고 계속 이렇게 가다간 나도 슈퍼 개발자가 되는거 아니야?! 하는 망상속에서 살고있기 때문에 지금은 너무나도 행복하다. 첫 직장이라서 모르는 것도 많았고 어떻게 해야할지 감이 잘 안왔지만 지금은 잘 적응해서 일 할 시간이 부족하다.</p>
<p>아 그리고, 팀원분들이 내가 고등학생이라고 자꾸 놀린다.</p>
<p>이렇게 계속 나한테 말 걸어주고 자꾸 다가와주어서 나는 너무 기쁘고 안도한다. 신년이되면 나도 이제 성인이니까 어른의 세계를 알려주신다고 하셨다. (<del>술.. 좋지..</del>)</p>
<h2 id="첫-flex">첫 Flex</h2>
<p>결론은, 내 첫 회사는 Flex이고 1의 후회도 없고 행복한 회사 생활을 하고 있다. 첫 월급을 받고 적지도 많지도 않은 딱 적당한 금액(<del>학생 신분으로 현장실습 중이라서 기존의 받는 금액의 70%정도를 받는다.</del>)으로  남들보다 빠른 스타트와 좋은 환경에서 일하고 공부할 수 있음에 감사하다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/858fe83e-e1cc-4475-a5f6-63dbcecd9c59/%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-11-05%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.33.56.png" alt="ㅠㅠ">
아 그리고 오늘 2020년도 병역특례업체에 선정되었다. 🥳
기념으로 슬랙으로 팀원분들이 농담을 해주셨는데 벌써 너무 슬프다. (<del>사실 좋다.😏</del>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Clean Architecture 깔끔하게 정리하기 😎]]></title>
            <link>https://velog.io/@_junukim/Clean-Architecture-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_junukim/Clean-Architecture-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 17 Sep 2020 01:18:12 GMT</pubDate>
            <description><![CDATA[<p>로버트 C. 마틴을 저자로한 도서 Clean Architecture를 보고 공부했던 내용을 공유합니다.</p>
<p><a href="https://app.gitbook.com/@junukim-dev-1/s/clean-architecture/">클릭아키텍처 정리</a></p>
<p>오타 및 잘못된 정보는 <a href="mailto:junukim.dev@gmail.com">junukim.dev@gmail.com</a> 으로 연락부탁드립니다. 🤞</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🙌 makeToon 완성기 - 2]]></title>
            <link>https://velog.io/@_junukim/makeToon-%EC%99%84%EC%84%B1%EA%B8%B0-2</link>
            <guid>https://velog.io/@_junukim/makeToon-%EC%99%84%EC%84%B1%EA%B8%B0-2</guid>
            <pubDate>Tue, 15 Sep 2020 00:39:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/_junukim/post/8b9a9bb8-4948-4504-9214-948ec69b8416/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.39.24.png" alt="메인페이지"></p>
<h2 id="react에서-svg-사용하기-🤹♂️">React에서 SVG 사용하기 🤹‍♂️</h2>
<p>React에서는 SVG를 다른 <code>assets</code>처럼 사용할 수도 있지만 <code>component</code>로 분할하여 사용할 수 있습니다.</p>
<p>svg파일을 열면 <code>svg</code>태그와 <code>g</code>, <code>path</code>등의 태그들을 확인할 수 있습니다. 그리고 이들로 svg를 구성하고 만듭니다.</p>
<p>그리고 이를 React에서 SVG로 컴포넌트화 시키는데 방법이 조금 까다롭습니다.</p>
<p>SVG파일이 작거나 비교적 만들기 쉬운 모양이라면 태그 조금의 변경으로 컴포넌트화가 가능합니다. 그러나 지도 SVG처럼 모양이 다체롭고 복잡한 경우에는 해당 방법이 거의 불가능합니다.</p>
<p>그래서 저는 어떻게 <code>Component</code>로 바꿀 수 있을까 구글링하다가 <code>SVG To JSX</code>라는 키워드를 통해 좋은 사이트를 찾을 수 있었습니다.</p>
<p><a href="https://svg2jsx.com/">svg2jsx.com</a></p>
<p>위 사이트는 SVG파일을 insert하면 JSX에서 사용가능한 SVG컴포넌트를 만들어줍니다. </p>
<p>이를 통해 SVG를 컴포넌트로 변경켰습니다. 그리고 SVG를 굳이 컴포넌트로 변형시킨 이유가 있습니다. SVG파일을 컴포넌트로 변경시켜 <code>react의 hooks와 지도 path의 onClick event</code>를 사용하기 위해서입니다.</p>
<p>지도의 곳곳을 클릭하여 이미지를 추가해야하는 프로젝트여서 어떻게 개발할까 생각하다가 이런 방법을 택하게 되었습니다.</p>
<h2 id="지역별-클릭-🥄">지역별 클릭 🥄</h2>
<p>인터넷을 통해 지도 SVG파일을 얻고 이를 바탕으로 지도앱을 개발하던도중 하나의 문제에 부딪히게됩니다.</p>
<blockquote>
<p>사용자가 지명을 모르면 말짱도루묵아닌가?</p>
</blockquote>
<p>그렇습니다. 제가 같고있는 SVG는 오직 지도 하나뿐이었습니다.</p>
<p>열심히 구상하고 계획한 프로젝트가 엉망이되려고하자 저는 직접 SVG를 만들어보기로 하였습니다.</p>
<p><code>XD</code>를 열어 지도 SVG를 붙이고, 구역에 맡게 이름을 써내려갔습니다. 너무 자잘자잘하거나 작은것들은 하나의 지역으로 모아서 붙이고, 너무 크거나 애매한 지역은 동부, 서부등으로 나누어서 지역을 나누었습니다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/b9686a07-8548-4957-b453-814bdee1694b/%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-09-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.17.05.png" alt="지역 SVG"></p>
<p>그리고 이렇게 하여 두개의 SVG파일을 얻을 수 있었습니다.</p>
<h3 id="pointer-events-none-👍">pointer-events: none; 👍</h3>
<pre><code class="language-tsx">&lt;svg ... /&gt; // 지역
&lt;svg ... /&gt; // 지도</code></pre>
<p>위와 같이 svg를 배치하고 <code>css position</code>을 <code>absolute</code>로 설정하여 위에 올린 후 지도 SVG에 <code>onClick</code>이벤트를 <code>path</code>마다 적용시켰더니 <strong>지역SVG에 지도SVG가 가려져서 클릭 이벤트에 접근을 하지 못하였습니다.</strong></p>
<p>정말 하루종일 구글링하고 여러 키워드로 검색하였으나 방법을 찾을 수 없어서 카카오톡 오픈채팅방과 페이스북을 통해 질문도 하였습니다.</p>
<p>하지만 키워드 선택에 실패했는지 방법은 찾기 힘들었고 계속해서 고민만 늘어났습니다.</p>
<p>그러다가 딱 머리를 스치고 지나가는 생각이 있었습니다.</p>
<blockquote>
<p>분명히 CSS에서 클릭을 비활성화 시킬 수 있을거야.</p>
</blockquote>
<p>그래서 CSS에 초첨을 두고 구글링를 하였는데.. 방법을 찾았습니다.
그리고 해당 방법은 <code>pointer-events: none;</code>이라는 속성입니다.</p>
<p>MDN에서 <code>pointer-events</code>속성을 다음과 같이 정의하고 있습니다.</p>
<blockquote>
<p><strong><a href="https://developer.mozilla.org/ko/docs/Web/CSS/pointer-events">MDN링크</a>:</strong> 그래픽 요소가 어떤 상황에서 포인터 이벤트의 대상이 될 수 있는지 지정합니다.</p>
</blockquote>
<p>pointer-events를 <code>none</code>으로 설정해주면 이벤트의 대상으로 설정되지 않습니다.</p>
<p>MDN에서 <code>pointer-events: none</code>을 다음과 같이 정의하고 있습니다.</p>
<blockquote>
<p><strong><a href="https://developer.mozilla.org/ko/docs/Web/CSS/pointer-events">MDN링크</a>:</strong> 요소가 포인터 이벤트의 대상이 되지 않습니다. 그러나 해당 요소의 자손이 다른 pointer-events 값을 지정한 경우, 그 자손은 대상이 될 수 있습니다. 이 때는 이벤트 캡처/버블 단계에서 none을 지정한 요소의 이벤트 처리기를 발동할 수 있습니다.</p>
</blockquote>
<p>이런 CSS도 있구나.. 하며 감탄했습니다.</p>
<h2 id="typescript로-지도-조작-만들기">Typescript로 지도 조작 만들기</h2>
<ul>
<li>지도 드래그</li>
<li>지도 확대 축소
위 내역은 현재 지도를 조작할 수 있는 방법들 입니다.</li>
</ul>
<p>라이브러리를 사용하지 않고 순수 Javascript(TS)로 개발하면서 생겼던 이슈들을 공유하려고 합니다.</p>
<p>다음 포스팅에서 자세하게 설명해드리겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🙌 makeToon 완성기 - 1]]></title>
            <link>https://velog.io/@_junukim/makeToon-%EC%99%84%EC%84%B1%EA%B8%B0-1</link>
            <guid>https://velog.io/@_junukim/makeToon-%EC%99%84%EC%84%B1%EA%B8%B0-1</guid>
            <pubDate>Tue, 01 Sep 2020 06:24:57 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/_junukim/post/6b715a1a-b0f2-4bb3-bfda-af29987f9faf/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.39.24.png" alt="maketoon 메인 이미지"></p>
<h2 id="개발-전-준비-사항-🤔">개발 전 준비 사항 🤔</h2>
<p>오랫만에 혼자하는 프로젝트이고 열심히 해보고 싶어서 차근차근 시작하기로 하였습니다. 그래서 개발 전에 미리 준비해야할 사항이 있을까? 싶어서 리스트를 나열해보았습니다.</p>
<ul>
<li>❌ 지도 모양의 <code>svg 파일</code></li>
<li>❌ 간편 로그인을 위한 <code>oAuth</code> 연결</li>
<li>❌ 배포를 위한 <code>aws ci/cd</code> 작업</li>
<li>❌ 정적 이미지 관리를 위한 <code>s3</code> 연결</li>
</ul>
<p>나열해본 리스트는 다음과 같았고, 하나하나 꼼꼼히 준비하였습니다.</p>
<h3 id="지도-모양의-svg-파일-😬">지도 모양의 <em>svg 파일</em> 😬</h3>
<p>구글에 지도 모양의 svg파일을 검색하면 여러가지 블로그와 파일들이 나옵니다. 이 중 저작권 관리가 쉽고 다루기쉬울 만한 파일이 뭐가 있을까 찾다가 <a href="https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%9D%BC:Administrative_divisions_map_of_South_Korea.svg">위키백과</a>에서 한국 지도를 찾아볼 수 있었습니다. 2014년이 마지막 업데이트지만 그래도 쓸만할 것 같아서 해당 svg로 골랐습니다.
<img src="https://images.velog.io/images/_junukim/post/cfd17cef-2813-4bf9-8ade-7182da12347a/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.44.59.png" alt="위키백과 이미지"></p>
<ul>
<li>✅ 지도 모양의 <code>svg 파일</code></li>
<li>❌ 간편 로그인을 위한 <code>oAuth</code> 연결</li>
<li>❌ 배포를 위한 <code>aws ci/cd</code> 작업</li>
<li>❌ 정적 이미지 관리를 위한 <code>s3</code> 연결</li>
</ul>
<h3 id="간편-로그인을-위한-oauth-연결">간편 로그인을 위한 <em>oAuth</em> 연결</h3>
<p>사용자에게 보다 편한 UX를 제공하기위해 별도의 로그인을 구현하지 않고 <code>oauth</code>연동을 통해 한번의 클릭만으로 로그은을 진행할 수 있도록 하였습니다.</p>
<p>특별히 oAuth중 <code>Facebook</code>을 사용하였습니다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/20ab6219-960d-4bbd-8151-fbac5c7c7915/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.46.21.png" alt="페이스북 이미지"></p>
<p>이와 같이 페이스북 개발자 센터에서 앱을 등록하고 Facebook로그인 제품 검수를 받았습니다. 요즘은 COVID 19 때문에 앱 검수가 힘들다고 하던데.. 작년 12월에 미리미리 해놔서 다행인 것 같습니다.</p>
<ul>
<li>✅ 지도 모양의 <code>svg 파일</code></li>
<li>✅ 간편 로그인을 위한 <code>oAuth</code> 연결</li>
<li>❌ 배포를 위한 <code>aws ci/cd</code> 작업</li>
<li>❌ 정적 이미지 관리를 위한 <code>s3</code> 연결</li>
</ul>
<h3 id="배포를-위한-aws-cicd-작업">배포를 위한 <em>aws ci/cd</em> 작업</h3>
<blockquote>
<p>자세한 내용은 <a href="https://velog.io/@_junukim/CloudFront%EB%A1%9C-React%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0">CloudFront로-React앱-배포하기</a> 편을 참고하여 주세요.</p>
</blockquote>
<p>개발에 앞서서 미리 클라이언트의 배포환경을 구축하고 <code>Github Actions</code>를 이용한 파이프라인까지 만들어두었습니다.</p>
<p>해당 <code>build.yml</code>파일과 모든 개발 파일은 <a href="https://github.com/makeToon">여기</a>에서 확인하실 수 있습니다.
<img src="https://images.velog.io/images/_junukim/post/12ed5e27-a704-454a-bf89-f676f41f0571/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.11.22.png" alt="깃허브 액션스 이미지"></p>
<ul>
<li>✅ 지도 모양의 <code>svg 파일</code></li>
<li>✅ 간편 로그인을 위한 <code>oAuth</code> 연결</li>
<li>✅ 배포를 위한 <code>aws ci/cd</code> 작업</li>
<li>❌ 정적 이미지 관리를 위한 <code>s3</code> 연결</li>
</ul>
<h3 id="정적-이미지-관리를-위한-s3-연결">정적 이미지 관리를 위한 <em>s3</em> 연결</h3>
<p>저는 평소 개발할 때 <code>assets</code>들을 배포 파일에 함께 넣어서 배포했는데 저번에 황당한 경험을 한 이후로 <code>AWS S3</code>에 정적 파일을 따로 저장하고 URL로 불러옵니다.</p>
<blockquote>
<p>이미지 파일이랑 동영상파일들을 함께 빌드해서 배포했더니 ReactAPP용량이 8MB가 넘었었다. <del>ㅋㅋ.. 지금 생각해보면.. 와우</del>
사용자를 고려하지 않고 돌아가니까 상관없지~ 했던 내가 생각난다..
<del>😑 해당 React앱 빌드는 다시 했었따.</del></p>
</blockquote>
<p><img src="https://images.velog.io/images/_junukim/post/27ac6aea-5970-4012-bdb5-217cfcd8ace2/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.14.57.png" alt="이미지 설명 코드 이미지"></p>
<p>이렇게 import해서 사용하였습니다.</p>
<ul>
<li>✅ 지도 모양의 <code>svg 파일</code></li>
<li>✅ 간편 로그인을 위한 <code>oAuth</code> 연결</li>
<li>✅ 배포를 위한 <code>aws ci/cd</code> 작업</li>
<li>✅ 정적 이미지 관리를 위한 <code>s3</code> 연결</li>
</ul>
<h2 id="이슈-및-해결-방법-🤷♂️">이슈 및 해결 방법 🤷‍♂️</h2>
<p>지도 SVG를 이용하면서 정말 많은 이슈와 문제들이 있었습니다.</p>
<p>SVG만 이렇게 직접적으로 다뤄본 적도 처음이었고 React에서 SVG를 사용하는게 좀 힘들었습니다.</p>
<p>또 <code>지도 드래그</code>와 <code>줌 인/아웃</code>, <code>지역 별 클릭</code>등 기능을 구현하는데 다양한 버그가 있었습니다.</p>
<p>다음 포스팅에서 이러한 이슈들과 이슈별 해결방안을 설명드리겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🙌 makeToon 완성기 - 0]]></title>
            <link>https://velog.io/@_junukim/MakeToon-%EC%99%84%EC%84%B1%EA%B8%B0</link>
            <guid>https://velog.io/@_junukim/MakeToon-%EC%99%84%EC%84%B1%EA%B8%B0</guid>
            <pubDate>Tue, 01 Sep 2020 02:12:14 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/_junukim/post/6f3a6b63-b636-45da-a748-02dd13b90939/%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-09-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.39.24.png" alt="maketoon 메인 이미지"></p>
<h1 id="maketoon-😉---웹-포토로그-제작">makeToon 😉 - 웹 포토로그 제작</h1>
<p> 사람들은 여행을 하고 사진으로 당시의 기억과 추억을 남깁니다. 하지만 사진으로 추억을 남긴다고 해도 당시의 상황이나 위치 등을 정확히 기억하지 못합니다. 이를 해결할 수 있는 방법은 없을까?</p>
<p> 사진으로 이루어진 지도를 만든다면 어떨까? 더욱 눈에 띄고 사진을 하나하나 채워 가면서 이것 또한 추억이 되지 않을까? 그리고 더욱 기억을 정확하고 오래 갖고 있지 않을까? 이러한 생각에서 개발된 <strong>사진으로 지도를 구성할 수 있는 어플. <code>makeToon</code></strong> 입니다.</p>
<h2 id="서론">서론</h2>
<p>MakeToon은 고등학교 2학년 겨울방학이 시작되고 겨울방학을 알차게 보내보자는 생각에서 여러 아이디어를 모아보다가 꽤 괜찮은 아이디어 같아서 개발하게 되었습니다. <strong>2019년 12월</strong> 부터 <strong>2020년 7월말</strong> 까지 개발하였으며 현재는 서비스되고 있는 중 입니다.</p>
<p>개발하면서 겪은 이슈 및 해결방안을 공유하기 위해 글을 작성합니다. 🎧</p>
<h2 id="기타">기타</h2>
<p>makeToon은 <a href="https://maketoon.junukim.dev">이곳</a>에서 이용하실 수 있습니다.
주소는 <code>https://maketoon.junukim.dev</code>입니다.</p>
<p>다음은 추후에 추가될 기능입니다.</p>
<ul>
<li><code>지도 프린트</code> 기능</li>
<li><code>모든 사진 모아보기</code> 기능</li>
<li><code>지도 공유</code> 기능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CloudFront로 React앱 배포하기 - 2]]></title>
            <link>https://velog.io/@_junukim/CloudFront%EB%A1%9C-React%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0-2</link>
            <guid>https://velog.io/@_junukim/CloudFront%EB%A1%9C-React%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0-2</guid>
            <pubDate>Mon, 27 Apr 2020 08:57:08 GMT</pubDate>
            <description><![CDATA[<h2 id="cloudfront-">CloudFront ?</h2>
<p>내가 CloudFront로 정적 웹 사이팅을 배포하는 이유는 별거 없다.
<strong>https가 무료</strong>이고, <strong>배포가 간단하기</strong> 때문이다. 나한테는 https가 무료인게 많이 끌렸었다.</p>
<h3 id="시작하기">시작하기</h3>
<p>먼저 S3때와 마찬가지로 CloudFront를 검색해준다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/f2a17cb5-e779-4c21-8463-a9b96a891e93/image.png" alt="클라우드 프론트 검색"></p>
<p>그리고 <code>Create Distribution</code>버튼을 클릭한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/faabe95c-8c25-4352-b295-d732e0587e2c/image.png" alt="클라우드 프론트 개설"></p>
<p>내 프로젝트는 당연히 웹이니까 <code>Web</code>란의 <strong>Get Started</strong> 버튼을 누른다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/e2841ec0-0716-42d3-8e03-f0c0f433ee03/image.png" alt="웹 선택"></p>
<p>이제 뭔가를 막 입력해야하는데 여기서 잘못입력하면 꼬일 수 있으니까 주의하면서 진행한다.</p>
<p>먼저 <strong>Origin Domain Name</strong>을 클릭하면 자신의 S3와 자동으로 연결되고, S3에서 만들어 둔 버킷과 연결할 수 있다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/01a4cb90-2661-4d61-9eac-c695c0a6f410/image.png" alt="도메인 이름"></p>
<p>이후 아래 <code>Default Cache Behavior Settings</code>에서 Viewer Protocol Policy를 <code>Redirect HTTP to HTTPS</code>로 바꿔준다. 그리고 맨 아래의 <code>Create Distribution</code>버튼을 눌러준다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/d1df0c86-a627-4c11-a8bb-328c4995923c/image.png" alt="설정 중"></p>
<p>그러면 저렇게 Status가 <code>in Progress</code>인 클라우드 프론트 Distribution이 생긴 것을 확인할 수 있다. in Progress 상태가 해제되면 CloudFront 생성이 완료된다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/6602d5bb-79f6-4bdf-bd50-fe31a5d4984f/image.png" alt="짜란"></p>
<p>CloudFront가 다 생성되고 나면 <code>Domain Name</code>을 통해서 배포한 React앱에 들어갈 수 있다. HTTPS가 적용된 상태일 것 이다.</p>
<h2 id="에러-핸들링">에러 핸들링</h2>
<p>React와 같은 SPA를 통해 S3 - CloudFront 배포를 하게되면 <code>Redirect</code>문제가 발생한다.</p>
<p>예를 들어 <a href="https://maketoon.junukim.dev">https://maketoon.junukim.dev</a> 라는 도메인으로 React앱을 배포했다.</p>
<p>해당 URL에 그냥 접속하면 앱은 매우 잘 작동한다. <strong>하지만 <a href="https://maketoon.junukim.dev/photomap">https://maketoon.junukim.dev/photomap</a> 으로 접속하면 <code>Access Denied</code> 문제가 발생한다.</strong> </p>
<p>이는 React에서 사용하는 <code>react-router-dom</code>때문인데, CloudFront에서 redirect를 403으로 막은 것 이다. 그래서 이를 해결하려면 CloudFront에서 에러 핸들링을 해줘야한다.</p>
<h3 id="access-denied-방지">Access Denied 방지</h3>
<p>CloudFront Distributions에서 자신의 CloudFront ID를 클릭하여 상세정보를 열람한다. 그 후 <code>Error Pages</code> 탭으로 이동하고 <code>Creaet Custom Error Response</code>버튼을 클릭한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/20307b91-2feb-4c4f-9efd-72796013d2bf/image.png" alt="403에러 해결 - 1"></p>
<p>해당 이미지와 같이 HTTP Error Code를 403으로 설정하고 TTL을 5초로 설정한다. 그리고 Response Page Path와 Response Code를 설정해준다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/9dcbf20e-ef95-4298-b2cb-34902bfceb6e/image.png" alt="403에러 해결 - 2"></p>
<p>403 뿐 아니라 404도 똑같이 만들어주면, 이렇게 된다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/d70f9fbb-02af-4b44-adb4-5cca54370173/image.png" alt="403에러 해결 - 3"></p>
<h3 id="캐시-문제-해결">캐시 문제 해결</h3>
<p>그리고 마지막으로 CloudFront는 배포에 오랜시간이 걸린다. 사실 배포에는 오래걸리지 않지만 브라우저 캐시 때문에 적용하고 하루 넘게 지나야 적용되는 것 이다. 이를 해결하는 방법은 간단하다.</p>
<p><code>Invalidations</code>탭으로 이동해서 <code>Create Invalidation</code>버튼을 클릭한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/8aa0eb68-3c6f-4c06-a706-f6598a23de91/image.png" alt="캐시 문제 해결 - 1"></p>
<p>그리고 Object Paths에 <strong>* or /*</strong> 이라고 입력한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/35ac44c9-924d-417f-a8a6-744de9cef60f/image.png" alt="캐시 문제 해결 - 2"></p>
<p>그리고 한 3분 정도 지나면 캐시 문제는 해결된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CloudFront로 React앱 배포하기 - 1]]></title>
            <link>https://velog.io/@_junukim/CloudFront%EB%A1%9C-React%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_junukim/CloudFront%EB%A1%9C-React%EC%95%B1-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 26 Apr 2020 10:36:18 GMT</pubDate>
            <description><![CDATA[<p>웹 개발을 공부하고 React를 사용하여 나만의 프로젝트를 진행하면서 localhost가 아닌 나만의 도메인으로 앱을 배포하고 싶었다. 그래서 공부했고 배포했다. 어려움은 거의 없었지만 그래도 내가 배포해본 경험을 글로 남겨본다.</p>
<h2 id="앱-소개">앱 소개</h2>
<p><img src="https://images.velog.io/images/_junukim/post/bdb9b9b5-9786-43b9-8805-bd3e88341ca4/image.png" alt="앱 이미지">
&quot;MakeToon&quot; 이라는 이름을 갖고있는 포토로그 프로젝트이다. React로 여러 프로젝트를 진행하였지만 해당 프로젝트만큼 SVG를 열심히 사용한 건 처음인 것 같다. 해당 프로젝트를 AWS에 올린 경험을 포스팅 하겠다.</p>
<p>프로젝트 소개는 <a href="https://www.notion.so/junukimdev/2bfe9a2ecee54a1f9a6a5858efe57188">노션</a>으로 대체하도록 하겠다.</p>
<p>! 프로젝트 관련 포스팅 -&gt; <a href="">바로가기</a></p>
<h2 id="react-앱-빌드">React 앱 빌드</h2>
<p>앱을 배포하기 위해선 develop모드가 아닌 product모드로 앱을 빌드해서 html파일을 뽑아야한다.</p>
<pre><code class="language-shell">&gt; npm run build</code></pre>
<p>해당 명령어를 통해 빌드된 앱을 만들 수 있다.</p>
<p>나 같은 경우는 <code>custom webpack</code>을 사용하기 때문에 <code>index.html</code>과 <code>main.css</code>, <code>bundle.js</code> 그리고 <code>favicon과 public파일</code>들로 이루어지지만 <code>create-react-app</code>을 이용해서 앱을 개발한 경우는 여러 파일들이 같이 나오게 된다.</p>
<p><code>CRA</code>를 사용해서 앱을 빌드하거나, <code>custom webpack</code>을 이용한 경우 모두 상관없이 AWS에서 배포할 수 있으니 별 걱정하지 않아도 된다.</p>
<h2 id="aws">AWS</h2>
<p>포스팅의 목표가 <code>CloudFront로 React앱 배포하기</code>인 만큼 AWS를 사용해야만 한다.</p>
<p>aws계정이 따로 없는 경우 AWS에 회원가입을 해준다.</p>
<p>참고로, AWS에 처음 접속하면 따로 회원가입 버튼이 없고 <strong>콘솔에 로그인</strong>이라는 버튼이 있다. 버튼을 클릭하면 <strong>AWS 계정 새로 만들기</strong>를 통해 회원가입이 가능하다.</p>
<h2 id="s3">S3</h2>
<p>AWS에 회원가입을 완료했으면 본격적인 배포를 할 수 있다.</p>
<p>내가 배포한 방법은 다음과 같다.</p>
<ol>
<li>정적 데이터를 AWS의 S3에 저장.</li>
<li>S3를 통해 정적 웹 호스팅을 구축하고 이를 CloudFront를 통해 배포.</li>
<li>route53을 이용해 CludeFront를 내 도메인에 장착.</li>
</ol>
<p>먼저 s3에 배포하기위해 서비스 검색을 한다.
해당 검색란에 <strong>S3</strong>를 검색한다. (S3 - 클라우드의 확장 가능한 스토리지)</p>
<p><img src="https://images.velog.io/images/_junukim/post/8c02ac41-b9a0-444a-8f17-007d87b3db15/image.png" alt="AWS 검색란 이미지"></p>
<p>S3를 성공적으로 검색하고 redirect되면 해당 화면으로 넘어온다. 여기서 <strong>버킷 만들기</strong> 버튼을 클릭한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/14db11b3-6c43-49d8-8259-a845b1f8ce6b/image.png" alt="S3 버킷 만들기 이미지"></p>
<p>버킷 이름을 정하고 위치를 조정한다.
아마 대부분 <code>아시아 태평양(서울) ap-northeast-2</code> 이라고 생각한다.
이후 버킷을 만들어준다.
<img src="https://images.velog.io/images/_junukim/post/ea4ac679-bbfb-4e0b-abe1-f86feb86ab6a/image.png" alt="버킷 만드는 중 이미지"></p>
<p>이렇게 버킷이 만들어진 것을 확인할 수 있다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/4ab806de-91eb-4424-8423-5cbc6aff7160/image.png" alt="버킷 완성된거 보는 이미지"></p>
<p>이제 해당 버킷을 공개적으로 사용할 수 있도록 수정해줘야한다. 현재 버킷은 엑세스가 <code>퍼블릭 아님</code>으로 되어있다. 이렇게 되면 권한이 없는 사람들은 나의 앱에 접근할 수 없다. (<code>access denied</code>) 그러므로 수정해보도록 하겠다.</p>
<p><strong>이름</strong>란에 있는 파란 버킷 이름을 누르면 된다. (해당 포스트에선 <strong>junukim-dev-posting</strong>)</p>
<p>클릭해서 버킷에 접속하면 해당 화면을 마주한다. 이때 바로 보이는 화면에서 나의 앱을 버킷에 담을 수 있다. 자신의 빌드 파일을 <strong>이 버킷은 비어 있습니다. 시작하려면 새 객체를 업로드합니다.</strong> 라고 적혀있는 하늘색 네모로 드래그하거나 업로드하면 된다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/bfed955e-dac3-43d0-9013-00b65619736c/image.png" alt="버킷 들어온 이미지"></p>
<p>성공적으로 빌드 파일을 업로드하면 이렇게, 파일이 생긴 것을 볼 수 있다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/153e311a-2bb4-4027-8b63-2cb7dcd2531c/image.png" alt="파일 올린 이후 이미지"></p>
<p>이제 파일을 다 올렸으니 권한을 설정하도록 하겠다. <strong>권한</strong> 탭으로 이동한다.
권한 탭에 들어오면 <code>퍼블릭 엑세스</code>를 허용해줄 수 있다. 편집 버튼을 누르고 허용해준다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/533d9aa0-1e70-4895-97cc-42274db59728/image.png" alt="엑세스 편집 이미지"></p>
<p>편집을 누르면 <strong>모든 퍼블릭 엑세스 차단</strong>의 체크를 해제할 수 있는데, 이를 해제하고 저장한다. 이후 확인을 입력한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/86dc1a55-85a4-4f52-b55f-9bf34e1c77cb/image.png" alt="퍼블릭 엑세스 차단"></p>
<p>이제 위에 <code>액세스 제어 목록</code>을 클릭하고 <strong>퍼블릭 엑세스 권한</strong>을 부여해준다.
퍼블릭 엑세스란에 있는 <strong>Everyone</strong>을 클릭하고 <code>버킷 읽기 권한</code>을 허용한 후 저장해준다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/3af4f87b-b813-4e6f-ae5a-c133b74cad04/image.png" alt="엑세스 권한 부여"></p>
<p>이후 위에 <code>버킷 정책</code> 버튼을 클릭하여 버킷 정책을 적어준다.
버킷 정책은 아래에 있는 <code>정책 생성기</code> 버튼을 통해서 만들어도 상관없지만 문구는 같기 때문에 그냥 복사하는 것을 추천한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/29a17a4e-f83c-4c3e-af89-9f495682fd53/image.png" alt="정책 설정"></p>
<p>해당 정책을 입력하고 자신의 버킷이름에 맞도록 수정한다.</p>
<pre><code>{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;AddPerm&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: &quot;*&quot;,
            &quot;Action&quot;: &quot;s3:GetObject&quot;,
            &quot;Resource&quot;: &quot;arn:aws:s3:::버킷이름/*&quot;
        }
    ]
}</code></pre><p>이후 저장 버튼을 누르고 상단의 <code>속성</code> 탭으로 넘어간다.
<strong>속성</strong> 탭에서 정적 파일을 웹 사이트 호스팅할 수 있도록 변경한다. <strong>정적 웹 사이트 호스팅</strong>을 클릭하고 <code>인덱스 문서</code>와 <code>오류 문서</code>에 <code>index.html</code>을 입력하고 저장한다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/e99adb54-645e-4ed9-9682-e1a28aad6d76/image.png" alt="웹 호스팅"></p>
<p>이러한 과정을 거치면 <code>앤드포인트</code> 라고 적혀있는 링크를 통해 자신이 버킷에 올린 빌드 파일을 정적 웹사이트 호스팅으로 접근할 수 있게 된다.</p>
<p><img src="https://images.velog.io/images/_junukim/post/fa0e00b0-9f77-4066-9b37-127b880145b0/image.png" alt="결과"></p>
<p>이렇게 정적 웹사이트 호스팅을 통해 React앱 빌드 파일을 정적 호스팅 해보았다. 하지만 현재 배포는 불완전함으로 이를 보안적으로 강화하고, 도메인을 달아줘야한다. 다음 포스팅에서 CludeFront와 연결해보도록 하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Jest와 Enzyme로 React Test하기 🤗]]></title>
            <link>https://velog.io/@_junukim/Jest%EC%99%80-Enzyme%EB%A1%9C-React-Test%ED%95%98%EA%B8%B0-9gk5zg6ir5</link>
            <guid>https://velog.io/@_junukim/Jest%EC%99%80-Enzyme%EB%A1%9C-React-Test%ED%95%98%EA%B8%B0-9gk5zg6ir5</guid>
            <pubDate>Wed, 29 Jan 2020 15:22:38 GMT</pubDate>
            <description><![CDATA[<p>처음으로 테스트 코드를 작성해보고 겪은 과정과 느낀점 그리고 소소한 팁들을 적어보려한다.</p>
<h2 id="테스트-한번-해보지-뭐">테스트? 한번 해보지 뭐</h2>
<p><strong>테스트 코드</strong>라.. 오래전 부터 들어왔고 많은 시도를 해왔었다. <a href="https://github.com/junu126/TIL_JS/blob/master/test/What-Is-Test.md">이론적으로 테스트를 공부하고</a> 수 많은 프로젝트에 도입을 해보려 했으나 번번이 실패하였던 기억이 있다. 그리고 사실 오늘 작성한 테스트 코드가 좋은 코드인지도 잘 모르겠다. 모든 것은 처음이 있었기에 끝이 있기 마련이다. 오늘의 도전을 하나의 시발점으로 두고 더욱 공부해야 겠다.</p>
<h2 id="세팅">세팅</h2>
<p>나는 TS를 사용하고 webpack을 직접 세팅하여 React 개발을 하고있다. 그렇기에 <code>CRA</code>를 사용하였을 때 기본적으로 install 되어있는 라이브러리들을 직접 다운받아야했다.</p>
<p>테스트 관련해서 1~2년 전 글은 많았지만 최근 글은 없어서 하는 수 없이 여러 블로그와 사이트에서 정보를 모았다. 그렇게 나는 이와 같은 라이브러리를 install 할 수 있었다.</p>
<h3 id="enzyme">enzyme</h3>
<pre><code>npm i -D enzyme enzyme-adapter-react-16 enzyme-to-json @types/enzyme</code></pre><h3 id="jest">jest</h3>
<pre><code>npm i -D jest ts-jest babel-jest @types/jest</code></pre><h3 id="react-test-renderer">react-test-renderer</h3>
<pre><code>npm i -D react-test-renderer @types/react-test-renderer</code></pre><p>각 라이브러리에 대한 설명은 <a href="%22https://velog.io/@velopert/react-testing%22">velopert님의 리액트 테스트 글에 자세히 설명되어있다.</a></p>
<h3 id="jestconfigjs">jest.config.js</h3>
<p>간단하게 라이브러리를 다운 받고 <code>test setting</code>을 해야한다. 그래서 jest.config.js를 설정하는데 여러 블로그에서 jest의 파일확장자를 <code>js</code>로 설정하였었다. <code>webpack.config.ts</code>나 <code>postcss.config.ts</code>같은 경우는 확장자를 <code>ts</code>로 하여도 오류없이 잘 돌아가서 당연히 <code>jest.config.ts</code>로 두고 세팅을 하였는데 계속 알 수 없는 오류가 발생하였다.</p>
<p>설마 하고 확장자를 <code>js</code>로 바꿔보았는데.. 만들어 둔 세팅이 잘 작동되서 당황했었다. 그러니 확장자를 <code>js</code>로 하자.</p>
<p><code>jest.config.js</code>파일을 생성하고 다음과 같은 코드를 입력해 준다.</p>
<p>jest.config.js</p>
<pre><code>module.exports = {
  globals: {
    &quot;ts-jest&quot;: {
      tsConfig: &quot;tsconfig.json&quot;,
      diagnostics: true
    }
  },
  moduleFileExtensions: [&quot;ts&quot;, &quot;js&quot;, &quot;tsx&quot;, &quot;jsx&quot;],
  moduleNameMapper: {    // 절대 경로
    &quot;^src/(.*)&quot;: &quot;&lt;rootDir&gt;/src/$1&quot;,
        ...
  },
  transformIgnorePatterns: [&quot;./node_modules/&quot;],
  preset: &quot;ts-jest&quot;,
  transform: {
    &quot;^.+\\.(ts|tsx)$&quot;: &quot;ts-jest&quot;
  },
  testMatch: [&quot;**/test/**/*.test.(ts|tsx)&quot;],
  testEnvironment: &quot;node&quot;,
  snapshotSerializers: [&quot;enzyme-to-json/serializer&quot;],
  setupFilesAfterEnv: [&quot;./src/test/setUpTest.ts&quot;]
};</code></pre><p>나는 개발하면서 <code>절대경로</code>를 사용하는데 jest에서 절대 경로를 사용해보려고 하니 조금 애 먹었다. 분명 시키는 대로 하고, 나와있는데로 설정했는데 왜 안될까.. 싶었는데!</p>
<p>현재 위의 코드에서 <code>moduleNameMapper</code>부분이 절대경로를 설정하는 부분이다. 보면 알겠지만 나는 <code>src</code> 디렉토리를 절대경로로 표기했다.</p>
<pre><code>&quot;^src/(.*)&quot;: &quot;&lt;rootDir&gt;/src/$1&quot;</code></pre><p>이와 같이 적혀있는데 <code>&quot;^src/(.*)&quot;</code>에서 <code>^</code>를 절대경로로 사용하는 문자열 구문인 줄 알고 빼고 적었다가 절대 로 설정이 잘 안됬다..</p>
<p>그리고 <code>&quot;&lt;rootDir&gt;/src/$1&quot;</code>에서 <code>&lt;rootDir&gt;</code>를 나의 디렉토리의 root를 적으라는 줄 알고 <code>.</code>을 찍었다가 절대경로 설정이 잘 안되었다.</p>
<p>이 부분 꼭 참고해서 설정할 수 있도록 하자.</p>
<p>혹시 했갈릴 수 있으니 <code>tsconfig.json</code>과 <code>jest.config.js</code>의 절대경로 부분을 사진으로 올려놓았다.</p>
<p><img src="https://images.velog.io/post-images/_junukim/9f682410-42a9-11ea-9c61-43466f0b70df/%EC%BA%A1%EC%B2%98.PNG" alt="캡처.PNG"></p>
<p>이제 마지막으로 <code>package.json</code>의 <code>script</code>탭에다가 실행 명령어를 입력해 준다.</p>
<p>package.json</p>
<pre><code>{
  ...
  &quot;scripts&quot;: {
      ...
    &quot;test&quot;: &quot;jest&quot;
   }
 }</code></pre><p>이렇게 <code>Typescript</code>와 <code>Jest, enzyme</code>를 이용한 Test setting을 마칠 수 있다.</p>
<p>그리고 <code>src/test/**/*.test.(ts|tsx)</code>에 test 파일을 작성할 수 있다.</p>
<h2 id="느낀점과-팁">느낀점과 팁</h2>
<p>나는 하나를 하더라도 내가 할 수 있는 역량 안에서 최대한 완벽하게 만들고 싶어하는 완벽주의자 이다. 그래서 테스트환경을 설정할 때도 최대한으로 설정해보았지만 아무래도 아직 엉성한 부분이 있는 것 같다. 나중에 꼭 시간나면 보완할 것 이다.</p>
<h3 id="팁">팁</h3>
<ul>
<li>jest.config.ts (x) -&gt; jest.config.js (o)</li>
<li><rootDir>을 통째로 넣을 것.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[나만의 React 프로젝트 설계하기😎]]></title>
            <link>https://velog.io/@_junukim/%EB%82%98%EB%A7%8C%EC%9D%98-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%A4%EA%B3%84%ED%95%98%EA%B8%B0-3tk5rs8r52</link>
            <guid>https://velog.io/@_junukim/%EB%82%98%EB%A7%8C%EC%9D%98-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%A4%EA%B3%84%ED%95%98%EA%B8%B0-3tk5rs8r52</guid>
            <pubDate>Fri, 24 Jan 2020 09:07:28 GMT</pubDate>
            <description><![CDATA[<p>최근에 프로젝트 설계에 대해 매우 좋은 평가를 받아서 내가 사용하고 있는 프로젝트 구조를 공개해보면 더 많은 성공을 거두지 않을까 싶어 글을 적는다. 개인적으로 부족한 점이 많다고 생각되는데 한 번 칭찬을 들으니까 욕심이 생겨서 더 많은 평가를 통해 부족한 점을 채워보고 싶다. 🤗</p>
<h1 id="배경">배경</h1>
<p>React를 이용해서 웹을 개발한지 어느덧 2년이 넘어간다. 책을 읽는 것 보단 공식 문서를 통해 공부하는 것을 더 좋아해서 공식문서를 많이 참고하여 공부하였는데 역시 너무 어려웠다. 영어 독해 능력이 떨어질 뿐더러 처음 접하는 프레임워크(프레임워크 처럼 사용할 수 있는 라이브러리)가 너무 어려웠다.</p>
<p>그냥 하라는 대로 하고, 기본적으로 제공해주는 틀을 이용해서 개발하였는데 계속 개발하다보니 이런 생각이 떠올랐다.</p>
<blockquote>
<p><em><strong>&quot;내가 회사에 가서도 CRA를 통해 개발할까? &quot;</strong></em> 🤔</p>
</blockquote>
<p>정답은 아니었다. 약 1년전에 우연한 기회로 <a href="https://banksalad.com/">레이니스트</a>에 견학을 가게됬는데 이때 궁금해서 웹 팀장님께 물어봤었다. 정말 직설적으로 물어봤었는데, 지금 생각해보면 정말 당연한 대답이다.😂 (<del>이불킥 엄청 했다</del>)</p>
<p>그래서 이 이후로 <code>webpack</code>을 공부하기 시작했고 React 프로젝트 기초 설정부터 폴더구조까지 직접 만들어보게되었다. <em><strong>(나는 내 프로젝트 구조가 한참 부족하고 보완 해야할 점이 많다고 생각하기 때문에 계속해서 보완하려고 노력하고 있다.)</strong></em></p>
<h2 id="디자인-패턴과-아키텍처">디자인 패턴과 아키텍처</h2>
<p>나는 React에서 상태관리를 위해 <code>Redux</code>를 사용한다. 주위에서 <code>ContextApi</code>나 <code>MobX</code>를 추천해주기도 하였지만 내가 생각하는 이상적인 코드의 깔끔함이 Redux와 가장 잘 맞는 것 같아서 Redux를 사용하고 있다. 때문에 <code>Flux</code>패턴을 사용하게 되는데 나는 여기에 아키텍처를 입혀보았다.</p>
<p>아키텍처 중 <a href="https://app.gitbook.com/@junukim-dev-1/s/clean-architecture/the_clean_architecture"><code>Clean Architecture</code>를 공부</a>하고 아키텍처에 대한 지식을 차근차근 쌓아가다가 계속 공부만 하고 적용을 안 해보다 보니 내가 정확하게 이해하고 있는지도 궁금했고, 공부만 해선 계속 지체될 것 같아서 과감하게 도전해보았다.</p>
<h3 id="실패">실패</h3>
<p>막연하게 도전했지만 React프로젝트에 Clean Architecture를 적용하는 것은 내 생각만큼 쉽지 않았다. 가장 큰 문제는 Redux가 있는데 어떻게 프로젝트 구조를 설계 해야하는지가 어려웠다.</p>
<p>그래서 나는 외부의 도움을 얻기로 하였다. 나는 Github에 떠돌고 있는 여러 <a href="https://github.com/eduardomoroni/react-clean-architecture">예제</a>들을 참고해보았다. 그 중 모티브를 삼아 설계했던 구조가 해당 링크이다.</p>
<p><img src="https://images.velog.io/post-images/_junukim/1a48eae0-3e7a-11ea-a574-958a9218937f/%EC%BA%A1%EC%B2%98.PNG" alt="캡처.PNG">위 사진은 모티브로 했던 폴더 구조인데 보이는 것 처럼 <code>module</code>들도 따로 분리하여 새로운 package를 형성하는 것을 볼 수 있다. 처음에는 이와 같은 방법으로 진행을 해보려고 많은 삽질을 해보았는데 개인적으로 선호하는 스타일이 아니어서 다른 방향으로 고개를 돌렸다.</p>
<p>이후에도 많은 시도를 하였다. <code>android의 Clean Architecture</code>처럼 구조를 잡아보기도 하였고 <code>redux를 제외</code>시키고 구조를 설계해보기도 하였다. 또 <code>TS말고 Javascript</code>를 이용해서도 해보았는데.. 역시 힘들었다. 많은 시도와 삽질을 해본 끝에 결단을 내린 폴더구조는 애매모호 했다.</p>
<h2 id="프로젝트-설계">프로젝트 설계</h2>
<p>Clean Architecture를 완전 사용하지 않고 어느정도만 <code>copy</code>한다는 느낌으로 설계하였다. 그리고 Redux의 데이터 흐름을 어떻게 하면 유연하게 흘러가게할 수 있을까, 의존성을 어떻게 하면 더 줄일 수 있을까 열심히 생각하면서 설계하였다.</p>
<pre><code>┌── .vscode                    - vscode setting
├── node_modules
├── public/                    - favicon, html
├── src/
│   ├── @types/                          - typescript date type 정의
│   │    └── index.d.ts
│   │
│   ├── assets/                          - assets 폴더
│   ├── components/                     - 컴포넌트 폴더 (views)
│   │   └── componentName/                          - index.ts를 정의
│   │         └── style/                            - 컴포넌트 별 style
│   ├── container/                      - 컨테이너 폴더 (presenters)
│   │   └── containerName/                          - custom hook을 통한 상태관리
│   │         └── presenter/                        - 해당 container에서 사용되는 presenter
│   ├── data/                              - redux 폴더 (use Cases &amp; entities)
│   │   ├── actions/                               - 액션 정의
│   │   ├── middleware/                                   - 미들웨어 정의
│   │   │    ├── api/
│   │   │    │    ├── apiTypes.ts
│   │   │    │    ├── baseUrl.ts
│   │   │    │    └── index.ts
│   │   │    │
│   │   │    └── sagas/                         - 사가 정의
│   │   │
│   │   └── reducers/                          - 리듀서 정의
│   │ 
│   ├── page/                             - 라우터 정의 폴더
│   │   └── App.tsx
│   │ 
│   ├── styles/                           - 글로벌 스타일 폴더
│   │   └── globalStyle.ts
│   │ 
│   └── utils/                            - 유틸 폴더
│       └── util.ts
│
├── package.json
├── .babelrc
├── .env
├── postcss.config.ts
├── tsconfig.json
├── tslint.json
└── webpack.config.ts</code></pre><h2 id="기술-스택">기술 스택</h2>
<p>프로젝트를 설계하면서 사용하는 기술에 따라 구조를 조금씩 변경하였다. 물론 라이브러리에 의존적이 않도록 나만의 규칙을 세우고 개발한다. 😏</p>
<p>기본적으로 <code>React + Redux + @middleware</code>를 사용하고, middleware는 <code>redux-saga</code>를 사용한다.
스타일링에선 <code>styled-components</code>를 사용하고,
HTTP 통신에서 <code>axios</code>를 사용한다.</p>
<p>또 <code>post-css</code>와 <code>webpack + babel</code>로 기본적인 앱 세팅을 하고있고, <code>Typescript</code>를 사용하여 개발한다.</p>
<h2 id="결론-및-고찰">결론 및 고찰</h2>
<p>위 프로젝트 구조가 내가 직접 설계하고 고안한 구조이다. 지금 이렇게 글을 적으면서 다시 돌아보니 많이 허접하고 부족한 점이 눈에 보이는 것 같다. 직접 프로젝트 구조를 설계하면서 데이터의 흐름이나 방향에 대해 많이 고민하게 되고 의존성 주입에 대해 많이 생각하게 되는 것 같다.</p>
<p>해당 프로젝트 구조를 만들기 까지 여러 프로젝트를 경험하였다.</p>
<p>처음에는 구글링을 하다가 언뜻 본 폴더구조에서 style폴더를 <code>src/</code>위치에 설계한 것 보고 따라해보았는데 <code>styled-components</code>를 사용해서 스타일링을 하다보니 styled-component의 네이밍이 겹치는 부분이 많아서 재활용 하기 힘든 이름을 정하게 되었다. 그러다가 <a href="https://velog.io/@velopert">velopert</a>님이 발표하신 자료를 우연하게 접하게 되었는데 나와 같은 고민을 하셨어서 좋은 해답을 찾을 수 있었다.</p>
<p>그리고 프로젝트 구조를 새우기전에는 container를 component의 구분을 짓는 용도로 사용하고 component의 모든 데이터를 관리하도록 하였는데 <a href="https://github.com/reduxjs/redux/tree/master/examples">redux example</a>를 참고하여 view는 모두 compoennt로 이동시키고 container를 presenter처럼 사용하게 되었다.</p>
<p><code>webpack</code>에 대한 이해도도 많이 부족하고, 아키텍처나 디자인 패턴에 대한 이해도가 많이 부족한 상황에서 나만의 React 프로젝트를 설계하는 과정은 쉽지 만은 않았다. 하지만 어려운 과정을 거치고 나니 많은 배움을 얻을 수 있었다. 직접 프로젝트를 설계한다는 경험을 통해 좀 더 깊은 생각을 할 수 있는 기회였다.</p>
<hr>
<p>처음 작성하는 블로그 글이라서 필력이 많이 부족합니다. 많은 조언 부탁드립니다.😎</p>
]]></description>
        </item>
    </channel>
</rss>