<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>float_letter.log</title>
        <link>https://velog.io/</link>
        <description>타입스크립트러버</description>
        <lastBuildDate>Sun, 24 Jan 2021 09:19:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>float_letter.log</title>
            <url>https://images.velog.io/profiles/float_letter/thumbnails/1541947347.902.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. float_letter.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/float_letter" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[내가 reactjs 를 vuejs보다 선호하는 이유]]></title>
            <link>https://velog.io/@float_letter/%EB%82%B4%EA%B0%80-reactjs-%EB%A5%BC-vuejs%EB%B3%B4%EB%8B%A4-%EC%84%A0%ED%98%B8%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@float_letter/%EB%82%B4%EA%B0%80-reactjs-%EB%A5%BC-vuejs%EB%B3%B4%EB%8B%A4-%EC%84%A0%ED%98%B8%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Sun, 24 Jan 2021 09:19:54 GMT</pubDate>
            <description><![CDATA[<p>필자는 vuejs를 2버전 까지 사용해 보았고 angular는 1.5버전까지 사용해보았으며
현재 주로 사용하고 있는 reactjs는 typescript와 함께 사용하고 있다.
angular는 2이후 버전에 대해서 구글에 배신감(?)을 느끼고 사용하지는 않지만 vuejs를 쓰면서 angularjs의 장점을 이식했다는 말을 어느정도 이해할 수 있었다.</p>
<p>vuejs를 쓰면서 일단 가장 좋은 점은 반응형시스템의 상태변경이 object.defineProperty를 사용한 setter, getter로 상태변경 추적 인터페이스를 숨겼기 때문에 상당히 직관적이고 간편하다는 점이다.
react처럼 비동기 api setState를 사용하면서 컴포넌트간 상태관리에 대해서 고민이 적다는점이 초보자에게 확실히 러닝커브가 낮아서 좋다는 점도 있다.
또한 기존 html,css,js문법을 그대로 써도 되기때문에 팀원들의 학습러닝커브가 낮을 수 밖에 없다는 점이 도입하기도 쉽다.
게다가 좀더 디테일하게 들어가면 angular1을 차용한것이 많이 보였기때문에 개인적으로는 이런 비슷한 요소들도 사용하기 편했다.</p>
<p>그럼에도 불구하고 vuejs를 쓰고자할때 생태계 크기를 제외하고 편의성으로 꺼릴 수 밖에 없는 이유들이 있다.</p>
<h2 id="typescript-tsx">Typescript! TSX!</h2>
<p>vuejs에서 typescript지원이 잘된다고 누군가 그러지만 언어레벨에서 tsx포맷을 지원하는것과 vue포맷을 지원하지않는것은 차이가 있을 수 밖에 없다.
당장 vuejs에서 typescript가 잘된다고 하더라도 ide에서 언어자체를 지원하는 레벨과는 차이가 날 수 밖에 없다. 아이러니하게도 이 부분은 angular2 이후도 마찬가지라 html에서 angular-component를 ide가 인식하고 읽어들이려면 별도의 angular-plugin을 받아야 하지만 tsx는 언어레벨에서 지원하기 때문에 ide가 ts를 지원한다면 react는 그럴필요가 없다.
vuejs도 tsx를 쓸수있다고는 하지만 여러 방법중에 하나일뿐이고 사람들이 주로 쓰는 best practice가 아니다. 게다가 tsx를 쓸거면 리액트를 쓰지 vue를 쓸 이유가 없기도 하다.
그런데 react는 @types를 받아야함에도 불구하고 typescript가 jsx/tsx포맷을 지원하기 때문에 아이러니하게도 typescript가 제일 잘 어울리는 라이브러리다.</p>
<h2 id="mixin-vs-hook">Mixin vs Hook</h2>
<p>정말 hook을 만든 사람은 어떤 발상이었을지는 모르지만 정말 완벽하다고 생각하고 있다.
hook은 class에서의 mixin이나 상속에서 다중상속의 문제를 깔끔하게 날려버린 완벽한 재사용방식이다.
괜히 vuejs3.0부터 리액트를 따라 hook을 도입하는게 아니라는 생각이 들었다.</p>
<p>vuejs에서 컴포넌트의 기능을 재사용하기 위해서 mixin을 사용할때 mixin간의 메소드가 충돌할 수 있는 문제는 개발자의 인지에서 캡슐화를 깨뜨릴수 있는 문제가 있다.
하지만 hook은 그럴 걱정이 없다. 만약 두개의 같은 hook을 사용하고 hook내부의 구현에 대해서 신경쓰지 않아도 호출부에서 인터페이스를 변경할 수 있기 때문에 내부 구현에서 무엇을 호출하든 신경쓸 요소가 매우적다. </p>
<pre><code class="language-tsx">const useCount = () =&gt; {
  const [count, setCount] = useState(0);  
  const addCount = () =&gt; {
    setCount(count + 1);
  }
  return [count, addCount];
}

// 두개의 카운트를 사용하는 컴포넌트
const MyComp = () =&gt; {
  // 호출부에서 이름을 변경했다.
  const [count1, addCount1] = useCount();
  const [count2, addCount2] = useCount();
  return ...;
}
</code></pre>
<h2 id="event-handling방식">Event Handling방식</h2>
<p>vuejs를 사용하면서 가장 이해할 수 없는게 어째서 상위컴포넌트 커스텀 이벤트 핸들링 방식으로 emit방식을 best practice로 차용했는지이다.
props에 function을 넣어서 인터페이스를 명확하게 하면 type hinting도 좋아지고 해당 컴포넌트를 사용하는 개발자가 문서를 뒤지거나 코드를 뒤질 필요없이 해당 코드의 인터페이스를 파악할 수 있는데 이 부분에서 굳이 캡슐화를 깨는 방식으로 best practice를 정해놨다는 점이다.</p>
<p>vue의 emit방식을 angular의 것을 차용한것은 잘못된것을 차용한게 아닌가 싶다. 분명히 단편적으로 봤을때는 좋다라고 생각할 수 도 있지만 vue-ts의 ide지원을 약하게 만드는 요소들중 하나이다.
컴포넌트를 정의할때 인터페이스에서 emit할 요소들을 정의하는게 아니라 emit을 하위 컴포넌트에서 호출하는게 곧 인터페이스이기 때문에 컴포넌트 사용자는 코드를 뒤지던가 문서를 볼 수 밖에 없다.
간단하게 함수의 parameter처럼 모든것을 props로 전달하도록 하는게 best-practice로 두지 않는 이유가 무엇인지는 구현상 성능문제때문일지는 비교해보지는 않았지만 이 부분이 정말 아쉬웠다.</p>
<h2 id="slot">Slot</h2>
<p>이 부분은 angularjs의 transclude를 차용했지만 별로 좋다고 생각하지 않는다.
분명히 하위 돔을 주입할때 그 요소들을 flat하게 주입할수 있다는 점이 장점이지만 이 부분은 props로만 주입하게 해도 충분하지 않았나싶다. 
컴포넌트,dom요소를 props와 분리하게 하고자함이 의도였을수는 있지만 slot도 vue의 ide지원을 어렵게 만드는 요소중 하나이다.
ts로 만들어져 있고 이런 컴포넌트를 주입하게 하면서 커스텀할 수 있는 여지를 열어 놓은 react의 잘 정의된 컴포넌트들은 있을법한 인터페이스의 단어만 잘 떠올려서 props를 적어도 무엇을 입력해야하는지 문서를 가지않고도 알 수 있으면서 직관적인 부분들이 굉장히 많지만 vuejs의 slot은 문서나 코드를 보지않고는 알 수 가없다. </p>
<h2 id="마치며">마치며..</h2>
<p>vuejs만 하던분들에 비하면 깊이가 얕아 잘모르는 부분도 있어서 어그로를 끌었을 수 있다고 생각하지만 
지극히 개인적인 편의성에 대한 비교로 reactjs를 더 선호하는 이유를 적었다.</p>
<p>이번 vue의 3.0이 어떤지는 아직 둘러보지는 않았지만 react의 hook방식을 차용한다고 하니 다음에 사용할때는 이 부분의 개선이 잘 일어났으면 좋겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux 대신에 Rematch!]]></title>
            <link>https://velog.io/@float_letter/Redux-%EB%8C%80%EC%8B%A0%EC%97%90-Rematch-u2jtwp1iqk</link>
            <guid>https://velog.io/@float_letter/Redux-%EB%8C%80%EC%8B%A0%EC%97%90-Rematch-u2jtwp1iqk</guid>
            <pubDate>Sun, 31 Mar 2019 09:12:51 GMT</pubDate>
            <description><![CDATA[<h2 id="시작하기에-앞서">시작하기에 앞서</h2>
<p>Redux와 Rematch를 소개하기에 앞서
먼저 간략하게 redux에 대한 설명을 하고 넘어가겠습니다.</p>
<h3 id="redux란">Redux란?</h3>
<p>redux에 대한 한글 소개문서에서는 자바스크립트앱을 위한 예측가능한 상태 컨테이너라고 소개합니다.</p>
<p>좀더 설명하자면 flux 아키텍쳐 구조를 가진 상태관리 라이브러리로 모든상태저장소를 중앙집중형식으로 관리하는 라이브러리라고 생각하면 됩니다.</p>
<p>그리고 해당 상태를 변경하기 위해서는 직접 해당상태를 조회하고 변경하는것이 아니라 action이라는 객체를 store에 dispatch시켜야하고 특정상태를 변경처리할 함수 reducer를 정의해야 가능합니다.</p>
<p>reducer라는 개념은 저도 처음에는 혼란스러웠는데요.</p>
<p>간단하게 event와 eventHandler라고 생각하시면 편할듯싶습니다.</p>
<p>reducer의 구성 조건은 순수 함수형이어야 하고 새로운 상태로 변경이되면 이전상태를 그대로 반환하는 대신에 상태를 복제하여 변경된 상태를 반환해야 합니다.</p>
<p>즉 이전 상태를 변경하는 행위는 하지말아야합니다.</p>
<pre><code class="language-javascript">function counter(state = 0, action) {
  switch (action.type) {
    case &quot;INCREMENT&quot;:
      return state + 1;
    case &quot;DECREMENT&quot;:
      return state - 1;
    default:
      return state;
  }
}</code></pre>
<p>counter리듀서가 처리할수있는 액션이 없다면 현재상태는 변경되지않고 그대로 반환되지만 변경이 된다면 변경된 상태를 반환합니다.</p>
<p>현재상태에서 새로운상태복제를 하지않는건 js number는 값객체이기 때문입니다.</p>
<h2 id="redux의-난해함">redux의 난해함</h2>
<p>redux는 이런식으로 상태관리를 하고있지만 초보자가 보기에는 난해합니다.
비슷한 객체지향 패턴인 command pattern도 잘사용하지않는사람이 많기떄문이죠</p>
<p>간단하게 counter앱을 정의해봅시다.</p>
<pre><code class="language-js">import { createStore } from &quot;redux&quot;;

// 액션타입을 정의하고

const INCREMENT = &quot;INCREMENT&quot;;
const DECEREMENT = &quot;DECREMENT&quot;;

///액션생성자를 만들어주고
const createIncrementAction = () =&gt; {
  return {
    type: INCREMENT
  };
};
const createDecrementAction = () =&gt; {
  return {
    type: DECREMENT
  };
};

// 이것을 처리할 reducer를 만듭시다.
function counter(state = 0, action) {
  switch (action.type) {
    case INCREMENT:
      return state + 1;
    case DECREMENT:
      return state - 1;
    default:
      return state;
  }
}

const store = createStore(counter);

sotre.subscribe(() =&gt; {
  console.log(store.getState());
});

store.dispatch(createIncrementAction()); //혹은
store.dispatch({ type: &quot;INCREMENT&quot; });
store.dispatch(createDecrementAction()); //혹은
store.dispatch({ type: &quot;DECREMENT&quot; });</code></pre>
<p>상태를 변경하는 조건은 액션이라고 하는 객체를 store에 dispatch해야합니다.
고작 counter 상태하나 변경하는데 거추장스러운 코드가 굉장히 많아지게됩니다.
이렇게 하는데에는 강력한 장점이 있기때문에 그렇습니다.</p>
<ol>
<li>확장성</li>
<li>모든 액션을 기록</li>
<li>시간여행디버깅가능</li>
</ol>
<p>그렇다고해도 함수형의 장점인 소프트웨어의 결합도가 낮은건 좋지만
응집도가 낮은것은 난해함을 극복하는데 있어서 큰 도움이 되지 않습니다.</p>
<p>redux커뮤니티중에서는 이런점을 극복하기 위한 방법으로 duck패턴을 사용하기를 권하고 있습니다.</p>
<p><a href="https://github.com/erikras/ducks-modular-redux">https://github.com/JisuPark/ducks-modular-redux</a></p>
<p>하지만 이런 패턴으로 구현하는 대신에 개인적으로 rematch라고하는 framework를 사용하기를 권장합니다.</p>
<h2 id="rematch는-또-뭔데">Rematch는 또 뭔데?</h2>
<p><a href="https://github.com/rematch/rematch">Rematch</a></p>
<p>소개문서를 설명하면</p>
<p>rematch는 redux의 보일러플레이트없는 best pratice입니다.</p>
<p>redux의 action type, action creator, switch문과 비동기처리를 하기위한 별도의 라이브러리인 thunk가 더이상 필요하지 않습니다.</p>
<p>간단하게 rematch소개페이지의 counter를 보면</p>
<h3 id="indexjs">index.js</h3>
<pre><code class="language-javascript">import { init } from &quot;@rematch/core&quot;;
import * as models from &quot;./models&quot;;

const store = init({
  models
});

export default store;</code></pre>
<h3 id="storejs">store.js</h3>
<pre><code class="language-javascript">export const count = {
  state: 0,
  reducers: {
    increment(state, payload) {
      return state + payload;
    }
  },
  effects: dispatch =&gt; ({
    async incrementAsync(payload, rootState) {
      await new Promise(resolve =&gt; setTimeout(resolve, 1000));
      dispatch.count.increment(payload);
    }
  })
};</code></pre>
<h3 id="dispatch">dispatch</h3>
<pre><code class="language-javascript">// reducers
store.dispatch({ type: &quot;count/increment&quot;, payload: 1 }); // state = { count: 1 }
store.dispatch.count.increment(1); // state = { count: 2 }

// effects
store.dispatch({ type: &quot;count/incrementAsync&quot;, payload: 1 }); // state = { count: 3 } after delay
store.dispatch.count.incrementAsync(1);</code></pre>
<p>보시다시피 직접 액션타입문자열을 정의할필요없이 모델의 이름과 리듀서 함수의 이름으로 actionType까지 프레임워크가 정의해주고 그것을 생성하기 위한 actionCreator까지 정의할필요가 사라졌습니다.
redux-thunk같은 비동기처리를 위해 붙이던 라이브러리도 필요없이 effects에서 정의하는것만으로 손쉽게 비동기액션도 붙일수있게 되었습니다.</p>
<p>게다가 typescript에서도 mapState, mapDispatch에 사용할 dispatch와 rootState의 타입을 정의하기 굉장히 간편합니다.
더군다나 dispatch에 정의되는 메소드에서도 엄격하지는 않지만 정의한 reducer의 정보를 토대로 타입정보를 알려줄수있습니다.</p>
<pre><code class="language-typescript">import { init, RematchRootState } from &quot;@rematch/core&quot;;
import * as models from &quot;./models&quot;;

export const store = init({
  models,
});

export type Store = typeof store;
export type Dispatch = typeof store.dispatch;
export type iRootState = RematchRootState&lt;typeof models&gt;;
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>이제 매번 ducks패턴에 맞춰서 구현하는 대신에 프레임워크가 제공해주는 틀대로 개발해보는건 어떨까요?</p>
<p>보일러플레이트코드를 매번 작성하는 피곤함에서 벗어나실수 있을겁니다.</p>
<blockquote>
<p><a href="https://github.com/rematch/rematch/blob/master/docs/purpose.md">redux &amp; rematch comparison</a>
<a href="https://hackernoon.com/redesigning-redux-b2baee8b8a38">why we created rematch</a></p>
</blockquote>
<blockquote>
<p>본포스트는 <a href="https://tigerwest.github.io/blog/2019/03/31/1554012373/">저의 블로그</a>에서 쓴 글을 재구성한 글입니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docz로 컴포넌트 문서화를 쉽게 해보자]]></title>
            <link>https://velog.io/@float_letter/2018-12-19-0012-%EC%9E%91%EC%84%B1%EB%90%A8-yjjptvo4j6</link>
            <guid>https://velog.io/@float_letter/2018-12-19-0012-%EC%9E%91%EC%84%B1%EB%90%A8-yjjptvo4j6</guid>
            <pubDate>Tue, 18 Dec 2018 15:13:44 GMT</pubDate>
            <description><![CDATA[<p>이보다 더 쉬울 수 없는 문서생성 라이브러리!</p>
<p>컴포넌트 문서화툴에 관해 관심을 가졌기 때문에 storybook을 써보려다가</p>
<p>typescript설정과 함께 쓰려면 여러가지 플러그인을 덕지덕지 붙이고 깔끔하지도 않기에 포기했었다.</p>
<p>최근 github trend들을 하나씩 둘러보던중에 맘에 쏙드는 라이브러리를 하나 발견했기에 포스팅하기로 했다.</p>
<h2 id="docz란-무엇인가">Docz란 무엇인가?</h2>
<p>docz는 복잡한 설정을 할 필요없는 프론트엔드를 위한 문서생성기다.</p>
<p>날이 가면 갈수록 스타일 가이드라인과 디자인체계는 빠르게 성장하고 있지만</p>
<p>프론트엔드는 불필요하게 복잡한 설정과 절차로 우리를 괴롭히고 있다.</p>
<p>docz의 등장은 이런 괴로움을 한번에 날려줄 라이브러리중 하나이다.</p>
<p>md파일을 넘어 mdx(md + jsx)라는 독자적인 형식을 쓰는데 React사용자라면 이해하는데 전혀 문제없다.</p>
<p>docz에서 문서끼리는 의존하지 않고 각문서가 각컴포넌트에 의존하는 형식이다.</p>
<p>빌드할때는 각각의 mdx문서들을 찾아내 빌드하게된다..</p>
<p>기존프로젝트에도 쉽게 적용할 수 있다.</p>
<p>백마디 말보다 실천이 우선이다.</p>
<p>기본프로젝트가 리액트라는 가정하에 진행한다.</p>
<p>설치를 먼저해보자!</p>
<pre><code class="language-bash">yarn add docz docz-theme-default -D</code></pre>
<p>docz코어 라이브러리와 docz의 기본theme을 우선 설치한다.</p>
<p>그후 간단한 버튼을 하나 만들어보자</p>
<pre><code class="language-typescript">import React from &quot;react&quot;;

export default (props) =&gt; {
  return &lt;button&gt;{props.children}&lt;/button&gt;
}</code></pre>
<p>그리고 button.mdx파일을 하나 만들고 다음과 같이 작성하고 다음 커맨드로 실행해보자</p>
<pre><code class="language-typescript">---
name: Button
---

import { Playground, PropsTable } from &#39;docz&#39;
import Button from &#39;./&#39;

# Button

## Basic usage

&lt;Playground&gt;
  &lt;Button&gt;Click me&lt;/Button&gt;
&lt;/Playground&gt;
</code></pre>
<pre><code class="language-bash">yarn docz dev
</code></pre>
<p>localhost:3000에 들어가보면  왼쪽 navigation에 Button이보인다. </p>
<p><img src="https://images.velog.io/post-images/float_letter/0801bfa0-02d6-11e9-9258-030c47fee7d4/page-not-found.png" alt="page-not-found.png"></p>
<p>클릭해보면 </p>
<p><img src="https://images.velog.io/post-images/float_letter/09dc4c00-02d6-11e9-9258-030c47fee7d4/2.button.png" alt="2.button.png"></p>
<p>짜잔! 깔끔한 디자인의 버튼에 대한 기본문서가 아주 손쉽게 생성이 되었다.</p>
<p>playground에는 우리가 정의한 버튼이 들어있고 상호작용할 수 있다! </p>
<p>하지만 현재의 버튼은 심심하니 props로 다른 속성을 주입받을 수 있게 수정해보자.</p>
<pre><code class="language-typescript">//button.mdx
&lt;Playground&gt;
  &lt;Button&gt;Click me&lt;/Button&gt;
  &lt;Button kind=&quot;test&quot;&gt;Click me&lt;/Button&gt;
&lt;/Playground&gt;
</code></pre>
<pre><code class="language-typescript">import React from &quot;react&quot;;

export default ({children, kind}) =&gt; {
  return &lt;button&gt;{kind}{children}&lt;/button&gt;
}</code></pre>
<p><img src="https://images.velog.io/post-images/float_letter/0b5d94d0-02d6-11e9-9258-030c47fee7d4/3.button.png" alt="3.button.png"></p>
<p>문서에서 컴포넌트를 사용한 코드에 맞게 렌더링이 되는 모습을 볼 수 가 있다.</p>
<h2 id="소개페이지-작성">소개페이지 작성</h2>
<p>맨처음 page not found가 거슬렸기에 소개페이지를 작성하는 법을 보자.</p>
<p>기본적으로 docz의 각 문서의 url경로는 파일경로를 hypen으로 연결한 형태이다.</p>
<p>src/button.mdx &gt; localhost:3000/src-button</p>
<p>route를 루트로 명시해주면 맨처음 페이지는 이 문서가 된다.</p>
<pre><code class="language-typescript">/// index.mdx
---
name: Design guide
route: /
---

# Getting Started

- **It’s consistent**. The way components are built and managed follows a predictable pattern.
- **It’s self-contained**. Your design system is treated as a standalone dependency.
- **It’s reusable**. You’ve built components so they can be reused in many contexts.
- **It’s accessible**. Applications built with your design system are usable by as many people as possible, no matter how they access the web.
- **It’s robust**. No matter the product or platform to which your design system is applied, it should perform with grace and minimal bugs.</code></pre>
<p><img src="https://images.velog.io/post-images/float_letter/0c974d50-02d6-11e9-9258-030c47fee7d4/4.indexmdx.png" alt="4.indexmdx.png"></p>
<h2 id="typescript-적용">Typescript 적용</h2>
<p>docz에서 타입스크립트를 적용하는 방법은 아주 쉽다.</p>
<p>다음 파일만 추가해주고 재시작해보자.</p>
<pre><code class="language-typescript">// doczrc.js
module.exports = {
  title: &#39;Docz Typescript&#39;,
  typescript: true,
}</code></pre>
<p>다음과 같이 typescript설정을 하겠다는 값만 주면 끝이다.</p>
<p>title은 문서의 제목이다.</p>
<p>당장 결과물에는 별차이가 없지만 button.mdx에</p>
<p>PropsTable을 추가로 import하고 Button을 집어넣어보고 </p>
<p>버튼컴포넌트의 형식을 index.jsx에서 index.tsx로 변경해보자</p>
<pre><code class="language-typescript">---
name: Button
---

import { Playground, PropsTable } from &#39;docz&#39;
import {Button} from &#39;../&#39;

# Button

&lt;PropsTable of={Button} /&gt;

## Basic usage
&lt;Playground&gt;
  &lt;Button&gt;Click me&lt;/Button&gt;
  &lt;Button kind=&quot;test&quot;&gt;Click me&lt;/Button&gt;
&lt;/Playground&gt;</code></pre>
<p><img src="https://images.velog.io/post-images/float_letter/0ddf36a0-02d6-11e9-9258-030c47fee7d4/5.button.png" alt="5.button.png"></p>
<p>자 어떤가?</p>
<p>버튼에 대한 propstable이 자동으로 생성되었다!</p>
<p>docz는 typescript를 인식해줄뿐만 아니라 props의 정보를 추출하여 table에 띄워주기까지 한다.</p>
<p>즉 interface를 두번선언할필요가 없다는 의미이다</p>
<p>type정보를 한번 변경했을때 어떻게 반영되는지 확인해보자.</p>
<pre><code class="language-typescript">import * as React from &quot;react&quot;;

export const Button: React.SFC&lt;{kind: number}&gt;= ({children, kind}) =&gt; {
  return &lt;button&gt;{kind}{children}&lt;/button&gt;;
};</code></pre>
<p>kind를 number로 받는다는 타입이 정해졌다. </p>
<p>mdx도 그에 맞게 수정해주자</p>
<pre><code class="language-typescript">&lt;Playground&gt;
  &lt;Button&gt;Click me&lt;/Button&gt;
  &lt;Button kind={1}&gt;Click me&lt;/Button&gt;
&lt;/Playground&gt;</code></pre>
<p><img src="https://images.velog.io/post-images/float_letter/0f6ed750-02d6-11e9-9258-030c47fee7d4/6button.png" alt="6button.png"></p>
<p>kind가 number로 들어온다는 사실이 명확해졌을 뿐만 아니라 propsTable에도 정확하게 나오게되었다.</p>
<h2 id="conclusion">Conclusion</h2>
<p>지금까지 docz를 사용하여 간단하게 컴포넌트를 문서화해보았다.</p>
<p>docz를 사용했을때의 장점으로는 디자이너와의 협업에서는 디자인 인터페이스에 대한 명세를 용이하게 하는것뿐만 아니라 동료 개발자와의 협업에 있어서도 컴포넌트의 인터페이스에 대해서 조금더 신경쓸수 있게 된다는 장점이 뚜렷하다.</p>
<p>단점으로는 아직 나온지 얼마안된 신생프로젝트라는것이고
사용하다보면 가끔씩 에러가 터지거나
theme객체를 받는 props를 정의하거나 hoc props를 받는다고 정의하게 되면 propstable은 모든 기본 props정보까지 들어오기때문에 쓸모가 없어진다는점등이 있다.</p>
<p>하지만 확실히 zero config bundle tool인 parcel같은 번들러처럼 docz도 zero config documenting tool로써 대세가 되지않을까 싶다.</p>
<blockquote>
<p><a href="https://www.docz.site/">Docz 공식사이트 링크</a></p>
</blockquote>
<blockquote>
<p>본 포스트는 <a href="https://tigerwest.github.io/blog/2018/12/18/1545144225/">제 블로그</a>의 포스트를 재구성한 내용입니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[jest-image-snapshot을 활용한 디자인 검수자동화를 해보자]]></title>
            <link>https://velog.io/@float_letter/2018-11-24-1711-%EC%9E%91%EC%84%B1%EB%90%A8-s0jov65k42</link>
            <guid>https://velog.io/@float_letter/2018-11-24-1711-%EC%9E%91%EC%84%B1%EB%90%A8-s0jov65k42</guid>
            <pubDate>Sat, 24 Nov 2018 09:40:42 GMT</pubDate>
            <description><![CDATA[<p>회사를 옮기고 나서 </p>
<p>프론트엔드개발자로서의 기본이 되야할</p>
<p>웹디자인에 맞춰서 페이지를 그려내는 작업을 하게됐다.</p>
<p>디자인에 맞춰서 css를 그리는것이 생각보다 어려울뿐만 아니라 </p>
<p>기기종별 내장폰트유무로 달라지는 폰트차이등 신경써야할것이 생각보다 많았다.</p>
<p>특히 인라인요소는 사람을 미치게 한다.</p>
<p>완성되고나면 디자이너분이 꼼꼼하게 검수를 해주시지만.....</p>
<p><img src="https://images.velog.io/post-images/float_letter/9951d870-efbf-11e8-b796-2db1515599f9/2603E750589594DF10-1.jpg" alt="2603E750589594DF10 (1).jpg">
 (용의눈으로... 아 아닙니다..)</p>
<p>검수하는 시간도 꽤나 걸릴뿐만 아니라</p>
<p>특히 틀린그림찾기에도 미숙한 나 때문에 디자이너분의 시간이 뺏긴다는 사실에 부끄러워졌다.</p>
<p>게다가 검수하고 수정사항요청받을때 마다 왠지 나의 얼굴이 붉혀짐은 덤...</p>
<p>적어도 이 부분은 적은코드로 자동화할 수 있는 방법이 있지 않을까 싶어서 관련된 라이브러리를 찾아보았다. </p>
<p>그리고... 찾아냈다.</p>
<p>이것을 진행하려면 여러개의 라이브러리가 필요하다.</p>
<p>필자는 타입스크립트 러버로서 타입스크립트 기준으로 진행할것이다.</p>
<pre><code class="language-bash">yarn add jest ts-jest typescript puppeteer jest-image-snapshot @types/jest @types/jest-image-snapshot @types/puppeteer -D</code></pre>
<pre><code class="language-bash">yarn tsc --init
yarn ts-jest config:init
</code></pre>
<pre><code class="language-json">
//tsconfig.json
{
  &quot;compilerOptions&quot;: {
    /* Basic Options */
    &quot;target&quot;: &quot;es6&quot;,   
    // ....
}</code></pre>
<p>tsconfig의 target은 es6로 진행해야한다.</p>
<p>그리고 별도의 테스트폴더에서 테스트코드로 기본설정을 작성해보자</p>
<pre><code class="language-typescript">/// inspection.test.ts

import {Browser, Page, launch} from &#39;puppeteer&#39;;
import {toMatchImageSnapshot} from &#39;jest-image-snapshot&#39;;

expect.extends({toMatchImageSnapshot});

describe(&#39;some page&#39;,() =&gt; {
  let browser: Browser;
  let page: Page;
  beforeAll(async done =&gt; {
    browser = await launch();
    done();
  });
  beforeEach(async done =&gt; {
    page = await browser.newPage();
    done();
  });
  afterEach(async done =&gt; {
    await page.close();
    done();
  });
  afterAll(async done =&gt; {
    await browser.close();
    browser = null;
    done();
  });
});</code></pre>
<p>beforeAll,afterAll에는 자신의 사이트를 열고 닫는 코드가 있어야한다.
하지만 일단 간단하게 코드만 보여주기 위해 사이트는 구글로 진행하겠다.
사이트를 검수한다고 가정해보고 구글의 스크린샷을 찍어보자.</p>
<pre><code class="language-typescript">/// inspection.test.ts

import {Browser, Page, launch} from &#39;puppeteer&#39;;


describe(&#39;some page&#39;,() =&gt; {
  // 생략

  it(&quot;main&quot;, async () =&gt; {
    await page.goto(&quot;https://www.google.com&quot;);
    const png = await page.screenshot();
    expect(png).toMatchImageSnapshot();
  });
});</code></pre>
<p>자 테스트 실행!</p>
<pre><code class="language-bash">yarn jest</code></pre>
<p>짜잔! </p>
<p>테스트파일이 있는 폴더에 <strong>image_snapshots</strong>폴더가 생기고 결과물이 저장된다.
<img src="https://images.velog.io/post-images/float_letter/86e8f880-efc9-11e8-b3df-756923c6e3b4/inspection-test-ts-some-page-main-1-snap.png" alt="inspection-test-ts-some-page-main-1-snap.png"></p>
<p>이것을 디자인시안파일이라고 가정하고 진행하자.
실제로는 디자인시안이미지를 이 이미지파일이름으로 바꾸고 교체하면된다. </p>
<p>하지만 같은페이지를 계속찍어봐야 우리가 원하는 검수비교가 된건지 알수가 없기에 행동을 추가해보자</p>
<pre><code class="language-typescript">//생략
describe(&#39;some page&#39;,() =&gt; {
  // 생략
  it(&quot;main&quot;, async () =&gt; {
    await page.goto(&quot;https://www.google.com&quot;);
    await page.type(&quot;input[type=&#39;text&#39;]&quot;, &quot;test&quot;); // 추가작성할 부분!
    const png = await page.screenshot();
    expect(png).toMatchImageSnapshot();
  });
});</code></pre>
<p>다시 테스트 진행!
<img src="https://images.velog.io/post-images/float_letter/728d2dc0-efc9-11e8-b3df-756923c6e3b4/%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%8B%A4%ED%8C%A8.PNG" alt="테스트실패.PNG"></p>
<p>당연히 실패가 뜬다.</p>
<p>친절하게 몇퍼센트나 차이나는지 몇픽셀이나 다른지도 결과에 출력이 된다.</p>
<p>시각적 결과물은 <strong>image_snapshots</strong>폴더에 <strong>diff_output</strong>폴더에 저장된다.</p>
<p><img src="https://images.velog.io/post-images/float_letter/73a77760-efc9-11e8-b3df-756923c6e3b4/inspection-test-ts-some-page-main-1-diff.png" alt="inspection-test-ts-some-page-main-1-diff.png"></p>
<p>기존이미지, 차이점, 새로찍은이미지순으로 이미지가 한이미지내에서 나열된다.</p>
<p>어떤가? 아름답지않은가?</p>
<p>여기서 좀더 코드를 추가하자면 기본적으로 디자인 크기에 맞춰서 브라우저의 viewport조정을 하면된다.</p>
<p>이전까지의 검수요청 &gt; 검수진행 &gt; 수정사항 요청 &gt; 수정진행 &gt; 검수진행 &gt; 반영 프로세스를</p>
<p>자동검수진행 &gt; 수정진행 &gt; 디자이너와의 타협(?) &gt; 반영 프로세스로 줄일 수 있게 되었다.</p>
<h2 id="pros">PROS</h2>
<ol>
<li>미쳐 보지못한 부분까지 전부 확인이 가능하다.</li>
<li>1 pixel까지 다맞춘다면 쾌감을 느낄수있다.</li>
<li>디자이너분의 검수시간을 줄일 수 있다.</li>
</ol>
<h2 id="cons">CONS</h2>
<ol>
<li>변태취급을 받을 수 있다.</li>
<li>반응형에는 무쓸모이다.</li>
<li>모르는척 넘어갈 수 없다.(?)</li>
</ol>
<p>단점에서의 반응형에서 무쓸모라는점은 사실 업무적으로 개선되어야 할 부분이다.
전체페이지 디자인이 아닌 컴포넌트별로 디자인을 별도로 진행하고
반응형 및 유스케이스별로 디자인상황에 대해서 각각 snapshot을 찍으면 될 부분이다.</p>
<h2 id="conclusion">Conclusion</h2>
<p>지금까지 jest-image-snapshot을 활용한 디자인 검수자동화를 대강 진행해보았다.
아쉽게 회사상황상 그렇게 유용하게 쓰이지는 못했지만 기획 및 디자인이 정확하게 나오는 환경이라면 꽤나 유용할듯 싶다.</p>
<h3 id="링크">링크</h3>
<p><a href="https://jestjs.io/">jest</a>
<a href="https://github.com/americanexpress/jest-image-snapshot">jest-image-snapshot</a>
<a href="https://github.com/GoogleChrome/puppeteer">puppeteer</a></p>
<blockquote>
<p>본 포스트는 <a href="https://tigerwest.github.io/blog/2018/11/24/1543039205/">제 블로그</a>의 포스트를 재구성한 내용입니다.</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>